snapshot before regression test
This commit is contained in:
394
includes/w32/fileio.py
Normal file
394
includes/w32/fileio.py
Normal file
@@ -0,0 +1,394 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
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
|
||||
|
||||
|
||||
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 = w32.win32file.CreateFileA(
|
||||
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) -> '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, 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, 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
|
||||
# stdio.printf("[DBG read_all] before size()\n")
|
||||
file_size: LONGLONG = self.size()
|
||||
# stdio.printf("[DBG read_all] after size(), file_size=%lld\n", file_size)
|
||||
if file_size < 0: return FRESULT.ERR_IO
|
||||
to_read: ULONG = 0
|
||||
if file_size < max_count - 1:
|
||||
to_read = ULONG(file_size)
|
||||
else:
|
||||
to_read = max_count - 1
|
||||
# stdio.printf("[DBG read_all] to_read=%u, before seek\n", to_read)
|
||||
self.seek(0, SEEK_SET)
|
||||
# stdio.printf("[DBG read_all] after seek, before ReadFile\n")
|
||||
bytes_read: ULONG = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
|
||||
# stdio.printf("[DBG read_all] after ReadFile, result=%d, bytes_read=%u\n", result, bytes_read)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
if bytes_read < max_count:
|
||||
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, 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
|
||||
file_size: LONGLONG = self.size()
|
||||
if file_size < 0: return FRESULT.ERR_IO
|
||||
to_read: ULONG = 0
|
||||
if file_size < max_count - 1:
|
||||
to_read = ULONG(file_size)
|
||||
else:
|
||||
to_read = max_count - 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 < max_count:
|
||||
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: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
return FileW(filename, mode, share)
|
||||
Reference in New Issue
Block a user