import t, c from stdint import * import memhub import string import stdlib import viperlib import hashlib import w32.win32file import w32.win32base # ============================================================ # Utils - 工程工具函数 # # 提供 SHA1 计算和目录清理等通用工具函数。 # ============================================================ # 全局 mbuddy 指针 _mbuddy: memhub.MemManager | t.CPtr # ============================================================ # compute_sha1 - 计算字符串的 SHA1,返回前 16 个十六进制字符 # # 使用 includes/hashlib 库的 sha1 类计算摘要,转为十六进制字符串。 # 参考 Projectrans.py 的 compute_sha1(hashlib.sha1().hexdigest()[:16])。 # ============================================================ def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str: """计算字符串的 SHA1,返回前 16 个十六进制字符(用于文件命名)""" if content is None or pool is None: return None # 构造 sha1 对象(__init__ 会初始化 state/count/buf) # ctx 在栈上分配(alloca),函数内使用完即丢弃,无需堆分配 ctx: hashlib.sha1 | t.CPtr = hashlib.sha1() if ctx is None: return None # 计算摘要 ctx.update(content) digest: bytes = pool.alloc(hashlib.SHA1_DIGEST_LEN) if digest is None: return None ctx.final(digest) # 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符) hex_buf: str = pool.alloc(17) if hex_buf is None: return None for i in range(8): hi: int = (digest[i] >> 4) & 0xF lo: int = digest[i] & 0xF if hi < 10: hex_buf[i * 2] = '0' + hi else: hex_buf[i * 2] = 'a' + (hi - 10) if lo < 10: hex_buf[i * 2 + 1] = '0' + lo else: hex_buf[i * 2 + 1] = 'a' + (lo - 10) hex_buf[16] = '\0' return hex_buf # ============================================================ # CleanDir - 删除目录中所有文件(非递归,保留目录本身) # # 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。 # ============================================================ def CleanDir(dir_path: str) -> int: """删除目录中所有文件(非递归),返回删除的文件数,-1 表示错误""" if dir_path is None: return -1 dir_len: t.CSizeT = string.strlen(dir_path) pattern: bytes = stdlib.malloc(dir_len + 8) if pattern is None: return -1 viperlib.snprintf(pattern, dir_len + 8, "%s/*", dir_path) find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) if find_data is None: stdlib.free(pattern) return -1 string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) if handle == w32.win32base.INVALID_HANDLE_VALUE: stdlib.free(pattern) stdlib.free(find_data) return 0 deleted: int = 0 while 1: fname: str = find_data.cFileName if fname is not None: # 跳过 . 和 .. if fname[0] == '.': if fname[1] == '\0': fname = None elif fname[1] == '.' and fname[2] == '\0': fname = None if fname is not None: fname_len: t.CSizeT = string.strlen(fname) full_path: bytes = stdlib.malloc(dir_len + fname_len + 2) if full_path is not None: viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname) if w32.win32file.DeleteFileA(full_path) != 0: deleted += 1 stdlib.free(full_path) if w32.win32file.FindNextFileA(handle, find_data) == 0: break w32.win32file.FindClose(handle) stdlib.free(pattern) stdlib.free(find_data) return deleted