landv / landv.github.io

landv-blogs
https://landv.cn
2 stars 0 forks source link

flashXmlLibToolsQTGui #90

Open landv opened 4 weeks ago

landv commented 4 weeks ago

flash xmlLib zlib 压缩和解压缩


import os
import zlib
from io import BytesIO
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox

class FileToolGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("文件压缩/解压缩工具")
        self.initUI()

    def initUI(self):
        self.action = 'decompress'  # 默认操作为解压缩
        self.resize(308, 266)
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        layout = QtWidgets.QVBoxLayout()

        # 操作选择部分
        operation_label = QtWidgets.QLabel("选择操作:")
        layout.addWidget(operation_label)

        self.decompress_radio = QtWidgets.QRadioButton("解压缩")
        self.decompress_radio.setChecked(True)
        self.compress_radio = QtWidgets.QRadioButton("压缩")

        radio_layout = QtWidgets.QHBoxLayout()
        radio_layout.addWidget(self.decompress_radio)
        radio_layout.addWidget(self.compress_radio)
        layout.addLayout(radio_layout)

        self.decompress_radio.toggled.connect(lambda: self.on_radio_toggled('decompress'))
        self.compress_radio.toggled.connect(lambda: self.on_radio_toggled('compress'))

        # 输入路径选择部分
        input_label = QtWidgets.QLabel("输入路径:")
        layout.addWidget(input_label)

        self.input_entry = QtWidgets.QLineEdit()
        layout.addWidget(self.input_entry)

        select_input_button = QtWidgets.QPushButton("选择输入路径")
        select_input_button.clicked.connect(self.select_input)
        layout.addWidget(select_input_button)

        # 输出路径选择部分
        output_label = QtWidgets.QLabel("输出路径:")
        layout.addWidget(output_label)

        self.output_entry = QtWidgets.QLineEdit()
        layout.addWidget(self.output_entry)

        select_output_button = QtWidgets.QPushButton("选择输出路径")
        select_output_button.clicked.connect(self.select_output)
        layout.addWidget(select_output_button)

        # 开始按钮
        start_button = QtWidgets.QPushButton("开始")
        start_button.clicked.connect(self.process_files)
        layout.addWidget(start_button)

        central_widget.setLayout(layout)

    def on_radio_toggled(self, action):
        self.action = action

    def select_input(self):
        if self.action == 'decompress':
            input_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "All Files (*);;Binary Files (*.bin)")
        else:
            input_path = QFileDialog.getExistingDirectory(self, "选择文件夹")

        if input_path:
            self.input_entry.setText(input_path)

    def select_output(self):
        if self.action == 'decompress':
            output_path = QFileDialog.getExistingDirectory(self, "选择文件夹")
        else:
            output_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "Library Files (*.lib)")

        if output_path:
            self.output_entry.setText(output_path)

    def process_files(self):
        input_path = self.input_entry.text()
        output_path = self.output_entry.text()

        if not input_path or not output_path:
            QMessageBox.critical(self, "错误", "请指定输入和输出路径")
            return

        if self.action == 'decompress':
            parsed_data = parse_binary_file(input_path)
            display_parsed_data(parsed_data, output_path)
            QMessageBox.information(self, "完成", "文件解压缩完成")
        elif self.action == 'compress':
            compress_files(input_path, output_path)
            QMessageBox.information(self, "完成", "文件压缩完成")

def parse_binary_file(file_path):
    map = {}

    with open(file_path, 'rb') as file:
        compressed_data = file.read()

    decompressed_data = zlib.decompress(compressed_data)
    byte_stream = BytesIO(decompressed_data)

    while byte_stream.tell() < len(decompressed_data):
        name_length = int.from_bytes(byte_stream.read(2), 'big')
        name = byte_stream.read(name_length).decode('utf-8')
        file_length = int.from_bytes(byte_stream.read(4), 'big')
        file_content = byte_stream.read(file_length)
        map[name] = file_content

    return map

def display_parsed_data(parsed_data, output_folder):
    for name, content in parsed_data.items():
        try:
            output_file_path = os.path.join(output_folder, name)
            os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
            with open(output_file_path, 'wb') as outfile:
                outfile.write(content)
        except UnicodeDecodeError:
            print(f'File Name: {name}')
            print('Content: [无法解码为UTF-8]')

def compress_files(input_folder, output_file_path):
    byte_stream = BytesIO()

    for root, dirs, files in os.walk(input_folder):
        for file_name in files:
            if file_name.endswith('.xml'):
                file_path = os.path.join(root, file_name)
                with open(file_path, 'rb') as file:
                    file_content = file.read()

                name_bytes = file_name.encode('utf-8')
                name_length = len(name_bytes)
                byte_stream.write(name_length.to_bytes(2, 'big'))
                byte_stream.write(name_bytes)
                file_length = len(file_content)
                byte_stream.write(file_length.to_bytes(4, 'big'))
                byte_stream.write(file_content)

    uncompressed_data = byte_stream.getvalue()
    compressed_data = zlib.compress(uncompressed_data)
    with open(output_file_path, 'wb') as output_file:
        output_file.write(compressed_data)

if __name__ == "__main__":
    app = QApplication([])
    window = FileToolGUI()
    window.show()
    app.exec_()
# 创建虚拟环境(可选步骤,如果你还没有虚拟环境)
python -m venv venv
# 激活虚拟环境
# Windows
venv\Scripts\activate
pip install PyQt5 pyinstaller
python.exe -m pip install --upgrade pip
pyinstaller --onefile --windowed --hidden-import PyQt5 flashXmlLibToolsQTGui.py

pyinstaller flashXmlLibToolsQTGui.spec
#记得目录不能有中文

# 混淆加密
pyarmor g 
pyarmor cfg pack:pyi_options = " -w --hidden-import PyQt5"

pyarmor cfg

pyarmor gen --pack onefile flashXmlLibToolsQTGui.py

# https://pyarmor.readthedocs.io/en/latest/topic/repack.html#packing-scripts-automatically