Files
Viper_VRTE/w32/fileio.vp
T
TermiNexus 728d090815 feat(vqt6/vipermath/vipersimd/w32/requests): 自绘 Canvas/Graph3D/ChartView 与 Qt6 Charts、新增 gzip 与 torch-lite 模块, 修包装类悬垂指针与中文路径/exp/大文件下载
- vqt6: 包装类统一补 __new__ 堆分配, 修"创建函数栈帧 alloca"被存进字段/跨帧返回后 _ptr 悬垂(传给 QLayout::addWidget 等即崩溃); 菜单类按依赖顺序前移, menuBar()/statusBar() 改返回裸指针; 接入 Qt6 Charts 并新增 _bridge_canvas(Canvas 手绘板 / Graph3D 软件 3D 网络图 / ChartView 折线图); 新增自绘 QRadioButton(圆环+内点, 过渡动画)、剪贴板、应用级字体族 API
- 新增模块: gzip.vp(RFC1952/1951 解码器)、torch/(torch-lite 稠密张量 + conv/pool 前反向)
- vipersimd: 新增 scalar_fma/add/mul/sqrt_array 未向量化对照内核(与对应 SIMD 版逐位一致)
- w32: 新增 UTF-8/UTF-16 路径转换, CreateFile/CreateDirectory 走 W 系列, 修中文路径被按 GBK 误读; read_all 参数 max_count -> buf_size 并文档化"容量含终止符"契约
- requests: https 响应缓冲按需翻倍扩容(上限 256MB), 修 MB 级正文(如 MNIST .gz)被 4KB 静默截断
- vipermath: 重写 exp 为范围归约 + 短泰勒, 修负值发散(x=-30 得 3.7e10)与 NaN 触发 2^31 次缩放导致的卡死
- builtins: 新增 sizet/uzt 别名; stdarg: va_arg 参数 CType -> CPtr
- chore: 删除 vendored jpeg change.log
2026-09-10 23:09:05 +08:00

427 lines
16 KiB
Plaintext

import t, c
from stdint import *
import stdio
import stdlib
import w32.win32base
import w32.win32file
class MODE(t.CEnum):
R = 0
W = 1
A = 2
RP = 3
WP = 4
AP = 5
X = 6
XP = 7
class FRESULT(t.CEnum):
OK = 0
ERR = -1
ERR_CLOSED = -2
ERR_PERM = -3
ERR_IO = -4
ERR_NOTFOUND = -5
SEEK_SET: t.CDefine = 0
SEEK_CUR: t.CDefine = 1
SEEK_END: t.CDefine = 2
INVALID_SET_FILE_POINTER: t.CDefine = -1
SHARE_READ: t.CDefine = 0x00000001
SHARE_WRITE: t.CDefine = 0x00000002
SHARE_DELETE: t.CDefine = 0x00000004
def create_file_utf8(path: str, access: ULONG, share: ULONG, disposition: ULONG,
flags: ULONG) -> w32.win32base.HANDLE:
"""按路径编码打开/创建文件。
合法 UTF-8(源码字面量、Qt 返回的中文目录) → 转 UTF-16 走 CreateFileW;
非法 UTF-8(如命令行 argv 的 ANSI 串) → 退回 CreateFileA。详见 win32base"""
if w32.win32base.utf8_is_valid(path) == 0:
return w32.win32file.CreateFileA(path, access, share, None, disposition,
flags, None)
wp: w32.win32base.WCHARPTR = w32.win32base.utf8_to_utf16_dup(path)
if wp is None:
# 宽字符缓冲分配失败: 走 A 路径, 非 ASCII 路径在此自然失败并返回
# INVALID_HANDLE_VALUE(不掩盖错误, 只是复用同一失败出口)
return w32.win32file.CreateFileA(path, access, share, None, disposition,
flags, None)
h: w32.win32base.HANDLE = w32.win32file.CreateFileW(
t.CPtr(wp), access, share, None, disposition, flags, None)
stdlib.free(wp)
return h
class File:
handle: w32.win32base.HANDLE
closed: bool
can_read: bool
can_write: bool
is_append: bool
_share_mode: ULONG
def __init__(self, filename: str, mode: ULONG, share: ULONG = SHARE_READ):
self.closed = True
self.can_read = False
self.can_write = False
self.is_append = False
self._share_mode = share
access: ULONG = 0
disposition: ULONG = w32.win32file.OPEN_EXISTING
if mode == MODE.R:
access = w32.win32file.GENERIC_READ
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
elif mode == MODE.W:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_ALWAYS
self.can_write = True
elif mode == MODE.A:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_ALWAYS
self.can_write = True
self.is_append = True
elif mode == MODE.RP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
self.can_write = True
elif mode == MODE.WP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_ALWAYS
self.can_read = True
self.can_write = True
elif mode == MODE.AP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_ALWAYS
self.can_read = True
self.can_write = True
self.is_append = True
elif mode == MODE.X:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_NEW
self.can_write = True
elif mode == MODE.XP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_NEW
self.can_read = True
self.can_write = True
else:
access = w32.win32file.GENERIC_READ
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
self.handle = create_file_utf8(
filename, access, self._share_mode, disposition,
w32.win32file.FILE_ATTRIBUTE_NORMAL
)
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
self.closed = True
return
self.closed = False
if self.is_append:
self.seek(0, SEEK_END)
def __enter__(self) -> 'File' | t.CPtr:
return self
def __exit__(self):
self.close()
def read(self, buf: bytes, count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
bytes_read: ULONG = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None)
if result == 0: return FRESULT.ERR_IO
return LONG(bytes_read)
def write(self, buf: bytes, count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_write: return FRESULT.ERR_PERM
bytes_written: ULONG = 0
result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, c.Addr(bytes_written), None)
if result == 0: return FRESULT.ERR_IO
return LONG(bytes_written)
def write_str(self, s: str) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_write: return FRESULT.ERR_PERM
length: ULONG = 0
p: bytes = s
while c.Deref(p) != 0:
length += 1
p += 1
return self.write(s, length)
def seek(self, offset: LONG, origin: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin)
if result == -1: return FRESULT.ERR_IO
return result
def tell(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
return self.seek(0, SEEK_CUR)
def close(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
w32.win32base.CloseHandle(self.handle)
self.closed = True
return FRESULT.OK
def flush(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
w32.win32file.FlushFileBuffers(self.handle)
return FRESULT.OK
def size(self) -> LONGLONG:
if self.closed: return -1
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li)))
if result == 0: return -1
return li.QuadPart
def readline(self, buf: bytes, max_count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
if max_count < 2: return FRESULT.ERR
total: ULONG = 0
bytes_read: ULONG = 0
ch: t.CInt = 0
while total < max_count - 1:
bytes_read = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None)
if result == 0 or bytes_read == 0: break
ch = c.Deref(buf + total)
total += 1
if ch == 10: break
if total < max_count:
buf[total] = 0
return LONG(total)
def read_all(self, buf: bytes, buf_size: ULONG) -> LONG:
"""把整个文件读进 buf 并写成 C 字符串(内部先 seek 到 0)
契约(注意与 write 的 count 口径不同):
buf_size 是缓冲区**容量, 含终止符** —— 最多读 buf_size-1 字节,
再在 buf[返回值] 写一个 NUL 字节, 故返回值 <= buf_size-1。
文件比 buf_size-1 更长时**静默截断**, 不报错; 要区分"读完了"还是
"被截断了", 请在调用前自己比一次 f.size()。
返回实际读到的字节数, 负数为错误码。"""
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
if buf_size < 2: return FRESULT.ERR
file_size: LONGLONG = self.size()
if file_size < 0: return FRESULT.ERR_IO
to_read: ULONG = 0
if file_size < buf_size - 1:
to_read = ULONG(file_size)
else:
to_read = buf_size - 1
self.seek(0, SEEK_SET)
bytes_read: ULONG = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
if result == 0: return FRESULT.ERR_IO
if bytes_read < buf_size:
buf[bytes_read] = 0
return LONG(bytes_read)
class FileW:
handle: w32.win32base.HANDLE
closed: bool
can_read: bool
can_write: bool
is_append: bool
_share_mode: ULONG
def __init__(self, filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ):
self.closed = True
self.can_read = False
self.can_write = False
self.is_append = False
self._share_mode = share
access: ULONG = 0
disposition: ULONG = w32.win32file.OPEN_EXISTING
if mode == MODE.R:
access = w32.win32file.GENERIC_READ
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
elif mode == MODE.W:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_ALWAYS
self.can_write = True
elif mode == MODE.A:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_ALWAYS
self.can_write = True
self.is_append = True
elif mode == MODE.RP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
self.can_write = True
elif mode == MODE.WP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_ALWAYS
self.can_read = True
self.can_write = True
elif mode == MODE.AP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.OPEN_ALWAYS
self.can_read = True
self.can_write = True
self.is_append = True
elif mode == MODE.X:
access = w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_NEW
self.can_write = True
elif mode == MODE.XP:
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
disposition = w32.win32file.CREATE_NEW
self.can_read = True
self.can_write = True
else:
access = w32.win32file.GENERIC_READ
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
self.handle = w32.win32file.CreateFileW(
filename, access, self._share_mode,
None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None
)
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
self.closed = True
return
self.closed = False
if self.is_append:
self.seek(0, SEEK_END)
def __enter__(self) -> 'FileW' | t.CPtr:
return self
def __exit__(self):
self.close()
def read(self, buf: bytes, count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
bytes_read: ULONG = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None)
if result == 0: return FRESULT.ERR_IO
return LONG(bytes_read)
def write(self, buf: bytes, count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_write: return FRESULT.ERR_PERM
bytes_written: ULONG = 0
result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), None)
if result == 0: return FRESULT.ERR_IO
return LONG(bytes_written)
def write_str(self, s: str) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_write: return FRESULT.ERR_PERM
length: ULONG = 0
p: bytes = s
while c.Deref(p) != 0:
length += 1
p += 1
return self.write(s, length)
def seek(self, offset: LONG, origin: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin)
if result == -1: return FRESULT.ERR_IO
return result
def tell(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
return self.seek(0, SEEK_CUR)
def close(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
w32.win32base.CloseHandle(self.handle)
self.closed = True
return FRESULT.OK
def flush(self) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
w32.win32file.FlushFileBuffers(self.handle)
return FRESULT.OK
def size(self) -> LONGLONG:
if self.closed: return -1
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li)))
if result == 0: return -1
return li.QuadPart
def readline(self, buf: bytes, max_count: ULONG) -> LONG:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
if max_count < 2: return FRESULT.ERR
total: ULONG = 0
bytes_read: ULONG = 0
ch: t.CInt = 0
while total < max_count - 1:
bytes_read = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None)
if result == 0 or bytes_read == 0: break
ch = c.Deref(buf + total)
total += 1
if ch == 10: break
if total < max_count:
buf[total] = 0
return LONG(total)
def read_all(self, buf: bytes, buf_size: ULONG) -> LONG:
"""把整个文件读进 buf 并写成 C 字符串(内部先 seek 到 0)
契约(注意与 write 的 count 口径不同):
buf_size 是缓冲区**容量, 含终止符** —— 最多读 buf_size-1 字节,
再在 buf[返回值] 写一个 NUL 字节, 故返回值 <= buf_size-1。
文件比 buf_size-1 更长时**静默截断**, 不报错; 要区分"读完了"还是
"被截断了", 请在调用前自己比一次 f.size()。
返回实际读到的字节数, 负数为错误码。"""
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
if buf_size < 2: return FRESULT.ERR
file_size: LONGLONG = self.size()
if file_size < 0: return FRESULT.ERR_IO
to_read: ULONG = 0
if file_size < buf_size - 1:
to_read = ULONG(file_size)
else:
to_read = buf_size - 1
self.seek(0, SEEK_SET)
bytes_read: ULONG = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
if result == 0: return FRESULT.ERR_IO
if bytes_read < buf_size:
buf[bytes_read] = 0
return LONG(bytes_read)
def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr:
return File(filename, mode, share)
def openw(filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
return FileW(filename, mode, share)