AwdbDataParserLarge.java
package com.xenoamess.ipplus360;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.*;
import com.xenoamess.ipplus360.entity.AwdbMetaData;
import com.xenoamess.ipplus360.enumerate.AwdbDataType;
import com.xenoamess.ipplus360.exception.InvalidAwdbException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 支持大文件的 awdb 数据解析器
*/
class AwdbDataParserLarge {
private static final Logger logger = LoggerFactory.getLogger(AwdbDataParserLarge.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final LargeFileBuffer buffer;
private final AwdbNodeCache cache;
private final CharsetDecoder strDecoder = StandardCharsets.UTF_8.newDecoder();
private long basePointer = 0;
public AwdbDataParserLarge(AwdbNodeCache cache, LargeFileBuffer buffer) {
this.cache = cache;
this.buffer = buffer;
}
public AwdbDataParserLarge(AwdbNodeCache cache, LargeFileBuffer buffer, long basePointer) {
this(cache, buffer);
this.basePointer = basePointer;
}
private final AwdbNodeCache.Loader loader = this::parseData;
/**
* 解析元数据
*
* @param length 元数据长度
* @return 元数据
*/
protected AwdbMetaData parseMeta(int length) throws IOException {
// 根据实际文件结构,元数据应该从偏移量2开始(因为前2字节是长度)
long startLen = 2 + length;
long oldLimit = buffer.limit();
buffer.limit(startLen);
// 跳过前2字节(长度)
buffer.position(2);
byte[] metaBytes = new byte[length];
buffer.get(metaBytes);
buffer.limit(oldLimit);
String meta = new String(metaBytes, StandardCharsets.UTF_8);
JsonNode metaJsonObj = OBJECT_MAPPER.readTree(meta);
return new AwdbMetaData(metaJsonObj, startLen);
}
/**
* 解析数据
*
* @param offset 偏移量
* @return JsonNode
*/
protected JsonNode parseData(long offset) throws IOException {
if (offset < 0 || offset >= buffer.capacity()) {
throw new InvalidAwdbException(
"The AWDB file's data section contains bad data: pointer " + offset + " out of bounds [0, " + buffer.capacity() + "]");
}
// LargeFileBuffer每个线程使用独立副本,且底层读取已线程安全,无需同步
buffer.position(offset);
buffer.limit(buffer.capacity()); // 设置限制到文件末尾
return parser();
}
/**
* 解析器
*
* @return JsonNode
*/
private JsonNode parser() throws IOException {
if (buffer.remaining() < 2) {
logger.warn("解析器:剩余数据不足,只有 {} 字节", buffer.remaining());
throw new InvalidAwdbException("Not enough data for parser: only " + buffer.remaining() + " bytes remaining");
}
int typeByte = buffer.get() & 0xFF;
AwdbDataType dataType = AwdbDataType.getDataType(typeByte);
if (dataType == null) {
throw new InvalidAwdbException("Unknown data type byte: " + typeByte);
}
int len = buffer.get() & 0xFF;
return parseDataType(dataType, len);
}
/**
* 根据数据类型来解析数据
*
* @param type 数据类型
* @param len 数据长度
* @return JsonNode
*/
private JsonNode parseDataType(AwdbDataType type, int len) throws IOException {
switch (type) {
case ARRAY:
return parseArray(len);
case POINTER:
return parsePointer(len);
case STRING:
return parseString(len);
case TEXT:
return parseText(len);
case INT:
return parseInt(len);
case UINT:
return parseUint(len);
case FLOAT:
return parseFloat(len);
case DOUBLE:
return parseDouble(len);
default:
throw new InvalidAwdbException("Unknown or unexpected type: " + type.name());
}
}
/**
* 解析数组数据(列表)
*
* @param len 数据长度
* @return JsonNode
*/
private JsonNode parseArray(int len) throws IOException {
List<JsonNode> list = new ArrayList<>(len);
for (int i = 0; i < len; i++) {
JsonNode node = parser();
list.add(node);
}
ArrayNode nodes = new ArrayNode(OBJECT_MAPPER.getNodeFactory());
return nodes.addAll(Collections.unmodifiableList(list));
}
/**
* 解析指针数据
*
* @param len 数据长度
* @return JsonNode
*/
private JsonNode parsePointer(int len) throws IOException {
long oldLimit = buffer.limit();
try {
// 指针长度至少为1字节
if (len <= 0) {
logger.warn("解析指针:无效的指针长度 {} 字节", len);
return null;
}
buffer.limit(buffer.position() + len);
// 检查剩余数据是否足够
if (buffer.remaining() < len) {
logger.warn("解析指针:剩余数据不足,预期 {} 字节,实际 {} 字节", len, buffer.remaining());
return null;
}
long buf = buffer2Long(len); // 使用无符号解析,避免负数
// 先校验偏移量的合理性,避免超大指针
if (buf < 0 || buf > buffer.capacity()) {
logger.warn("指针偏移量无效: {} (有效范围: [0, {}]), 跳过此数据",
buf, buffer.capacity() - 1);
return null;
}
long pointer = basePointer + buf;
// 验证指针的有效性,重点检查偏移计算是否合理
if (pointer < 0 || pointer >= buffer.capacity()) {
logger.warn("指针无效: {} (基指针: {}, 偏移: {}, 有效范围: [0, {}]), 跳过此数据",
pointer, basePointer, buf, buffer.capacity() - 1);
return null;
}
long position = buffer.position();
JsonNode jsonNode = cache.get(loader, pointer);
buffer.position(position);
return jsonNode;
} catch (BufferUnderflowException e) {
logger.warn("解析指针:缓冲器下溢,数据长度 {} 字节", len);
return null;
} finally {
buffer.limit(oldLimit);
}
}
/**
* 解析字符串数据
*
* @param len 数据长度
* @return JsonNode
*/
private JsonNode parseString(int len) {
long oldLimit = buffer.limit();
try {
// 验证长度的合理性
if (len < 0 ) { // 限制最大长度
logger.warn("解析字符串:无效的长度 {} 字节", len);
return null;
}
// 检查剩余数据是否足够
if (buffer.remaining() < len || buffer.position() + len > buffer.capacity()) {
logger.warn("解析字符串:剩余数据不足,预期 {} 字节,实际剩余 {} 字节", len, buffer.remaining());
return null;
}
buffer.limit(buffer.position() + len);
byte[] bytes = new byte[len];
buffer.get(bytes);
String s = new String(bytes, StandardCharsets.UTF_8);
buffer.limit(oldLimit);
return new TextNode(s);
} catch (BufferUnderflowException e) {
logger.warn("解析字符串:缓冲器下溢,数据长度 {} 字节", len);
buffer.limit(oldLimit); // 确保恢复原始限制
return null;
} catch (Exception e) {
logger.warn("解析字符串:{},数据长度 {} 字节", e.getMessage(), len);
buffer.limit(oldLimit); // 确保恢复原始限制
return null;
}
}
/**
* 解析长字符串数据
*
* @param len 数据长度
* @return JsonNode
*/
private JsonNode parseText(int len) {
long oldLimit = buffer.limit();
try {
buffer.limit(buffer.position() + len);
long dataLen = buffer2Long(len); // 使用无符号解析,接受更大范围
buffer.limit(oldLimit);
// 限制字符串最大长度,避免内存溢出
// final int MAX_TEXT_LENGTH = 100000; // 限制为100KB
// if (dataLen > MAX_TEXT_LENGTH) {
// logger.warn("文本数据过长,限制为{}字节: {}", MAX_TEXT_LENGTH, dataLen);
// dataLen = MAX_TEXT_LENGTH;
// }
// 确保剩余数据足够
if (buffer.position() + dataLen > buffer.capacity() || dataLen < 0) {
logger.warn("解析文本:无效长度或数据不足,预期 {} 字节,剩余 {} 字节", dataLen, buffer.capacity() - buffer.position());
return null;
}
buffer.limit(buffer.position() + dataLen);
byte[] bytes = new byte[(int) dataLen];
buffer.get(bytes);
String s = new String(bytes, StandardCharsets.UTF_8);
buffer.limit(oldLimit);
return new TextNode(s);
} catch (BufferUnderflowException e) {
logger.warn("解析文本:缓冲器下溢");
buffer.limit(oldLimit); // 确保恢复原始限制
return null;
} catch (Exception e) {
logger.warn("解析文本:{}", e.getMessage());
buffer.limit(oldLimit); // 确保恢复原始限制
return null;
}
}
/**
* 解析无符号整型数据
*
* @param len 数据长度
* @return 无符号整型
*/
private JsonNode parseUint(int len) {
return new LongNode(buffer2Long(len));
}
/**
* 解析有符号整型。INT/FLOAT/DOUBLE 的 len 字节实际是首个数据字节,
* 其后再读 3 字节,共 4 字节大端。
*
* @param firstByte 首个数据字节(即控制区的 len 字节)
* @return 有符号整型
*/
private JsonNode parseInt(int firstByte) {
int value = ((firstByte & 0xFF) << 24)
| ((buffer.get() & 0xFF) << 16)
| ((buffer.get() & 0xFF) << 8)
| (buffer.get() & 0xFF);
return new IntNode(value);
}
/**
* 解析double类型的数据。len 字节是 8 字节大端位模式的首字节。
*
* @param firstByte 首个数据字节(即控制区的 len 字节)
* @return double类型数据
*/
private JsonNode parseDouble(int firstByte) {
long bits = ((long) (firstByte & 0xFF) << 56) | buffer2Long(7);
return new DoubleNode(Double.longBitsToDouble(bits));
}
/**
* 解析float类型的数据。len 字节是 4 字节大端位模式的首字节。
*
* @param firstByte 首个数据字节(即控制区的 len 字节)
* @return float类型数据
*/
private JsonNode parseFloat(int firstByte) {
int bits = ((firstByte & 0xFF) << 24)
| ((buffer.get() & 0xFF) << 16)
| ((buffer.get() & 0xFF) << 8)
| (buffer.get() & 0xFF);
return new FloatNode(Float.intBitsToFloat(bits));
}
/**
* 从指定偏移位置读取len个字节,解析为无符号整数
*
* @param offset 偏移位置
* @param len 数据长度
* @return 无符号整型
*/
private long buffer2Long(long offset, int len) {
try {
long num = 0;
// 验证 len 的合理性 - 允许更大的长度范围
if (len <= 0 ) {
logger.warn("解析无符号整数:无效长度 {} 字节", len);
return -1;
}
// 读取指定长度的字节数据
byte[] bytes = new byte[len];
buffer.get(offset, bytes, 0, len);
// 解析字节数据,处理字节序问题
for (int i = 0; i < len; i++) {
num = (num << 8) | (bytes[i] & 0xFF);
// 超过8字节的数据截断,避免long类型溢出
if (i >= 7) {
logger.warn("解析无符号整数:数据长度 {} 字节超过 long 类型存储范围,只取低8字节", len);
break;
}
}
// 验证解析结果的合理性
if (num < 0) {
logger.warn("解析无符号整数:解析结果为负数 {},长度 {} 字节", num, len);
return -1;
}
return num;
} catch (Exception e) {
logger.warn("解析无符号整数异常: {}", e.getMessage());
return -1;
}
}
/**
* 解析无符号整型
*
* @param len 数据长度
* @return 无符号整型
*/
private long buffer2Long(int len) {
try {
long num = 0;
// 验证 len 的合理性 - 允许更大的长度范围
if (len <= 0 ) {
logger.warn("解析无符号整数:无效长度 {} 字节", len);
return -1;
}
// 读取指定长度的字节数据
byte[] bytes = new byte[len];
buffer.get(bytes);
// 解析字节数据,处理字节序问题
for (int i = 0; i < len; i++) {
num = (num << 8) | (bytes[i] & 0xFF);
// 如果长度超过8字节,只取低8字节,避免long类型溢出
if (i >= 7) {
logger.warn("解析无符号整数:数据长度 {} 字节超过 long 类型存储范围,只取低8字节", len);
break;
}
}
// 验证解析结果的合理性
if (num < 0) {
logger.warn("解析无符号整数:解析结果为负数 {},长度 {} 字节", num, len);
return -1;
}
return num;
} catch (BufferUnderflowException e) {
logger.warn("解析无符号整数:缓冲器下溢,数据长度 {} 字节", len);
// 重置位置到操作前的位置
buffer.position(buffer.position() - len);
return -1;
}
}
/**
* 解析有符号整型
*
* @param len 数据长度
* @return 有符号整型
*/
private int buffer2Integer(int len) {
int num = 0;
try {
// 检查剩余数据是否足够
if (buffer.remaining() < len || len <= 0 || len > 4) { // int最多4字节
// logger.warn("解析整数:无效长度或数据不足,预期 {} 字节,实际剩余 {} 字节", len, buffer.remaining());
// 如果长度无效,尝试跳过处理
buffer.position(buffer.position() + len);
return 0;
}
for (int i = 0; i < len; i++) {
num = (num << 8) | (buffer.get() & 0xFF);
}
return num;
} catch (BufferUnderflowException e) {
logger.warn("解析整数:缓冲器下溢,数据长度 {} 字节", len);
return 0;
}
}
}