AwdbDataParser.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.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * awdb文件数据解析器
 */
class AwdbDataParser {
    private static final Logger logger = LoggerFactory.getLogger(AwdbDataParser.class);
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private final ByteBuffer buffer;

    private final AwdbNodeCache cache;

    private final CharsetDecoder strDecoder = StandardCharsets.UTF_8.newDecoder();

    private long basePointer = 0;

    public AwdbDataParser(AwdbNodeCache cache, ByteBuffer buffer) {
        this.cache = cache;
        this.buffer = buffer;
    }

    public AwdbDataParser(AwdbNodeCache cache, ByteBuffer 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 {
        int startLen = 2 + length;
        buffer.limit(startLen);
     //   buffer.position(2); // 跳过前2字节(长度)
        String meta = strDecoder.decode(buffer).toString();
        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 >= this.buffer.capacity()) {
            throw new InvalidAwdbException(
                    "The AWDB file's data section contains bad data: pointer " + offset + " out of bounds [0, " + buffer.capacity() + "]");
        }

        buffer.position((int) offset);

        return parser();
    }

    /**
     * 解析器
     *
     * @return JsonNode
     */
    private JsonNode parser() throws IOException {
        // 获取控制字节
        int typeByte = 0xFF & buffer.get();

        // awdb数据类型
        AwdbDataType dataType = AwdbDataType.getDataType(typeByte);
        if (dataType == null) {
            throw new InvalidAwdbException("Unknown data type byte: " + typeByte);
        }

        // 获取列表长度
        int len = 0xFF & buffer.get();

        // len由buffer.get() & 0xFF得到,范围0-255,不会为负数
        // 空值(len == 0)是合法的,比如空字符串、空数组,不需要拦截

        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 {
        // 指针长度至少为1字节
        if (len <= 0) {
            logger.warn("解析指针:无效的指针长度 {} 字节", len);
            return null;
        }

        int oldLimit = buffer.limit();
        buffer.limit(buffer.position() + len);
        long buf = AwdbDataParser.buffer2Integer(buffer, 0, len);
        buffer.limit(oldLimit);

        // 先校验偏移量的合理性,避免超大指针
        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;
        }

        int position = buffer.position();
        JsonNode jsonNode = cache.get(loader, pointer);
        buffer.position(position);
        return jsonNode;
    }

    /**
     * 解析字符串数据
     *
     * @param len 数据长度
     * @return JsonNode
     */
    private JsonNode parseString(int len) throws CharacterCodingException {
        int oldLimit = buffer.limit();
        buffer.limit(buffer.position() + len);
        String s = strDecoder.decode(buffer).toString();
        buffer.limit(oldLimit);
        return new TextNode(s);
    }

    /**
     * 解析长字符串数据
     *
     * @param len 数据长度
     * @return JsonNode
     */
    private JsonNode parseText(int len) throws CharacterCodingException {
        int oldLimit = buffer.limit();
        buffer.limit(buffer.position() + len);
        int dataLen = AwdbDataParser.buffer2Integer(buffer, 0, 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.limit()) {
            logger.warn("数据不足,只读取剩余字节");
            dataLen = buffer.limit() - buffer.position();
        }
        
        buffer.limit(buffer.position() + dataLen);
        String s = strDecoder.decode(buffer).toString();
        buffer.limit(oldLimit);
        return new TextNode(s);
    }

    /**
     * 解析无符号整型数据
     *
     * @param len 数据长度
     * @return JsonNode
     */
    private JsonNode parseUint(int len) {
        return new LongNode(buffer2Long(len));
    }

    /**
     * 解析有符号整型。INT/FLOAT/DOUBLE 的 len 字节实际是首个数据字节,
     * 其后再读 3 字节,共 4 字节大端。
     *
     * @param firstByte 首个数据字节(即控制区的 len 字节)
     * @return JsonNode
     */
    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 JsonNode
     */
    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 JsonNode
     */
    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));
    }

    /**
     * 解析无符号整型
     *
     * @param len 数据长度
     * @return 无符号整型
     */
    private long buffer2Long(int len) {
        long num = 0;
        for (int i = 0; i < len; i++) {
            num = (num << 8) | (buffer.get() & 0xFF);
        }
        return num;
    }

    /**
     * 解析有符号整型
     *
     * @param buffer 缓存器
     * @param base   基准位置
     * @param len    数据长度
     * @return 有符号整型
     */
    protected static int buffer2Integer(ByteBuffer buffer, int base, int len) {
        int num = base;
        for (int i = 0; i < len; i++) {
            num = (num << 8) | (buffer.get() & 0xFF);
        }
        return num;
    }
}