C
Qt Quick Ultralite 文件加载示例
/****************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/#include "posixfilesystem.h" #include <sys/stat.h> #include <fcntl.h> #include <cstring> #include <string> #include <filesystem> #include <platforminterface/allocator.h> #if defined(QUL_OS_LINUX) #include <unistd.h> #endif #ifdef QUL_OS_MACOS #include <unistd.h> #define fstat64 fstat #define stat64 stat #endif #ifdef QUL_OS_WIN #include <io.h> #include <windows.h> #ifdef QUL_CC_MSVC #define fstat64 _fstat64 #define stat64 __stat64 typedef uintptr_t ssize_t; #endif #endif static std::string appFilePath() { #if defined(QUL_OS_LINUX) || defined(QUL_OS_MACOS) std::filesystem::path executable(std::string("/proc/") + std::to_string(::getpid()) + std::string("/exe")); if (!std::filesystem::exists(executable) || !std::filesystem::is_symlink(executable)) { return std::string(); } executable = std::filesystem::canonical(executable); if (!std::filesystem::exists(executable)) return std::string(); return executable.remove_filename().string(); #elif defined(QUL_OS_WIN) wchar_t buffer[MAX_PATH + 2]; DWORD v = GetModuleFileNameW(NULL, buffer, MAX_PATH + 1); buffer[MAX_PATH + 1] = 0; std::filesystem::path executable; if (v == 0) return NULL; else if (v <= MAX_PATH) { std::wstring ws(buffer); executable = std::filesystem::path(std::string(ws.begin(), ws.end())); return executable.remove_filename().string(); } // MAX_PATH sized buffer wasn't large enough to contain the full path, use heap wchar_t *b = 0; int i = 1; size_t size; do { ++i; size = MAX_PATH * i; b = reinterpret_cast<wchar_t *>(std::realloc(b, (size + 1) * sizeof(wchar_t))); if (b) v = GetModuleFileNameW(NULL, b, size); } while (b && v == size); if (b) *(b + size) = 0; std::wstring res(b); std::free(b); executable = std::filesystem::path(std::string(res.begin(), res.end())); return executable.remove_filename().string(); #else #error Not implemented #endif } PosixFile::PosixFile(int fileHandle) { m_fileHandle = fileHandle; } PosixFile::~PosixFile() { if (m_fileHandle >= 0) close(); } uint64_t PosixFile::size() { struct stat64 stat_buf; int rc = ::fstat64(m_fileHandle, &stat_buf); return rc == 0 ? stat_buf.st_size : 0; } int PosixFile::read(unsigned char *outputBuffer, uint64_t startOffset, unsigned int readSize) { off_t offt = ::lseek(m_fileHandle, startOffset, SEEK_SET); if (offt == -1) { Qul::PlatformInterface::log("Failed to seek: %s\n", strerror(errno)); return -1; } ssize_t actualSize = ::read(m_fileHandle, outputBuffer, readSize); if (actualSize != readSize) { Qul::PlatformInterface::log("Unable to read enough data: %s\n", strerror(errno)); } return actualSize; } int PosixFile::close() { if (::close(m_fileHandle) != 0) { Qul::PlatformInterface::log("Unable to close file: %s\n", strerror(errno)); return -1; } m_fileHandle = -1; return 0; } Qul::PlatformInterface::File *PosixFilesystem::open(const char *fileName, Qul::PlatformInterface::File::Mode mode) { if (strlen(fileName) == 0) { Qul::PlatformInterface::log("File name is empty.\n"); return nullptr; } std::filesystem::path path(fileName); if (path.is_relative()) { // In case the path is relative, it is treated relative to the application binary. path = std::filesystem::path(appFilePath()) / path; } #ifndef NDEBUG Qul::PlatformInterface::log("Loading file %s\n", path.string().c_str()); #endif #ifdef QUL_OS_LINUX int flags = O_CLOEXEC; #elif defined(QUL_OS_MACOS) int flags = O_CLOEXEC; #elif defined(QUL_OS_WIN) int flags = O_BINARY; #endif if (mode == Qul::PlatformInterface::File::Mode::ReadOnly) flags |= O_RDONLY; else { Qul::PlatformInterface::log("Only Read-Only is supported"); return nullptr; } if (std::filesystem::is_directory(path)) { Qul::PlatformInterface::log("Could not open file '%s' because it is a directory.\n", path.make_preferred().string().c_str()); return nullptr; } int handle = ::open(path.make_preferred().string().c_str(), flags); if (handle < 0) { Qul::PlatformInterface::log("Could not open file: %s\n", strerror(errno)); return nullptr; } return Qul::PlatformInterface::qul_new<PosixFile>(handle); }