#!/usr/bin/env python

"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

# 导入所需的标准库
import os
import re

from xml.etree import ElementTree as et  # 导入XML解析库

# 导入自定义模块和函数
from lib.core.common import getSafeExString
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import paths
from lib.core.datatype import AttribDict
from lib.core.exception import SqlmapInstallationException
from lib.core.settings import PAYLOAD_XML_FILES

def cleanupVals(text, tag):
    """
    清理和转换XML中的值
    :param text: 需要处理的文本
    :param tag: XML标签名
    :return: 处理后的值
    """
    # 处理clause标签中的范围表示法(如"1-3"转换为"1,2,3")
    if tag == "clause" and '-' in text:
        text = re.sub(r"(\d+)-(\d+)", lambda match: ','.join(str(_) for _ in xrange(int(match.group(1)), int(match.group(2)) + 1)), text)

    # 对clause和where标签的内容按逗号分割
    if tag in ("clause", "where"):
        text = text.split(',')

    # 如果文本是纯数字，转换为整数
    if hasattr(text, "isdigit") and text.isdigit():
        text = int(text)

    # 处理列表类型的值
    elif isinstance(text, list):
        count = 0
        # 遍历列表，将数字字符串转换为整数
        for _ in text:
            text[count] = int(_) if _.isdigit() else _
            count += 1

        # 如果列表只有一个元素且不是特定标签，则返回该元素
        if len(text) == 1 and tag not in ("clause", "where"):
            text = text[0]

    return text

def parseXmlNode(node):
    """
    解析XML节点
    :param node: XML节点对象
    """
    # 解析boundary(边界)节点
    for element in node.findall("boundary"):
        boundary = AttribDict()  # 创建一个属性字典

        # 遍历boundary的子节点
        for child in element:
            if child.text:
                values = cleanupVals(child.text, child.tag)
                boundary[child.tag] = values
            else:
                boundary[child.tag] = None

        conf.boundaries.append(boundary)

    # 解析test(测试)节点
    for element in node.findall("test"):
        test = AttribDict()  # 创建一个属性字典

        # 遍历test的子节点
        for child in element:
            if child.text and child.text.strip():
                values = cleanupVals(child.text, child.tag)
                test[child.tag] = values
            else:
                # 处理没有子元素的节点
                if len(child.findall("*")) == 0:
                    test[child.tag] = None
                    continue
                else:
                    test[child.tag] = AttribDict()

                # 处理有子元素的节点
                for gchild in child:
                    if gchild.tag in test[child.tag]:
                        prevtext = test[child.tag][gchild.tag]
                        test[child.tag][gchild.tag] = [prevtext, gchild.text]
                    else:
                        test[child.tag][gchild.tag] = gchild.text

        conf.tests.append(test)

def loadBoundaries():
    """
    从XML文件加载边界定义
    
    >>> conf.boundaries = []
    >>> loadBoundaries()
    >>> len(conf.boundaries) > 0
    True
    """
    try:
        # 尝试解析boundaries.xml文件
        doc = et.parse(paths.BOUNDARIES_XML)
    except Exception as ex:
        # 如果解析失败，抛出安装异常
        errMsg = "something appears to be wrong with "
        errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex))
        errMsg += "sure that you haven't made any changes to it"
        raise SqlmapInstallationException(errMsg)

    root = doc.getroot()
    parseXmlNode(root)

def loadPayloads():
    """
    从XML文件加载有效载荷/测试用例
    
    >>> conf.tests = []
    >>> loadPayloads()
    >>> len(conf.tests) > 0
    True
    """
    # 遍历所有payload XML文件
    for payloadFile in PAYLOAD_XML_FILES:
        payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)

        try:
            # 尝试解析payload XML文件
            doc = et.parse(payloadFilePath)
        except Exception as ex:
            # 如果解析失败，抛出安装异常
            errMsg = "something appears to be wrong with "
            errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
            errMsg += "sure that you haven't made any changes to it"
            raise SqlmapInstallationException(errMsg)

        root = doc.getroot()
        parseXmlNode(root)
