Merge pull request #15 from lioncash/file

hecl/hecl: Introduce FopenUnique
This commit is contained in:
Phillip Stephens 2019-08-21 23:16:25 -07:00 committed by GitHub
commit e691b95cbf
8 changed files with 137 additions and 103 deletions

View File

@ -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;

View File

@ -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/"));

View File

@ -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);

View File

@ -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"));
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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) {