Initial QSfera import
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import inspect
|
||||
import ctypes
|
||||
from ctypes import wintypes
|
||||
from enum import IntFlag, Enum, unique
|
||||
|
||||
from helpers.ConfigHelper import is_windows
|
||||
|
||||
|
||||
error_message = "'%s' function is only supported in Windows OS."
|
||||
|
||||
# ==========================
|
||||
# Structures
|
||||
# ==========================
|
||||
class FILETIME(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("dwLowDateTime", wintypes.DWORD),
|
||||
("dwHighDateTime", wintypes.DWORD),
|
||||
]
|
||||
|
||||
class WIN32_FILE_ATTRIBUTE_DATA(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("dwFileAttributes", wintypes.DWORD),
|
||||
("ftCreationTime", FILETIME),
|
||||
("ftLastAccessTime", FILETIME),
|
||||
("ftLastWriteTime", FILETIME),
|
||||
("nFileSizeHigh", wintypes.DWORD),
|
||||
("nFileSizeLow", wintypes.DWORD),
|
||||
]
|
||||
|
||||
# Ref: https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||
@unique
|
||||
class FileAttributeConstants(IntFlag):
|
||||
__str__ = Enum.__str__
|
||||
FILE_ATTRIBUTE_PINNED = 0x00080000
|
||||
FILE_ATTRIBUTE_UNPINNED = 0x00100000
|
||||
FILE_ATTRIBUTE_ARCHIVE = 0x00000020
|
||||
|
||||
GetFileAttributesExW = None
|
||||
GetCompressedFileSizeW = None
|
||||
|
||||
if is_windows():
|
||||
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
|
||||
|
||||
GetFileAttributesExW = kernel32.GetFileAttributesExW
|
||||
GetFileAttributesExW.argtypes = [
|
||||
wintypes.LPCWSTR,
|
||||
ctypes.c_int,
|
||||
ctypes.POINTER(WIN32_FILE_ATTRIBUTE_DATA),
|
||||
]
|
||||
GetFileAttributesExW.restype = wintypes.BOOL
|
||||
|
||||
GetCompressedFileSizeW = kernel32.GetCompressedFileSizeW
|
||||
GetCompressedFileSizeW.argtypes = [
|
||||
wintypes.LPCWSTR,
|
||||
ctypes.POINTER(wintypes.DWORD),
|
||||
]
|
||||
GetCompressedFileSizeW.restype = wintypes.DWORD
|
||||
|
||||
|
||||
def get_file_attributes(path):
|
||||
if is_windows():
|
||||
data = WIN32_FILE_ATTRIBUTE_DATA()
|
||||
success = GetFileAttributesExW(path, 0, ctypes.byref(data))
|
||||
if not success:
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
attributes = FileAttributeConstants(data.dwFileAttributes)
|
||||
mask = (
|
||||
FileAttributeConstants.FILE_ATTRIBUTE_PINNED |
|
||||
FileAttributeConstants.FILE_ATTRIBUTE_UNPINNED |
|
||||
FileAttributeConstants.FILE_ATTRIBUTE_ARCHIVE
|
||||
)
|
||||
return attributes & mask
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def get_compressed_file_size(path):
|
||||
if is_windows():
|
||||
high = wintypes.DWORD(0)
|
||||
low = GetCompressedFileSizeW(path, ctypes.byref(high))
|
||||
|
||||
if low == 0xFFFFFFFF:
|
||||
err = ctypes.get_last_error()
|
||||
if err != 0:
|
||||
raise ctypes.WinError(err)
|
||||
|
||||
return (high.value << 32) | low
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def resource_archived(resource_path):
|
||||
if is_windows():
|
||||
return bool(get_file_attributes(resource_path) & FileAttributeConstants.FILE_ATTRIBUTE_ARCHIVE)
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def resource_pinned(resource_path):
|
||||
if is_windows():
|
||||
return bool(get_file_attributes(resource_path) & FileAttributeConstants.FILE_ATTRIBUTE_PINNED)
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def resource_unpinned(resource_path):
|
||||
if is_windows():
|
||||
return bool(get_file_attributes(resource_path) & FileAttributeConstants.FILE_ATTRIBUTE_UNPINNED)
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def is_placeholder_resource(resource_path):
|
||||
if is_windows():
|
||||
size_on_disk = get_compressed_file_size(resource_path)
|
||||
unpinned = resource_unpinned(resource_path)
|
||||
pinned = resource_pinned(resource_path)
|
||||
archived = resource_archived(resource_path)
|
||||
return (not size_on_disk or unpinned) and not (pinned and archived)
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
|
||||
|
||||
def is_file_downloaded(resource_path):
|
||||
if is_windows():
|
||||
size_on_disk = get_compressed_file_size(resource_path)
|
||||
pinned = resource_pinned(resource_path)
|
||||
unpinned = resource_unpinned(resource_path)
|
||||
archived = resource_archived(resource_path)
|
||||
return size_on_disk and (pinned or archived) and not unpinned
|
||||
raise OSError(error_message % inspect.currentframe().f_back.f_code.co_name)
|
||||
Reference in New Issue
Block a user