mirror of https://github.com/AxioDL/metaforce.git
Merge pull request #15 from lioncash/file
hecl/hecl: Introduce FopenUnique
This commit is contained in:
commit
e691b95cbf
|
@ -255,7 +255,7 @@ static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, T
|
|||
return std::make_unique<ToolHelp>(info);
|
||||
}
|
||||
|
||||
std::unique_ptr<FILE, decltype(&std::fclose)> fp{hecl::Fopen(toolName.c_str(), _SYS_STR("rb")), std::fclose};
|
||||
auto fp = hecl::FopenUnique(toolName.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
|
||||
return nullptr;
|
||||
|
|
|
@ -257,7 +257,7 @@ public:
|
|||
class ConfigFile {
|
||||
SystemString m_filepath;
|
||||
std::vector<std::string> m_lines;
|
||||
FILE* m_lockedFile = nullptr;
|
||||
UniqueFilePtr m_lockedFile;
|
||||
|
||||
public:
|
||||
ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/"));
|
||||
|
|
|
@ -275,6 +275,16 @@ inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType
|
|||
return fp;
|
||||
}
|
||||
|
||||
struct UniqueFileDeleter {
|
||||
void operator()(FILE* file) const noexcept { std::fclose(file); }
|
||||
};
|
||||
using UniqueFilePtr = std::unique_ptr<FILE, UniqueFileDeleter>;
|
||||
|
||||
inline UniqueFilePtr FopenUnique(const SystemChar* path, const SystemChar* mode,
|
||||
FileLockType lock = FileLockType::None) {
|
||||
return UniqueFilePtr{Fopen(path, mode, lock)};
|
||||
}
|
||||
|
||||
inline int FSeek(FILE* fp, int64_t offset, int whence) {
|
||||
#if _WIN32
|
||||
return _fseeki64(fp, offset, whence);
|
||||
|
|
|
@ -60,19 +60,23 @@ extern "C" uint8_t HECL_STARTUP[];
|
|||
extern "C" size_t HECL_STARTUP_SZ;
|
||||
|
||||
static void InstallBlendershell(const SystemChar* path) {
|
||||
FILE* fp = hecl::Fopen(path, _SYS_STR("w"));
|
||||
if (!fp)
|
||||
auto fp = hecl::FopenUnique(path, _SYS_STR("w"));
|
||||
|
||||
if (fp == nullptr) {
|
||||
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("unable to open {} for writing")), path);
|
||||
fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp.get());
|
||||
}
|
||||
|
||||
static void InstallAddon(const SystemChar* path) {
|
||||
FILE* fp = hecl::Fopen(path, _SYS_STR("wb"));
|
||||
if (!fp)
|
||||
auto fp = hecl::FopenUnique(path, _SYS_STR("wb"));
|
||||
|
||||
if (fp == nullptr) {
|
||||
BlenderLog.report(logvisor::Fatal, fmt(_SYS_STR("Unable to install blender addon at '{}'")), path);
|
||||
fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp.get());
|
||||
}
|
||||
|
||||
static int Read(int fd, void* buf, size_t size) {
|
||||
|
@ -224,18 +228,20 @@ void Connection::_closePipe() {
|
|||
|
||||
void Connection::_blenderDied() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
FILE* errFp = hecl::Fopen(m_errPath.c_str(), _SYS_STR("r"));
|
||||
if (errFp) {
|
||||
fseek(errFp, 0, SEEK_END);
|
||||
int64_t len = hecl::FTell(errFp);
|
||||
if (len) {
|
||||
fseek(errFp, 0, SEEK_SET);
|
||||
std::unique_ptr<char[]> buf(new char[len + 1]);
|
||||
memset(buf.get(), 0, len + 1);
|
||||
fread(buf.get(), 1, len, errFp);
|
||||
auto errFp = hecl::FopenUnique(m_errPath.c_str(), _SYS_STR("r"));
|
||||
|
||||
if (errFp != nullptr) {
|
||||
std::fseek(errFp.get(), 0, SEEK_END);
|
||||
const int64_t len = hecl::FTell(errFp.get());
|
||||
|
||||
if (len != 0) {
|
||||
std::fseek(errFp.get(), 0, SEEK_SET);
|
||||
const auto buf = std::make_unique<char[]>(len + 1);
|
||||
std::fread(buf.get(), 1, len, errFp.get());
|
||||
BlenderLog.report(logvisor::Fatal, fmt("\n{:.{}s}"), buf.get(), len);
|
||||
}
|
||||
}
|
||||
|
||||
BlenderLog.report(logvisor::Fatal, fmt("Blender Exception"));
|
||||
}
|
||||
|
||||
|
|
|
@ -43,17 +43,19 @@ Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, S
|
|||
}
|
||||
|
||||
std::vector<std::string>& Project::ConfigFile::lockAndRead() {
|
||||
if (m_lockedFile)
|
||||
if (m_lockedFile != nullptr) {
|
||||
return m_lines;
|
||||
}
|
||||
|
||||
m_lockedFile = hecl::Fopen(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
|
||||
hecl::FSeek(m_lockedFile, 0, SEEK_SET);
|
||||
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
|
||||
hecl::FSeek(m_lockedFile.get(), 0, SEEK_SET);
|
||||
|
||||
std::string mainString;
|
||||
char readBuf[1024];
|
||||
size_t readSz;
|
||||
while ((readSz = fread(readBuf, 1, 1024, m_lockedFile)))
|
||||
while ((readSz = std::fread(readBuf, 1, sizeof(readBuf), m_lockedFile.get()))) {
|
||||
mainString += std::string(readBuf, readSz);
|
||||
}
|
||||
|
||||
std::string::const_iterator begin = mainString.begin();
|
||||
std::string::const_iterator end = mainString.begin();
|
||||
|
@ -110,14 +112,13 @@ bool Project::ConfigFile::checkForLine(std::string_view refLine) {
|
|||
}
|
||||
|
||||
void Project::ConfigFile::unlockAndDiscard() {
|
||||
if (!m_lockedFile) {
|
||||
if (m_lockedFile == nullptr) {
|
||||
LogModule.reportSource(logvisor::Fatal, __FILE__, __LINE__, fmt("Project::ConfigFile::lockAndRead not yet called"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_lines.clear();
|
||||
fclose(m_lockedFile);
|
||||
m_lockedFile = NULL;
|
||||
m_lockedFile.reset();
|
||||
}
|
||||
|
||||
bool Project::ConfigFile::unlockAndCommit() {
|
||||
|
@ -126,23 +127,22 @@ bool Project::ConfigFile::unlockAndCommit() {
|
|||
return false;
|
||||
}
|
||||
|
||||
SystemString newPath = m_filepath + _SYS_STR(".part");
|
||||
FILE* newFile = hecl::Fopen(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
|
||||
const SystemString newPath = m_filepath + _SYS_STR(".part");
|
||||
auto newFile = hecl::FopenUnique(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
|
||||
bool fail = false;
|
||||
for (const std::string& line : m_lines) {
|
||||
if (fwrite(line.c_str(), 1, line.size(), newFile) != line.size()) {
|
||||
if (std::fwrite(line.c_str(), 1, line.size(), newFile.get()) != line.size()) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
if (fwrite("\n", 1, 1, newFile) != 1) {
|
||||
if (std::fputc('\n', newFile.get()) == EOF) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_lines.clear();
|
||||
fclose(newFile);
|
||||
fclose(m_lockedFile);
|
||||
m_lockedFile = NULL;
|
||||
newFile.reset();
|
||||
m_lockedFile.reset();
|
||||
if (fail) {
|
||||
#if HECL_UCS2
|
||||
_wunlink(newPath.c_str());
|
||||
|
@ -191,20 +191,21 @@ Project::Project(const ProjectRootPath& rootPath)
|
|||
m_cookedRoot.makeDir();
|
||||
|
||||
/* Ensure beacon is valid or created */
|
||||
ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
|
||||
FILE* bf = hecl::Fopen(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
|
||||
const ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
|
||||
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
|
||||
struct BeaconStruct {
|
||||
hecl::FourCC magic;
|
||||
uint32_t version;
|
||||
} beacon;
|
||||
#define DATA_VERSION 1
|
||||
if (fread(&beacon, 1, sizeof(beacon), bf) != sizeof(beacon)) {
|
||||
fseek(bf, 0, SEEK_SET);
|
||||
constexpr uint32_t DATA_VERSION = 1;
|
||||
if (std::fread(&beacon, 1, sizeof(beacon), bf.get()) != sizeof(beacon)) {
|
||||
std::fseek(bf.get(), 0, SEEK_SET);
|
||||
beacon.magic = HECLfcc;
|
||||
beacon.version = SBig(DATA_VERSION);
|
||||
fwrite(&beacon, 1, sizeof(beacon), bf);
|
||||
std::fwrite(&beacon, 1, sizeof(beacon), bf.get());
|
||||
}
|
||||
fclose(bf);
|
||||
bf.reset();
|
||||
|
||||
if (beacon.magic != HECLfcc || SBig(beacon.version) != DATA_VERSION) {
|
||||
LogModule.report(logvisor::Fatal, fmt("incompatible project version"));
|
||||
return;
|
||||
|
|
|
@ -256,17 +256,22 @@ ProjectRootPath SearchForProject(SystemStringView path) {
|
|||
Sstat theStat;
|
||||
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
|
||||
if (S_ISREG(theStat.st_mode)) {
|
||||
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char magic[4];
|
||||
size_t readSize = fread(magic, 1, 4, fp);
|
||||
fclose(fp);
|
||||
if (readSize != 4)
|
||||
const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
|
||||
if (readSize != sizeof(magic)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static constexpr hecl::FourCC hecl("HECL");
|
||||
if (hecl::FourCC(magic) != hecl)
|
||||
if (hecl::FourCC(magic) != hecl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return ProjectRootPath(testPath);
|
||||
}
|
||||
}
|
||||
|
@ -280,40 +285,51 @@ ProjectRootPath SearchForProject(SystemStringView path) {
|
|||
}
|
||||
|
||||
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
|
||||
ProjectRootPath testRoot(path);
|
||||
const ProjectRootPath testRoot(path);
|
||||
auto begin = testRoot.getAbsolutePath().begin();
|
||||
auto end = testRoot.getAbsolutePath().end();
|
||||
|
||||
while (begin != end) {
|
||||
SystemString testPath(begin, end);
|
||||
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
|
||||
Sstat theStat;
|
||||
|
||||
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
|
||||
if (S_ISREG(theStat.st_mode)) {
|
||||
FILE* fp = hecl::Fopen(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char magic[4];
|
||||
size_t readSize = fread(magic, 1, 4, fp);
|
||||
fclose(fp);
|
||||
if (readSize != 4)
|
||||
const size_t readSize = std::fread(magic, 1, sizeof(magic), fp.get());
|
||||
if (readSize != sizeof(magic)) {
|
||||
continue;
|
||||
if (hecl::FourCC(magic) != FOURCC('HECL'))
|
||||
}
|
||||
if (hecl::FourCC(magic) != FOURCC('HECL')) {
|
||||
continue;
|
||||
ProjectRootPath newRootPath = ProjectRootPath(testPath);
|
||||
auto origEnd = testRoot.getAbsolutePath().end();
|
||||
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\'))
|
||||
}
|
||||
|
||||
const ProjectRootPath newRootPath = ProjectRootPath(testPath);
|
||||
const auto origEnd = testRoot.getAbsolutePath().end();
|
||||
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\')) {
|
||||
++end;
|
||||
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\')))
|
||||
}
|
||||
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) {
|
||||
++end;
|
||||
}
|
||||
|
||||
subpathOut.assign(end, origEnd);
|
||||
return newRootPath;
|
||||
}
|
||||
}
|
||||
|
||||
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
|
||||
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\')) {
|
||||
--end;
|
||||
if (begin != end)
|
||||
}
|
||||
if (begin != end) {
|
||||
--end;
|
||||
}
|
||||
}
|
||||
return ProjectRootPath();
|
||||
}
|
||||
|
|
|
@ -57,44 +57,45 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
|
|||
|
||||
#endif
|
||||
|
||||
hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
|
||||
const hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
|
||||
|
||||
/* Try main steam install directory first */
|
||||
hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
|
||||
hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode))
|
||||
const hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
|
||||
const hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
|
||||
return mainAppPath;
|
||||
}
|
||||
|
||||
/* Iterate alternate steam install dirs */
|
||||
hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
|
||||
FILE* fp = hecl::Fopen(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
|
||||
if (!fp)
|
||||
const hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
|
||||
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
|
||||
if (fp == nullptr) {
|
||||
return {};
|
||||
hecl::FSeek(fp, 0, SEEK_END);
|
||||
int64_t fileLen = hecl::FTell(fp);
|
||||
}
|
||||
hecl::FSeek(fp.get(), 0, SEEK_END);
|
||||
const int64_t fileLen = hecl::FTell(fp.get());
|
||||
if (fileLen <= 0) {
|
||||
fclose(fp);
|
||||
return {};
|
||||
}
|
||||
hecl::FSeek(fp, 0, SEEK_SET);
|
||||
std::string fileBuf;
|
||||
fileBuf.resize(fileLen);
|
||||
if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) {
|
||||
fclose(fp);
|
||||
hecl::FSeek(fp.get(), 0, SEEK_SET);
|
||||
std::string fileBuf(fileLen, '\0');
|
||||
if (std::fread(fileBuf.data(), 1, fileLen, fp.get()) != fileLen) {
|
||||
return {};
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
std::smatch dirMatch;
|
||||
auto begin = fileBuf.cbegin();
|
||||
auto end = fileBuf.cend();
|
||||
const auto end = fileBuf.cend();
|
||||
while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
|
||||
std::string match = dirMatch[1].str();
|
||||
hecl::SystemStringConv otherInstallDir(match);
|
||||
hecl::SystemString otherAppPath =
|
||||
const std::string match = dirMatch[1].str();
|
||||
const hecl::SystemStringConv otherInstallDir(match);
|
||||
const auto otherAppPath =
|
||||
hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath;
|
||||
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode))
|
||||
|
||||
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
|
||||
return otherAppPath;
|
||||
}
|
||||
|
||||
begin = dirMatch.suffix().first;
|
||||
}
|
||||
|
||||
|
|
|
@ -144,38 +144,38 @@ void ResourceLock::ClearThreadRes() {
|
|||
}
|
||||
|
||||
bool IsPathPNG(const hecl::ProjectPath& path) {
|
||||
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
return false;
|
||||
uint32_t buf = 0;
|
||||
if (fread(&buf, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
uint32_t buf = 0;
|
||||
if (std::fread(&buf, 1, sizeof(buf), fp.get()) != sizeof(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = hecl::SBig(buf);
|
||||
if (buf == 0x89504e47)
|
||||
return true;
|
||||
return false;
|
||||
return buf == 0x89504e47;
|
||||
}
|
||||
|
||||
bool IsPathBlend(const hecl::ProjectPath& path) {
|
||||
auto lastCompExt = path.getLastComponentExt();
|
||||
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend")))
|
||||
return false;
|
||||
FILE* fp = hecl::Fopen(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (!fp)
|
||||
return false;
|
||||
uint32_t buf = 0;
|
||||
if (fread(&buf, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
const auto lastCompExt = path.getLastComponentExt();
|
||||
if (lastCompExt.empty() || hecl::StrCmp(lastCompExt.data(), _SYS_STR("blend"))) {
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
|
||||
if (fp == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t buf = 0;
|
||||
if (std::fread(&buf, 1, sizeof(buf), fp.get()) != sizeof(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = hecl::SLittle(buf);
|
||||
if (buf == 0x4e454c42 || buf == 0x88b1f)
|
||||
return true;
|
||||
return false;
|
||||
return buf == 0x4e454c42 || buf == 0x88b1f;
|
||||
}
|
||||
|
||||
bool IsPathYAML(const hecl::ProjectPath& path) {
|
||||
|
|
Loading…
Reference in New Issue