refactor(file): overhaul filesystem for better accuracy, add some new features too

This commit is contained in:
phaneron 2025-03-15 22:23:38 -04:00
parent e674242b47
commit 5d96890167
111 changed files with 3708 additions and 3420 deletions

29
bc/File.hpp Normal file
View file

@ -0,0 +1,29 @@
#ifndef BC_FILE_HPP
#define BC_FILE_HPP
#include "bc/file/Defines.hpp"
#include "bc/file/Error.hpp"
#include "bc/file/SimpleGlob.hpp"
#include "bc/file/Close.hpp"
#include "bc/file/Copy.hpp"
#include "bc/file/CreateDirectory.hpp"
#include "bc/file/Delete.hpp"
#include "bc/file/Exists.hpp"
#include "bc/file/GetFileInfo.hpp"
#include "bc/file/GetPos.hpp"
#include "bc/file/GetWorkingDirectory.hpp"
#include "bc/file/IsAbsolutePath.hpp"
#include "bc/file/MakeAbsolutePath.hpp"
#include "bc/file/Move.hpp"
#include "bc/file/Open.hpp"
#include "bc/file/ProcessDirFast.hpp"
#include "bc/file/Read.hpp"
#include "bc/file/RemoveDirectory.hpp"
#include "bc/file/SetAttributes.hpp"
#include "bc/file/SetPos.hpp"
#include "bc/file/SetWorkingDirectory.hpp"
#include "bc/file/Write.hpp"
#endif

19
bc/file/Close.cpp Normal file
View file

@ -0,0 +1,19 @@
#include "bc/file/Close.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool Close(StreamRecord* file) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, close);
parms.file = file;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->close(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

16
bc/file/Close.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef BC_FILE_CLOSE_HPP
#define BC_FILE_CLOSE_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// close
bool Close(StreamRecord* file);
} // namespace File
} // namespace Blizzard
#endif

20
bc/file/Copy.cpp Normal file
View file

@ -0,0 +1,20 @@
#include "bc/file/Copy.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool Copy(const char* src, const char* dst, bool overwrite) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, copy);
parms.name = src;
parms.newname = dst;
parms.overwrite = overwrite;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->copy(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

13
bc/file/Copy.hpp Normal file
View file

@ -0,0 +1,13 @@
#ifndef BC_FILE_COPY_HPP
#define BC_FILE_COPY_HPP
namespace Blizzard {
namespace File {
// copy
bool Copy(const char* src, const char* dst, bool overwrite);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,19 @@
#include "bc/file/CreateDirectory.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool CreateDirectory(const char* name, bool recurse) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, mkdir);
parms.name = name;
parms.recurse = recurse;
parms.set_acl = 0;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->mkdir(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,15 @@
#ifndef BC_FILE_CREATE_DIRECTORY_HPP
#define BC_FILE_CREATE_DIRECTORY_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// mkdir
bool CreateDirectory(const char* name, bool recurse);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1,22 +1,9 @@
#ifndef BC_FILE_DEFINES_HPP #ifndef BC_FILE_DEFINES_HPP
#define BC_FILE_DEFINES_HPP #define BC_FILE_DEFINES_HPP
// How many bytes to when translating stacked filesystem names to large, native file paths
#define BC_FILE_MAX_PATH 1024 #define BC_FILE_MAX_PATH 1024
// File open/creation flags. // file attribute flags
// See Blizzard::File::Open() for more info
#define BC_FILE_OPEN_READ 0x0001
#define BC_FILE_OPEN_WRITE 0x0002
#define BC_FILE_OPEN_SHARE_READ 0x0004
#define BC_FILE_OPEN_SHARE_WRITE 0x0008
#define BC_FILE_OPEN_TRUNCATE 0x0100
#define BC_FILE_OPEN_ALWAYS 0x0200
#define BC_FILE_OPEN_CREATE 0x0400
#define BC_FILE_OPEN_MUST_NOT_EXIST 0x0800
#define BC_FILE_OPEN_MUST_EXIST 0x1000
// File attribute flags
#define BC_FILE_ATTRIBUTE_READONLY 0x01 #define BC_FILE_ATTRIBUTE_READONLY 0x01
#define BC_FILE_ATTRIBUTE_HIDDEN 0x02 #define BC_FILE_ATTRIBUTE_HIDDEN 0x02
#define BC_FILE_ATTRIBUTE_SYSTEM 0x04 #define BC_FILE_ATTRIBUTE_SYSTEM 0x04
@ -25,28 +12,28 @@
#define BC_FILE_ATTRIBUTE_NORMAL 0x20 #define BC_FILE_ATTRIBUTE_NORMAL 0x20
#define BC_FILE_ATTRIBUTE_DIRECTORY 0x40 #define BC_FILE_ATTRIBUTE_DIRECTORY 0x40
// File error codes // file error codes
#define BC_FILE_ERROR_GENERIC_FAILURE 0 #define BC_FILE_ERROR_GENERIC_FAILURE 0
#define BC_FILE_ERROR_ACCESS_DENIED 1 #define BC_FILE_ERROR_ACCESS_DENIED 1
#define BC_FILE_ERROR_FILE_NOT_FOUND 2 #define BC_FILE_ERROR_FILE_NOT_FOUND 2
#define BC_FILE_ERROR_BAD_FILE 3 #define BC_FILE_ERROR_BAD_FILE 3
#define BC_FILE_ERROR_BUSY 4 #define BC_FILE_ERROR_BUSY 4
#define BC_FILE_ERROR_OOM 5 #define BC_FILE_ERROR_READ 5
#define BC_FILE_ERROR_INVALID_HANDLE 6 #define BC_FILE_ERROR_WRITE 6
#define BC_FILE_ERROR_END_OF_FILE 7 #define BC_FILE_ERROR_END_OF_FILE 7
#define BC_FILE_ERROR_INVALID_ARGUMENT 8 #define BC_FILE_ERROR_INVALID_ARGUMENT 8
#define BC_FILE_ERROR_UNIMPLEMENTED 9 #define BC_FILE_ERROR_UNIMPLEMENTED 9
#define BC_FILE_ERROR_NO_SPACE_ON_DEVICE 11 #define BC_FILE_ERROR_NO_SPACE_ON_DEVICE 11
// File SetPos whence // file SetPos whence
#define BC_FILE_SEEK_START 0 #define BC_FILE_SEEK_START 0
#define BC_FILE_SEEK_CURRENT 1 #define BC_FILE_SEEK_CURRENT 1
#define BC_FILE_SEEK_END 2 #define BC_FILE_SEEK_END 2
// Error handling utilities // error handling utilities
#define BC_FILE_SET_ERROR(errorcode) ::Blizzard::File::SetLastError(static_cast<int32_t>(errorcode)) #define BC_FILE_SET_ERROR(errorcode) ::Blizzard::File::SetLastError(static_cast<int32_t>(errorcode))
#define BC_FILE_SET_ERROR_MSG(errorcode, pfmt, ...) \ #define BC_FILE_SET_ERROR_MSG(errorcode, pfmt, ...) \
::Blizzard::File::SetLastError(errorcode); \ ::Blizzard::File::SetLastError(errorcode); \
::Blizzard::File::AddToLastErrorStack(errorcode, ::Blizzard::String::QuickFormat<1024>(pfmt, ##__VA_ARGS__).Str(), 1) ::Blizzard::File::AddToLastErrorStack(errorcode, ::Blizzard::String::QuickFormat<1024>(pfmt, ##__VA_ARGS__).ToString(), 1)
#endif #endif

19
bc/file/Delete.cpp Normal file
View file

@ -0,0 +1,19 @@
#include "bc/file/Delete.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool Delete(const char* name) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, unlink);
parms.name = name;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->unlink(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

13
bc/file/Delete.hpp Normal file
View file

@ -0,0 +1,13 @@
#ifndef BC_FILE_DELETE_HPP
#define BC_FILE_DELETE_HPP
namespace Blizzard {
namespace File {
// unlink
bool Delete(const char* name);
} // namespace File
} // namespace Blizzard
#endif

28
bc/file/Error.cpp Normal file
View file

@ -0,0 +1,28 @@
#include "bc/file/Error.hpp"
#include <cstdio>
#include <cinttypes>
namespace Blizzard {
namespace File {
// Functions
void SetLastError(int32_t errorcode) {
// TODO
}
void AddToLastErrorStack(int32_t errorcode, const char* msg, int32_t a3) {
// TODO: use proper logging
char empty[] = "";
if (!msg) {
msg = empty;
}
fprintf(stderr, "[bc/file] %" PRIi32 ": '%s'\n", errorcode, msg);
}
}
}

17
bc/file/Error.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef BC_FILE_ERROR_HPP
#define BC_FILE_ERROR_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// Functions
void SetLastError(int32_t errorcode);
void AddToLastErrorStack(int32_t errorcode, const char* msg, int32_t param_3);
} // namespace File
} // namespace Blizzard
#endif

34
bc/file/Exists.cpp Normal file
View file

@ -0,0 +1,34 @@
#include "bc/file/Exists.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
uint32_t Exists(const char* name) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, exists);
parms.name = name;
parms.info = &parms.noinfo;
auto fs = System_File::Stacked::s_manager;
if (name && fs && fs->exists(fs, &parms)) {
return parms.info->filetype;
} else {
return 0;
}
}
bool IsFile(const char* name) {
return Exists(name) == 1;
}
bool IsDirectory(const char* name) {
return Exists(name) == 2;
}
} // namespace File
} // namespace Blizzard

21
bc/file/Exists.hpp Normal file
View file

@ -0,0 +1,21 @@
#ifndef BC_FILE_EXISTS_HPP
#define BC_FILE_EXISTS_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// exists
uint32_t Exists(const char* name);
// exists
bool IsFile(const char* name);
// exists
bool IsDirectory(const char* name);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1,371 +0,0 @@
#include "bc/file/File.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include <cstdio>
#include <cinttypes>
namespace Blizzard {
namespace File {
// Functions
void SetLastError(int32_t errorcode) {
// TODO
}
void AddToLastErrorStack(int32_t errorcode, const char* msg, int32_t a3) {
// TODO: use proper logging
char empty[] = "";
if (!msg) {
msg = empty;
}
fprintf(stderr, "[bc/file] %" PRIi32 ": '%s'\n", errorcode, msg);
}
// In BlizzardCore parlance, a file only exists if its path points to a regular file. (not a directory)
// i.e. directories are not considered to be file objects.
bool Exists(const char* path) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
FileInfo info = {};
System_File::Stacked::FileParms parms = {};
parms.filename = path;
parms.info = &info;
auto status = manager->Do(Filesystem::Call::Exists, &parms);
return status;
}
bool Flush(StreamRecord* stream) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = stream;
auto status = manager->Do(Filesystem::Call::Flush, &parms);
return status;
}
// Alias of Exists.
bool IsFile(const char* path) {
return Exists(path);
}
// Calls Exists internally, only checking whether it has the directory attribute instead of normal attribute
bool IsDirectory(const char* path) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
FileInfo info = {};
System_File::Stacked::FileParms parms = {};
parms.filename = path;
parms.info = &info;
auto status = manager->Do(Filesystem::Call::Exists, &parms);
return info.attributes & BC_FILE_ATTRIBUTE_DIRECTORY;
}
// Delete a file.
bool Delete(const char* path) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
auto status = manager->Do(Filesystem::Call::Delete, &parms);
return status;
}
bool IsAbsolutePath(const char* path) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
return manager->Do(Filesystem::Call::IsAbsolutePath, &parms);
}
// Get file information about path, writing information to the passed info pointer.
bool GetFileInfo(const char* path, FileInfo* info) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
parms.info = info;
auto status = manager->Do(Filesystem::Call::GetFileInfo, &parms);
return status;
}
// Get file information from a StreamRecord, writing information to the passed info pointer.
bool GetFileInfo(StreamRecord* stream, FileInfo* info) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = stream;
parms.info = info;
return manager->Do(Filesystem::Call::GetFileInfo, &parms);
}
bool GetWorkingDirectory(char* path, size_t capacity) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.directory = path;
parms.directorySize = capacity;
return manager->Do(Filesystem::Call::GetWorkingDirectory, &parms);
}
bool SetWorkingDirectory(const char* path) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
return manager->Do(Filesystem::Call::SetWorkingDirectory, &parms);
}
// Get file information from a stream record, returning a file info pointer owned by StreamRecord
// The FileInfo ptr returned is invalidated after a call to File::Close(stream)
FileInfo* GetFileInfo(StreamRecord* stream) {
static FileInfo s_noinfo = {};
auto manager = System_File::Stacked::Manager();
if (!manager) {
return &s_noinfo;
}
System_File::Stacked::FileParms parms = {};
parms.stream = stream;
parms.info = nullptr;
auto status = manager->Do(Filesystem::Call::GetFileInfo, &parms);
if (status) {
return parms.info;
}
return &s_noinfo;
}
bool MakeAbsolutePath(const char* rel, char* result, int32_t capacity, bool unkflag) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = rel;
parms.flag = unkflag;
parms.directory = result;
parms.directorySize = capacity;
return manager->Do(Filesystem::Call::MakeAbsolutePath, &parms);
}
// Open a filename according to flags (see Defines.hpp)
// if successful, will return true and referenced file object will be set
bool Open(const char* filename, uint32_t flags, StreamRecord*& file) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = filename;
parms.flag = flags;
auto status = manager->Do(Filesystem::Call::Open, &parms);
if (status) {
file = parms.stream;
}
return status;
}
bool SetAttributes(const char* filename, uint32_t attributes) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = filename;
parms.flag = static_cast<uint32_t>(attributes);
parms.mode = File::Mode::setperms;
return manager->Do(Filesystem::Call::SetAttributes, &parms);
}
bool Close(StreamRecord* stream) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = stream;
auto status = manager->Do(Filesystem::Call::Close, &parms);
return status;
}
bool Copy(const char* source, const char* destination, bool overwrite) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = source;
parms.destination = destination;
return manager->Do(Filesystem::Call::Copy, &parms);
}
bool CreateDirectory(const char* path, bool recursive) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
parms.flag = recursive;
return manager->Do(Filesystem::Call::CreateDirectory, &parms);
}
bool ProcessDirFast(const char* path, void* param, ProcessDirCallback callback, bool unkflag) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.filename = path;
parms.param = param;
parms.flag = unkflag;
parms.callback = callback;
return manager->Do(Filesystem::Call::ProcessDirFast, &parms);
}
bool Read(StreamRecord* file, void* buffer, size_t bytesToRead, size_t* bytesRead) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = file;
parms.param = buffer;
parms.size = bytesToRead;
auto status = manager->Do(Filesystem::Call::Read, &parms);
if (bytesRead) {
*bytesRead = static_cast<size_t>(parms.size);
}
return status;
}
bool Write(StreamRecord* file, void* buffer, size_t bytesToWrite, size_t* bytesWritten) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = file;
parms.param = buffer;
parms.size = bytesToWrite;
auto status = manager->Do(Filesystem::Call::Write, &parms);
if (bytesWritten) {
*bytesWritten = static_cast<size_t>(parms.size);
}
return status;
}
bool SetPos(StreamRecord* file, int64_t pos, int32_t whence) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = file;
parms.position = pos;
parms.whence = whence;
return manager->Do(Filesystem::Call::SetPos, &parms);
}
bool GetPos(StreamRecord* file, int64_t& pos) {
auto manager = System_File::Stacked::Manager();
if (!manager) {
return false;
}
System_File::Stacked::FileParms parms = {};
parms.stream = file;
parms.position = pos;
auto status = manager->Do(Filesystem::Call::GetPos, &parms);
if (status) {
pos = parms.position;
}
return status;
}
} // namespace File
} // namespace Blizzard

View file

@ -1,60 +0,0 @@
#ifndef BC_FILE_FILE_HPP
#define BC_FILE_FILE_HPP
#include "bc/Time.hpp"
#include "bc/file/Defines.hpp"
#include "bc/file/Types.hpp"
#include "bc/system/file/System_File.hpp"
namespace Blizzard {
namespace File {
// Functions
void SetLastError(int32_t errorcode);
void AddToLastErrorStack(int32_t errorcode, const char* msg, int32_t param_3);
bool Copy(const char* source, const char* destination, bool overwrite);
bool CreateDirectory(const char* path, bool recursive);
bool Delete(const char* path);
bool Exists(const char* path);
bool Flush(StreamRecord* stream);
bool IsFile(const char* path);
bool IsDirectory(const char* path);
bool IsAbsolutePath(const char* path);
bool GetFileInfo(const char* path, FileInfo* info);
bool GetFileInfo(StreamRecord* stream, FileInfo* info);
FileInfo* GetFileInfo(StreamRecord* stream);
bool GetWorkingDirectory(char* path, size_t capacity);
bool SetWorkingDirectory(const char* path);
bool MakeAbsolutePath(const char* rel, char* result, int32_t capacity, bool unkflag);
bool Open(const char* filename, uint32_t flags, StreamRecord*& stream);
bool Close(StreamRecord* stream);
bool SetAttributes(const char* filename, uint32_t attributes);
bool Read(StreamRecord* stream, void* buffer, size_t bytesToRead, size_t* bytesRead);
bool Write(StreamRecord* stream, void* buffer, size_t bytesToWrite, size_t* bytesWritten);
bool SetPos(StreamRecord* stream, int64_t pos, int32_t whence);
bool GetPos(StreamRecord* stream, int64_t& pos);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1,21 +0,0 @@
#include "bc/file/Filesystem.hpp"
#include <cstddef>
namespace Blizzard {
namespace File {
bool Filesystem::Do(Filesystem::Call fscall, System_File::Stacked::FileParms* parms) {
uint32_t callindex = static_cast<uint32_t>(fscall);
// Mark byte offset of Call function.
// Allows the filesystem stack to resume normal activity in case of a fallback
parms->offset = offsetof(Filesystem, funcs) + (callindex * sizeof(uintptr_t));
// Get filesystem call from array
auto func = reinterpret_cast<Filesystem::CallFunc>(this->funcs[callindex]);
// Do call
return func(this, parms);
}
} // namespace File
} // namespace Blizzard

View file

@ -7,57 +7,49 @@
namespace Blizzard { namespace Blizzard {
namespace File { namespace File {
class Filesystem;
typedef bool (*Operation)(Filesystem* fs, System_File::Stacked::FileParms* parms);
// Filesystem describes the layout of a virtual filesystem. // Filesystem describes the layout of a virtual filesystem.
// It is linked to other Filesystems in a list structure. // It is linked to other Filesystems in a list structure.
class Filesystem { class Filesystem {
public: public:
enum class Call : uint32_t {
SetWorkingDirectory,
Close,
Create,
GetWorkingDirectory,
ProcessDirFast,
Exists,
Flush,
GetFileInfo,
GetFreeSpace,
GetPos,
GetRootChars,
IsAbsolutePath,
IsReadOnly,
MakeAbsolutePath,
CreateDirectory,
Move,
Copy,
Open,
Read,
ReadP,
RemoveDirectory,
SetCacheMode,
SetEOF,
SetAttributes,
SetPos,
Delete,
Write,
WriteP,
Shutdown,
EndOfCalls
};
// I hate C++ enums
static constexpr size_t s_numCalls = static_cast<size_t>(Call::EndOfCalls);
// One signature for all filesystem calls
typedef bool (*CallFunc)(Filesystem*, System_File::Stacked::FileParms*);
// The source filesystem (where it was copied from) // The source filesystem (where it was copied from)
// You can tell if base == this, that it is the original stack and not part of the filesystem manager // You can tell if base == this, that it is the original stack and not part of the filesystem manager
Filesystem* base; Filesystem* base;
// The next filesystem (towards lower filesystems) // The next filesystem (towards lower filesystems)
Filesystem* next; Filesystem* next;
CallFunc funcs[s_numCalls];
bool Do(Call call, System_File::Stacked::FileParms* parms); Operation cd;
Operation close;
Operation create;
Operation cwd;
Operation dirwalk;
Operation exists;
Operation flush;
Operation getfileinfo;
Operation getfreespace;
Operation getpos;
Operation getrootchars;
Operation isabspath;
Operation isreadonly;
Operation makeabspath;
Operation mkdir;
Operation move;
Operation copy;
Operation open;
Operation read;
Operation readp;
Operation rmdir;
Operation setcachemode;
Operation seteof;
Operation setfileinfo;
Operation setpos;
Operation unlink;
Operation write;
Operation writep;
Operation shutdown;
}; };
} // namespace File } // namespace File

61
bc/file/GetFileInfo.cpp Normal file
View file

@ -0,0 +1,61 @@
#include "bc/file/GetFileInfo.hpp"
#include "bc/file/Types.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool GetFileInfo(const char* name, FileInfo* info) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, getfileinfo);
parms.name = name;
parms.file = nullptr;
parms.setinfo = 0;
parms.getinfo = 0xFFFFFFFF;
parms.info = &parms.noinfo;
auto fs = System_File::Stacked::s_manager;
if (fs && fs->getfileinfo(fs, &parms)) {
*info = *parms.info;
return true;
}
return false;
}
FileInfo* GetFileInfo(StreamRecord* file) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, getfileinfo);
parms.name = nullptr;
parms.file = file;
parms.setinfo = 0;
parms.getinfo = 0xFFFFFFFF;
parms.info = nullptr;
auto fs = System_File::Stacked::s_manager;
if (fs && fs->getfileinfo(fs, &parms)) {
return parms.info;
}
static FileInfo s_noinfo = {};
return &s_noinfo;
}
bool GetFileInfo(StreamRecord* file, FileInfo* info) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, getfileinfo);
parms.name = nullptr;
parms.file = file;
parms.info = nullptr;
auto fs = System_File::Stacked::s_manager;
if (fs && fs->getfileinfo(fs, &parms)) {
*info = *parms.info;
return true;
}
return false;
}
} // namespace File
} // namespace Blizzard

22
bc/file/GetFileInfo.hpp Normal file
View file

@ -0,0 +1,22 @@
#ifndef BC_FILE_GET_FILE_INFO_HPP
#define BC_FILE_GET_FILE_INFO_HPP
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// getfileinfo
bool GetFileInfo(const char* name, FileInfo* info);
// getfileinfo
FileInfo* GetFileInfo(StreamRecord* file);
// getfileinfo
bool GetFileInfo(StreamRecord* file, FileInfo* info);
} // namespace File
} // namespace Blizzard
#endif

25
bc/file/GetPos.cpp Normal file
View file

@ -0,0 +1,25 @@
#include "bc/file/GetPos.hpp"
#include "bc/file/Defines.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool GetPos(StreamRecord* file, int64_t& offset) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, getpos);
parms.file = file;
parms.offset = offset;
parms.whence = BC_FILE_SEEK_CURRENT;
auto fs = System_File::Stacked::s_manager;
if (!fs || !fs->setpos(fs, &parms)) {
return false;
}
offset = parms.offset;
return true;
}
} // namespace File
} // namespace Blizzard

17
bc/file/GetPos.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef BC_FILE_GET_POS_HPP
#define BC_FILE_GET_POS_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// getpos
bool GetPos(StreamRecord* file, int64_t& offset);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,21 @@
#include "bc/file/GetWorkingDirectory.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool GetWorkingDirectory(char* buffer, int32_t buffersize) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, cwd);
parms.buffer = buffer;
parms.buffersize = buffersize;
*buffer = '\0';
auto fs = System_File::Stacked::s_manager;
return fs ? fs->cwd(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,15 @@
#ifndef BC_FILE_GET_WORKING_DIRECTORY_HPP
#define BC_FILE_GET_WORKING_DIRECTORY_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// cwd
bool GetWorkingDirectory(char* buffer, int32_t buffersize);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,19 @@
#include "bc/file/IsAbsolutePath.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool IsAbsolutePath(const char* name) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, isabspath);
parms.name = name;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->isabspath(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,12 @@
#ifndef BC_FILE_IS_ABSOLUTE_PATH_HPP
#define BC_FILE_IS_ABSOLUTE_PATH_HPP
namespace Blizzard {
namespace File {
bool IsAbsolutePath(const char* name);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,22 @@
#include "bc/file/MakeAbsolutePath.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool MakeAbsolutePath(const char* name, char* buffer, int32_t buffersize, bool canonicalize) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, makeabspath);
parms.name = name;
parms.buffer = buffer;
parms.buffersize = buffersize;
parms.canonicalize = canonicalize;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->makeabspath(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,15 @@
#ifndef BC_FILE_MAKE_ABSOLUTE_PATH_HPP
#define BC_FILE_MAKE_ABSOLUTE_PATH_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// makeabspath
bool MakeAbsolutePath(const char* name, char* buffer, int32_t buffersize, bool canonicalize);
} // namespace File
} // namespace Blizzard
#endif

19
bc/file/Move.cpp Normal file
View file

@ -0,0 +1,19 @@
#include "bc/file/Move.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool Move(const char* src, const char* dst) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, move);
parms.name = src;
parms.newname = dst;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->move(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

13
bc/file/Move.hpp Normal file
View file

@ -0,0 +1,13 @@
#ifndef BC_FILE_MOVE_HPP
#define BC_FILE_MOVE_HPP
namespace Blizzard {
namespace File {
// move
bool Move(const char* src, const char* dst);
} // namespace File
} // namespace Blizzard
#endif

25
bc/file/Open.cpp Normal file
View file

@ -0,0 +1,25 @@
#include "bc/file/Open.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool Open(const char* name, int32_t mode, StreamRecord*& file) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, open);
parms.name = name;
parms.mode = mode;
parms.file = nullptr;
auto fs = System_File::Stacked::s_manager;
if (!fs || !fs->open(fs, &parms)) {
return false;
}
file = parms.file;
return true;
}
} // namespace File
} // namespace Blizzard

16
bc/file/Open.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef BC_FILE_OPEN_HPP
#define BC_FILE_OPEN_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// open
bool Open(const char* name, int32_t mode, StreamRecord*& file);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1 +0,0 @@
#include "bc/file/path/Path.hpp"

View file

@ -0,0 +1,22 @@
#include "bc/file/ProcessDirFast.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool ProcessDirFast(const char* name, void* param, ProcessDirCallback callback, bool nofollow) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, dirwalk);
parms.name = name;
parms.dirwalkparam = param;
parms.dirwalkcallback = callback;
// parms.unk88 = false;
parms.mode = nofollow;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->dirwalk(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,15 @@
#ifndef BC_FILE_PROCESS_DIR_FAST_HPP
#define BC_FILE_PROCESS_DIR_FAST_HPP
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// dirwalk
bool ProcessDirFast(const char* name, void* param, ProcessDirCallback callback, bool flag);
} // namespace File
} // namespace Blizzard
#endif

41
bc/file/Read.cpp Normal file
View file

@ -0,0 +1,41 @@
#include "bc/file/Read.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool Read(StreamRecord* file, void* buffer, int32_t* count) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, read);
parms.file = file;
parms.data = buffer;
parms.count = *count;
*count = 0;
auto fs = System_File::Stacked::s_manager;
if (!fs || !fs->read(fs, &parms)) {
return false;
}
*count = parms.count;
return true;
}
bool Read(StreamRecord* file, void* buffer, int64_t offset, int32_t* count) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, readp);
parms.file = file;
parms.data = buffer;
parms.offset = offset;
parms.count = *count;
*count = 0;
auto fs = System_File::Stacked::s_manager;
if (!fs || !fs->readp(fs, &parms)) {
return false;
}
*count = parms.count;
return true;
}
} // namespace File
} // namespace Blizzard

19
bc/file/Read.hpp Normal file
View file

@ -0,0 +1,19 @@
#ifndef BC_FILE_READ_HPP
#define BC_FILE_READ_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// read
bool Read(StreamRecord* file, void* buffer, int32_t* count);
// readp
bool Read(StreamRecord* file, void* buffer, int64_t offset, int32_t* count);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,90 @@
#include "bc/file/RemoveDirectory.hpp"
#include "bc/file/ProcessDirFast.hpp"
#include "bc/file/Defines.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/file/SetAttributes.hpp"
#include "bc/file/Exists.hpp"
#include "bc/file/Delete.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/String.hpp"
namespace Blizzard {
namespace File {
bool RemoveDirectory(const char* name) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, rmdir);
parms.name = name;
parms.recurse = false;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->rmdir(fs, &parms) : false;
}
bool RemoveDirectoryAndContents(const char* name, bool noreadonly) {
class Internal {
public:
struct RemoveDirectoryRecurseData {
bool unk00;
bool noreadonly;
};
static bool RemoveDirectoryRecurse(RemoveDirectoryRecurseData* data, const char* name, bool noreadonly) {
data->unk00 = true;
data->noreadonly = noreadonly;
return File::ProcessDirFast(name, static_cast<void*>(data), Callback, false) && data->unk00;
}
static bool Callback(const ProcessDirParms& dirwalkparms) {
char name[BC_FILE_MAX_PATH];
auto rmdirdata = reinterpret_cast<RemoveDirectoryRecurseData*>(dirwalkparms.param);
bool removeditem = false;
if (dirwalkparms.isdir) {
String::Format(name, BC_FILE_MAX_PATH, "%s%s/", dirwalkparms.dir, dirwalkparms.item);
removeditem = File::RemoveDirectoryAndContents(name, true);
} else {
String::Format(name, BC_FILE_MAX_PATH, "%s%s", dirwalkparms.dir, dirwalkparms.item);
if (rmdirdata->noreadonly) {
File::SetAttributes(name, BC_FILE_ATTRIBUTE_NORMAL);
}
// TODO: ???
// if (sub_44EFB0(name)) {
// return true;
// }
removeditem = File::Delete(name);
}
if (!removeditem) {
rmdirdata->unk00 = false;
}
return true;
}
};
if (File::Exists(name) != 2) {
return false;
}
char path[BC_FILE_MAX_PATH];
String::Copy(path, name, BC_FILE_MAX_PATH);
String::ForceTrailingSeparator(path, BC_FILE_MAX_PATH, '\0');
Internal::RemoveDirectoryRecurseData rmdirdata;
if (!Internal::RemoveDirectoryRecurse(&rmdirdata, path, noreadonly)) {
return false;
}
return File::RemoveDirectory(name);
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,18 @@
#ifndef BC_FILE_REMOVE_DIRECTORY_HPP
#define BC_FILE_REMOVE_DIRECTORY_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// rmdir
bool RemoveDirectory(const char* name);
// rmdir (-r)
bool RemoveDirectoryAndContents(const char* name, bool a2);
} // namespace File
} // namespace Blizzard
#endif

23
bc/file/SetAttributes.cpp Normal file
View file

@ -0,0 +1,23 @@
#include "bc/file/SetAttributes.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/file/Defines.hpp"
#include "bc/system/file/Stacked.hpp"
#include <cstddef>
namespace Blizzard {
namespace File {
bool SetAttributes(const char* name, int32_t attributes) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, setfileinfo);
parms.name = name;
parms.setinfo = BC_SYSTEM_FILE_INFO_ATTRIBUTES;
parms.noinfo.attributes = attributes;
parms.info = &parms.noinfo;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->setfileinfo(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

16
bc/file/SetAttributes.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef BC_FILE_SET_ATTRIBUTES_HPP
#define BC_FILE_SET_ATTRIBUTES_HPP
#include <cstdint>
namespace Blizzard {
namespace File {
// setfileinfo
bool SetAttributes(const char* name, int32_t attributes);
} // namespace File
} // namespace Blizzard
#endif

20
bc/file/SetPos.cpp Normal file
View file

@ -0,0 +1,20 @@
#include "bc/file/SetPos.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
namespace Blizzard {
namespace File {
bool SetPos(StreamRecord* file, int64_t offset, int32_t whence) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, setpos);
parms.file = file;
parms.offset = offset;
parms.whence = whence;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->setpos(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

17
bc/file/SetPos.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef BC_FILE_SET_POS_HPP
#define BC_FILE_SET_POS_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// setpos
bool SetPos(StreamRecord* file, int64_t offset, int32_t whence);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -0,0 +1,19 @@
#include "bc/file/SetWorkingDirectory.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool SetWorkingDirectory(const char* name) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, cd);
parms.name = name;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->cd(fs, &parms) : false;
}
} // namespace File
} // namespace Blizzard

View file

@ -0,0 +1,13 @@
#ifndef BC_FILE_SET_WORKING_DIRECTORY_HPP
#define BC_FILE_SET_WORKING_DIRECTORY_HPP
namespace Blizzard {
namespace File {
// cd
bool SetWorkingDirectory(const char* name);
} // namespace File
} // namespace Blizzard
#endif

72
bc/file/SimpleGlob.cpp Normal file
View file

@ -0,0 +1,72 @@
#include "bc/file/SimpleGlob.hpp"
#include <cstdint>
#include <cctype>
namespace Blizzard {
namespace File {
bool SimpleGlob(const char* name, const char* pattern) {
auto p = pattern;
auto n = name;
while (true) {
if (*p == '\0') {
return !*n;
}
if (!*n && *p != '*') {
return false;
}
if (*p == '*') {
break;
}
if (*p == '?') {
if (!*n) {
return false;
}
} else {
if (*p == '\\' && p[1]) {
p++;
}
if (*p != *n) {
if (tolower(static_cast<uint8_t>(*n)) != tolower(static_cast<uint8_t>(*p))) {
return false;
}
}
}
n++;
p++;
}
while (*p == '*') {
p++;
}
if (*p) {
if (*p != '?' && *p != '\\') {
if (!*n) {
return false;
}
while (*p != *n) {
if (!*++n) {
return false;
}
}
}
if (!*n) {
return false;
}
while (!SimpleGlob(n, p)) {
n++;
if (*n == '\0') {
return false;
}
}
}
return true;
}
} // namespace File
} // namespace Blizzard

12
bc/file/SimpleGlob.hpp Normal file
View file

@ -0,0 +1,12 @@
#ifndef BC_FILE_SIMPLE_GLOB_HPP
#define BC_FILE_SIMPLE_GLOB_HPP
namespace Blizzard {
namespace File {
bool SimpleGlob(const char* name, const char* pattern);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -5,7 +5,7 @@
#include "bc/time/Time.hpp" #include "bc/time/Time.hpp"
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
#include <windows.h> typedef void* HANDLE;
#endif #endif
#include <cstddef> #include <cstddef>
@ -15,59 +15,57 @@ namespace File {
// Types // Types
// Used by SetCacheMode
enum Mode { enum Mode {
setperms = 4, read = 0x0001,
settimes = 16, write = 0x0002,
nocache = 64 shareread = 0x0004,
sharewrite = 0x0008,
nocache = 0x0040,
temporary = 0x0080,
truncate = 0x0100,
append = 0x0200,
create = 0x0400,
mustnotexist = 0x0800,
mustexist = 0x1000
}; };
class FileInfo { class FileInfo {
public: public:
Time::TimeRec* time; const char* name;
// The device ID storing this file. int32_t unk04;
uint32_t device;
// Tell if a file is a directory
// read-only, hidden
// See file/Defines.hpp for more
uint32_t attributes;
// Size in bytes
uint64_t size; uint64_t size;
// Note that these are Y2K time, not Unix int32_t attributes;
Time::Timestamp accessTime; Time::Timestamp createtime;
Time::Timestamp modificationTime; Time::Timestamp writetime;
Time::Timestamp attributeModificationTime; Time::Timestamp accesstime;
int32_t filetype;
int32_t normal;
}; };
class ProcessDirParms { class ProcessDirParms {
public: public:
const char* root = nullptr; const char* dir;
const char* item = nullptr; const char* item;
bool itemIsDirectory = false; void* param;
void* param = nullptr; bool isdir;
}; };
typedef bool (*ProcessDirCallback)(const ProcessDirParms&); typedef bool (*ProcessDirCallback)(const ProcessDirParms&);
class StreamRecord { class StreamRecord {
public: public:
static constexpr size_t s_padPath = 80;
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
HANDLE filehandle; HANDLE filehandle;
#endif #endif
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
// File descriptor int filefd;
int32_t filefd;
#endif #endif
// Open flags int32_t mode;
uint32_t flags; bool haveinfo;
// Determines whether info object is initialized uint32_t unk0C;
bool hasInfo; Blizzard::File::FileInfo info;
FileInfo info; int32_t* unk48;
// The path of the opened file. const char* name;
char path[s_padPath];
}; };
} // namespace File } // namespace File

57
bc/file/Write.cpp Normal file
View file

@ -0,0 +1,57 @@
#include "bc/file/Write.hpp"
#include "bc/file/Filesystem.hpp"
#include "bc/file/Types.hpp"
#include "bc/system/file/Stacked.hpp"
#include "bc/system/file/Types.hpp"
namespace Blizzard {
namespace File {
bool Write(StreamRecord* file, const void* data, int32_t count) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, write);
parms.file = file;
parms.data = const_cast<void*>(data);
parms.offset = -1LL;
parms.count = count;
auto fs = System_File::Stacked::s_manager;
return fs ? fs->write(fs, &parms) : false;
}
bool Write(StreamRecord* file, const void* data, int32_t* count) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, write);
parms.file = file;
parms.data = const_cast<void*>(data);
parms.offset = -1LL;
parms.count = *count;
auto fs = System_File::Stacked::s_manager;
if (!fs || fs->write(fs, &parms)) {
return false;
}
*count = parms.count;
return true;
}
bool Write(StreamRecord* file, const void* data, int64_t offset, int32_t* count) {
System_File::Stacked::FileParms parms;
parms.op = offsetof(Filesystem, writep);
parms.file = file;
parms.data = const_cast<void*>(data);
parms.offset = offset;
parms.count = *count;
auto fs = System_File::Stacked::s_manager;
if (!fs || fs->writep(fs, &parms)) {
return false;
}
*count = parms.count;
return true;
}
} // namespace File
} // namespace Blizzard

22
bc/file/Write.hpp Normal file
View file

@ -0,0 +1,22 @@
#ifndef BC_FILE_WRITE_HPP
#define BC_FILE_WRITE_HPP
#include <cstdint>
#include "bc/file/Types.hpp"
namespace Blizzard {
namespace File {
// write
bool Write(StreamRecord* file, const void* data, int32_t count);
// write
bool Write(StreamRecord* file, const void* data, int32_t* count);
// writep
bool Write(StreamRecord* file, const void* data, int64_t offset, int32_t* count);
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1,225 +0,0 @@
#include "bc/file/path/Path.hpp"
#include "bc/file/path/Posix.hpp"
#include "bc/String.hpp"
#include "bc/Memory.hpp"
#include "bc/Debug.hpp"
#include <cctype>
namespace Blizzard {
namespace File {
namespace Path {
// Classes
QuickNative::QuickNative(const char* path) {
this->size = 0;
this->slowpath = nullptr;
this->fastpath[0] = '\0';
if (!path) {
return;
}
// Null byte
constexpr size_t reserved = 1;
this->size = String::Length(path) + reserved;
char* nativePath = nullptr;
if (this->size < BC_FILE_MAX_PATH) {
// (fast)
nativePath = this->fastpath;
MakeNativePath(path, this->fastpath, BC_FILE_MAX_PATH);
} else {
// (slow)
this->slowpath = reinterpret_cast<char*>(Memory::Allocate(this->size));
nativePath = this->slowpath;
MakeNativePath(path, this->slowpath, this->size);
}
#if defined(WHOA_SYSTEM_LINUX)
// Linux typically does not involve a case-sensitive filesystem
// For compatibility, try to find if this path exists in another case
// This is much slower
// The size of the resolved path. Maybe be larger due to "./"
size_t resolvedSize = this->size + 2;
auto resolvedPath = static_cast<char*>(Memory::Allocate(resolvedSize));
resolvedPath[resolvedSize-1] = '\0';
bool wasResolved = ResolvePosixCasePath(nativePath, resolvedPath);
if (!wasResolved) {
Memory::Free(resolvedPath);
return;
}
if (this->slowpath != nullptr) {
Memory::Free(this->slowpath);
}
this->slowpath = resolvedPath;
#endif
}
QuickNative::~QuickNative() {
if (this->slowpath != nullptr) {
Memory::Free(this->slowpath);
}
}
const char* QuickNative::Str() {
if (this->slowpath != nullptr) {
return this->slowpath;
}
return this->fastpath;
}
size_t QuickNative::Size() {
return this->size;
}
// Functions
void ForceTrailingSeparator(char* buf, size_t bufMax, char sep) {
if (buf == nullptr) {
return;
}
// If no separator character is provided, infer correct separator based on runes
if (sep == '\0') {
auto ptr = buf;
char ch;
while (true) {
ch = *ptr++;
// Make inference based on what data we have.
if (ch == '/' || ch == '\\') {
sep = ch;
break;
}
if (ch == '\0') {
// Fail safe to the system's path separator.
sep = BC_FILE_SYSTEM_PATH_SEPARATOR;
break;
}
}
}
// Buffer needs at least two characters.
if (bufMax < 2) {
return;
}
// Slice off the end of the path buffer, so that any existing* trailing separator is discarded.
auto len = String::Length(buf);
char ch = '\0';
if (len > 0) {
ch = buf[len - 1];
}
switch (ch) {
case '/':
case '\\':
len--;
break;
default:
break;
}
// Add (back*) trailing separator
BLIZZARD_ASSERT(len <= bufMax - 2);
buf[len] = sep;
buf[len + 1] = '\0'; // pad null
}
// Convert path to DOS-style.
// the function will iterate through the path string, converting all occurrences of forward slashes (/) to backslashes (\)
bool MakeBackslashPath(const char* path, char* result, size_t capacity) {
size_t i = 0;
size_t c = capacity - 1;
while (i <= c) {
if (path[i] == '\0') {
result[i] = '\0';
return true;
}
result[i] = path[i] == '/' ? '\\' : path[i];
i++;
}
result[0] = '\0';
return false;
}
// Make a path string consistent before the last path separator.
bool MakeConsistentPath(const char* path, char* result, size_t capacity) {
if (!result || (capacity < 1)) {
return false;
}
if (!path || (capacity == 1)) {
*result = '\0';
return false;
}
for (auto i = capacity - 1; i != -1; i--) {
auto ch = path[i];
switch (ch) {
case '\\':
return MakeBackslashPath(path, result, capacity);
case '/':
return MakeUnivPath(path, result, capacity);
case '\0':
default:
break;
}
}
String::Copy(result, path, capacity);
return true;
}
// Convert any path string into something that can be used on the current OS.
bool MakeNativePath(const char* path, char* result, size_t capacity) {
#if defined(WHOA_SYSTEM_WIN)
return MakeWindowsPath(path, result, capacity);
#else
return MakeUnivPath(path, result, capacity);
#endif
}
// Convert a path string into something UNIX-friendly.
bool MakeUnivPath(const char* path, char* result, size_t capacity) {
size_t i = 0; // path and result index
size_t c = capacity - 1; // ceiling
while (i <= c) {
if (path[i] == '\0') {
result[i] = '\0';
return true;
}
result[i] = path[i] == '\\' ? '/' : path[i];
i++;
}
result[0] = '\0';
return false;
}
bool MakeWindowsPath(const char* path, char* result, size_t capacity) {
return MakeBackslashPath(path, result, capacity);
}
} // namespace Path
} // namespace File
} // namespace Blizzard

View file

@ -1,51 +0,0 @@
#ifndef BC_FILE_PATH_PATH_HPP
#define BC_FILE_PATH_PATH_HPP
#include "bc/file/Defines.hpp"
#include <cstddef>
namespace Blizzard {
namespace File {
namespace Path {
// Classes
// Quick native path translation on the stack.
// Can be slow in some instances, as it resorts to heap allocation if path size >= BC_FILE_MAX_PATH
// Note: this name is an invention, however its behavior is repeated in all System_File implementations.
// So it probably did exist as an inlined class.
class QuickNative {
private:
size_t size;
// stack allocation
char fastpath[BC_FILE_MAX_PATH];
// heap
char* slowpath;
public:
QuickNative(const char* path);
~QuickNative();
const char* Str();
size_t Size();
};
// Functions
void ForceTrailingSeparator(char* buf, size_t bufMax, char sep);
bool MakeBackslashPath(const char* path, char* result, size_t capacity);
bool MakeConsistentPath(const char* path, char* result, size_t capacity);
bool MakeNativePath(const char* path, char* result, size_t capacity);
bool MakeUnivPath(const char* path, char* result, size_t capacity);
bool MakeWindowsPath(const char* path, char* result, size_t capacity);
} // namespace Path
} // namespace File
} // namespace Blizzard
#endif

View file

@ -1,75 +0,0 @@
#include "bc/file/path/Posix.hpp"
#if defined(WHOA_SYSTEM_LINUX)
#include <cstring>
#include <dirent.h>
#include <alloca.h>
#include <cstdio>
#include <cstdint>
// adapted from https://github.com/OneSadCookie/fcaseopen/blob/master/fcaseopen.c
bool ResolvePosixCasePath(const char* path, char* r) {
auto l = strlen(path);
auto p = static_cast<char*>(alloca(l + 1));
strcpy(p, path);
size_t rl = 0;
DIR* d;
if (p[0] == '/') {
d = opendir("/");
p = p + 1;
} else {
d = opendir(".");
r[0] = '.';
r[1] = 0;
rl = 1;
}
int32_t last = 0;
auto c = strsep(&p, "/");
while (c) {
if (!d) {
return false;
}
if (last) {
closedir(d);
return false;
}
r[rl] = '/';
rl += 1;
r[rl] = 0;
struct dirent* e = readdir(d);
while (e) {
if (strcasecmp(c, e->d_name) == 0) {
strcpy(r + rl, e->d_name);
rl += strlen(e->d_name);
closedir(d);
d = opendir(r);
break;
}
e = readdir(d);
}
if (!e) {
strcpy(r + rl, c);
rl += strlen(c);
last = 1;
}
c = strsep(&p, "/");
}
if (d) {
closedir(d);
}
return true;
}
#endif

View file

@ -1,6 +0,0 @@
#ifndef BC_FILE_PATH_POSIX_HPP
#define BC_FILE_PATH_POSIX_HPP
bool ResolvePosixCasePath(const char* path, char* r);
#endif

View file

@ -1,75 +1,25 @@
#ifndef BC_OS_FILE_HPP #ifndef BC_OS_FILE_HPP
#define BC_OS_FILE_HPP #define BC_OS_FILE_HPP
#include "bc/file/Types.hpp" #include "bc/os/file/CloseFile.hpp"
#include "bc/os/file/CopyFile.hpp"
#include <cstdint> #include "bc/os/file/CreateDirectory.hpp"
#include "bc/os/file/CreateFile.hpp"
enum EOSFileDisposition { #include "bc/os/file/DeleteFile.hpp"
OS_CREATE_NEW = 1, #include "bc/os/file/DirectoryExists.hpp"
OS_CREATE_ALWAYS = 2, #include "bc/os/file/FileExists.hpp"
OS_OPEN_EXISTING = 3, #include "bc/os/file/FileList.hpp"
OS_OPEN_ALWAYS = 4, #include "bc/os/file/GetCurrentDirectory.hpp"
OS_TRUNCATE_EXISTING = 5 #include "bc/os/file/GetDownloadFolder.hpp"
}; #include "bc/os/file/GetFileAttributes.hpp"
#include "bc/os/file/GetFileSize.hpp"
enum EOSFileAccess { #include "bc/os/file/MoveFile.hpp"
OS_GENERIC_ALL = 0x10000000, #include "bc/os/file/ReadFile.hpp"
OS_GENERIC_EXECUTE = 0x20000000, #include "bc/os/file/RemoveDirectory.hpp"
OS_GENERIC_WRITE = 0x40000000, #include "bc/os/file/RemoveDirectoryRecurse.hpp"
OS_GENERIC_READ = 0x80000000 #include "bc/os/file/SetCurrentDirectory.hpp"
}; #include "bc/os/file/SetFileAttributes.hpp"
#include "bc/os/file/SetFilePointer.hpp"
enum EOSFileShare { #include "bc/os/file/WriteFile.hpp"
OS_FILE_SHARE_READ = 0x00000001,
OS_FILE_SHARE_WRITE = 0x00000002
};
enum EOSFileFlagsAndAttributes {
OS_FILE_ATTRIBUTE_READONLY = 0x1,
OS_FILE_ATTRIBUTE_HIDDEN = 0x2,
OS_FILE_ATTRIBUTE_SYSTEM = 0x4,
OS_FILE_ATTRIBUTE_DIRECTORY = 0x10,
OS_FILE_ATTRIBUTE_ARCHIVE = 0x20,
OS_FILE_ATTRIBUTE_NORMAL = 0x80,
OS_FILE_ATTRIBUTE_TEMPORARY = 0x100,
OS_FILE_ATTRIBUTE_OFFLINE = 0x1000,
OS_FILE_ATTRIBUTE_ENCRYPTED = 0x4000,
OS_FILE_FLAG_OPEN_NO_RECALL = 0x00100000,
OS_FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000,
OS_FILE_FLAG_POSIX_SEMANTICS = 0x01000000,
OS_FILE_FLAG_BACKUP_SEMANTICS = 0x02000000,
OS_FILE_FLAG_DELETE_ON_CLOSE = 0x04000000,
OS_FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000,
OS_FILE_FLAG_RANDOM_ACCESS = 0x10000000,
OS_FILE_FLAG_NO_BUFFERING = 0x20000000,
OS_FILE_FLAG_OVERLAPPED = 0x40000000,
OS_FILE_FLAG_WRITE_THROUGH = 0x80000000
};
typedef Blizzard::File::StreamRecord* HOSFILE;
constexpr HOSFILE HOSFILE_INVALID = nullptr;
HOSFILE OsCreateFile(const char* fileName, uint32_t desiredAccess, uint32_t shareMode, uint32_t createDisposition, uint32_t flagsAndAttributes, uint32_t extendedFileType);
int32_t OsSetFileAttributes(const char* fileName, uint32_t attributes);
uint64_t OsGetFileSize(HOSFILE fileHandle);
int32_t OsWriteFile(HOSFILE fileHandle, void* buffer, size_t bytesToWrite, size_t* bytesWritten);
int32_t OsReadFile(HOSFILE fileHandle, void* buffer, size_t bytesToRead, size_t* bytesRead);
void OsCloseFile(HOSFILE fileHandle);
int64_t OsSetFilePointer(HOSFILE fileHandle, int64_t distanceToMove, uint32_t moveMethod);
int32_t OsSetCurrentDirectory(const char* pathName);
int32_t OsGetCurrentDirectory(size_t pathLen, char* pathName);
int32_t OsCreateDirectory(const char* pathName, int32_t recursive);
#endif #endif

6
bc/os/file/CloseFile.cpp Normal file
View file

@ -0,0 +1,6 @@
#include "bc/os/file/CloseFile.hpp"
#include "bc/file/Close.hpp"
void OsCloseFile(HOSFILE fileHandle) {
Blizzard::File::Close(reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle));
}

8
bc/os/file/CloseFile.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_CLOSE_FILE_HPP
#define BC_OS_FILE_CLOSE_FILE_HPP
#include "bc/os/file/Types.hpp"
void OsCloseFile(HOSFILE fileHandle);
#endif

12
bc/os/file/CopyFile.cpp Normal file
View file

@ -0,0 +1,12 @@
#include "bc/os/file/CopyFile.hpp"
#include "bc/os/file/Defines.hpp"
#include "bc/file/Copy.hpp"
int32_t OsCopyFile(const char* existingFileName, const char* newFileName, int32_t failIfExists) {
if (!existingFileName || !newFileName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::Copy(existingFileName, newFileName, failIfExists == 0);
}

8
bc/os/file/CopyFile.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_COPY_FILE_HPP
#define BC_OS_FILE_COPY_FILE_HPP
#include <cstdint>
int32_t OsCopyFile(const char* existingFileName, const char* newFileName, int32_t failIfExists);
#endif

View file

@ -0,0 +1,12 @@
#include "bc/os/file/CreateDirectory.hpp"
#include "bc/file/CreateDirectory.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsCreateDirectory(const char* pathName, int32_t recursive) {
if (pathName == nullptr) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::CreateDirectory(pathName, recursive != 0);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_CREATE_DIRECTORY_HPP
#define BC_OS_FILE_CREATE_DIRECTORY_HPP
#include <cstdint>
int32_t OsCreateDirectory(const char* pathName, int32_t recursive);
#endif

67
bc/os/file/CreateFile.cpp Normal file
View file

@ -0,0 +1,67 @@
#include "bc/os/file/CreateFile.hpp"
#include "bc/os/file/SetFileAttributes.hpp"
#include "bc/Debug.hpp"
#include "bc/file/Open.hpp"
#include "bc/os/file/Types.hpp"
int32_t OsCreateFileMode(uint32_t desiredAccess, uint32_t shareMode, uint32_t createDisposition) {
using Mode = Blizzard::File::Mode;
int32_t mode;
if (desiredAccess & OS_GENERIC_READ) {
mode |= Mode::read;
}
if (desiredAccess & OS_GENERIC_WRITE) {
mode |= Mode::write;
}
if (shareMode & OS_FILE_SHARE_READ) {
mode |= Mode::shareread;
}
if (shareMode & OS_FILE_SHARE_WRITE) {
mode |= Mode::sharewrite;
}
switch (createDisposition) {
case OS_CREATE_NEW:
// mode |= 0xC00;
mode |= (Mode::create|Mode::mustnotexist);
break;
case OS_CREATE_ALWAYS:
// mode |= 0x400;
mode |= Mode::create;
break;
case OS_OPEN_EXISTING:
// mode |= 0x1000
mode |= Mode::mustexist;
break;
case OS_OPEN_ALWAYS:
// mode |= 0x200;
mode |= Mode::append;
break;
case OS_TRUNCATE_EXISTING:
// mode |= 0x100;
mode |= Mode::truncate;
break;
}
return mode;
}
HOSFILE OsCreateFile(const char* fileName, uint32_t desiredAccess, uint32_t shareMode, uint32_t createDisposition, uint32_t flagsAndAttributes, uint32_t extendedFileType) {
BLIZZARD_VALIDATE(fileName, "invalid filename", HOSFILE_INVALID);
BLIZZARD_VALIDATE(desiredAccess != 0, "invalid desired access", HOSFILE_INVALID);
BLIZZARD_VALIDATE(createDisposition <= OS_TRUNCATE_EXISTING, "invalid create disposition", HOSFILE_INVALID);
Blizzard::File::StreamRecord* file;
if (!Blizzard::File::Open(fileName, OsCreateFileMode(desiredAccess, shareMode, createDisposition), file)) {
return HOSFILE_INVALID;
}
if ((flagsAndAttributes & OS_FILE_ATTRIBUTE_NORMAL) == 0) {
OsSetFileAttributes(fileName, flagsAndAttributes);
}
return reinterpret_cast<HOSFILE>(file);
}

10
bc/os/file/CreateFile.hpp Normal file
View file

@ -0,0 +1,10 @@
#ifndef BC_OS_FILE_CREATE_FILE_HPP
#define BC_OS_FILE_CREATE_FILE_HPP
#include <cstdint>
#include "bc/os/file/Types.hpp"
HOSFILE OsCreateFile(const char* fileName, uint32_t desiredAccess, uint32_t shareMode, uint32_t createDisposition, uint32_t flagsAndAttributes, uint32_t extendedFileType);
#endif

10
bc/os/file/Defines.hpp Normal file
View file

@ -0,0 +1,10 @@
#ifndef BC_OS_FILE_DEFINES_HPP
#define BC_OS_FILE_DEFINES_HPP
#define OS_FILE_ERROR_INVALID_PARAMETER 0x57
#include "bc/file/Error.hpp"
#define OS_FILE_SET_LAST_ERROR(err) ::Blizzard::File::SetLastError(err)
#endif

12
bc/os/file/DeleteFile.cpp Normal file
View file

@ -0,0 +1,12 @@
#include "bc/os/file/DeleteFile.hpp"
#include "bc/os/file/Defines.hpp"
#include "bc/file/Delete.hpp"
int32_t OsDeleteFile(const char* fileName) {
if (!fileName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::Delete(fileName);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_DELETE_FILE_HPP
#define BC_OS_FILE_DELETE_FILE_HPP
#include <cstdint>
int32_t OsDeleteFile(const char* fileName);
#endif

View file

@ -0,0 +1,6 @@
#include "bc/os/file/DirectoryExists.hpp"
#include "bc/file/Exists.hpp"
int32_t OsDirectoryExists(const char* dirName) {
return Blizzard::File::IsDirectory(dirName);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_DIRECTORY_EXISTS_HPP
#define BC_OS_FILE_DIRECTORY_EXISTS_HPP
#include <cstdint>
int32_t OsDirectoryExists(const char* dirName);
#endif

View file

@ -0,0 +1,6 @@
#include "bc/os/file/FileExists.hpp"
#include "bc/file/Exists.hpp"
int32_t OsFileExists(const char* path) {
return Blizzard::File::IsFile(path);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_FILE_EXISTS_HPP
#define BC_OS_FILE_FILE_EXISTS_HPP
#include <cstdint>
int32_t OsFileExists(const char* path);
#endif

73
bc/os/file/FileList.cpp Normal file
View file

@ -0,0 +1,73 @@
#include "bc/os/file/FileList.hpp"
#include "bc/file/Defines.hpp"
#include "bc/file/GetFileInfo.hpp"
#include "bc/file/MakeAbsolutePath.hpp"
#include "bc/file/ProcessDirFast.hpp"
#include "bc/file/SimpleGlob.hpp"
#include "bc/file/Types.hpp"
#include "bc/string/Copy.hpp"
#include "bc/string/Path.hpp"
int32_t OsFileList(const char* dir, const char* pattern, OsFileListCallback callback, void* param, int32_t flags) {
class Internal {
public:
struct FileListParms {
OsFileListCallback callback;
void* param;
uint32_t flags;
const char* pattern;
};
static bool Callback(const Blizzard::File::ProcessDirParms& parms) {
char path[260];
OS_FILE_DATA data;
Blizzard::String::Copy(data.fileName, parms.item, sizeof(data.fileName));
Blizzard::String::JoinPath(path, sizeof(path), parms.dir, parms.item);
auto list = static_cast<FileListParms*>(parms.param);
if (Blizzard::File::SimpleGlob(parms.item, list->pattern)) {
Blizzard::File::FileInfo info;
if (Blizzard::File::GetFileInfo(path, &info)) {
// TODO: consider making this 64 bits
data.size = static_cast<uint32_t>(info.size);
data.flags = 0;
if (info.attributes & BC_FILE_ATTRIBUTE_DIRECTORY) {
data.flags |= 0x10;
}
if (info.attributes & BC_FILE_ATTRIBUTE_READONLY) {
data.flags |= 0x01;
}
if (info.attributes & BC_FILE_ATTRIBUTE_HIDDEN) {
data.flags |= 0x02;
}
if (list->flags && ((info.attributes & BC_FILE_ATTRIBUTE_HIDDEN) == 0)) {
if (list->callback(data, list->param)) {
return false;
}
}
}
}
return true;
}
};
char finddir[260];
char findpath[260];
Blizzard::String::Copy(finddir, dir, 260);
if (!Blizzard::File::MakeAbsolutePath(finddir, findpath, 260, false)) {
return false;
}
Internal::FileListParms parms;
parms.param = param;
parms.flags = flags;
parms.callback = callback;
parms.pattern = pattern;
return Blizzard::File::ProcessDirFast(findpath, static_cast<void*>(&parms), Internal::Callback, false);
}

17
bc/os/file/FileList.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef BC_OS_FILE_FILE_LIST_HPP
#define BC_OS_FILE_FILE_LIST_HPP
#include <cstdint>
class OS_FILE_DATA {
public:
uint32_t size;
uint32_t flags;
char fileName[260];
};
typedef int32_t (*OsFileListCallback)(const OS_FILE_DATA& data, void* param);
int32_t OsFileList(const char* dir, const char* pattern, OsFileListCallback callback, void* param, int32_t flags);
#endif

View file

@ -0,0 +1,12 @@
#include "bc/os/file/GetCurrentDirectory.hpp"
#include "bc/file/GetWorkingDirectory.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsGetCurrentDirectory(uint32_t buffersize, char* buffer) {
if (!buffer) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::GetWorkingDirectory(buffer, buffersize);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_GET_CURRENT_DIRECTORY_HPP
#define BC_OS_FILE_GET_CURRENT_DIRECTORY_HPP
#include <cstdint>
int32_t OsGetCurrentDirectory(uint32_t buffersize, char* buffer);
#endif

View file

@ -0,0 +1,10 @@
#include "bc/os/file/GetDownloadFolder.hpp"
#include "bc/file/GetWorkingDirectory.hpp"
const char* OsFileGetDownloadFolder() {
static char s_downloadfolder[260] = { 0 };
if (s_downloadfolder[0] == '\0') {
Blizzard::File::GetWorkingDirectory(s_downloadfolder, 260);
}
return s_downloadfolder;
}

View file

@ -0,0 +1,6 @@
#ifndef BC_OS_FILE_GET_DOWNLOAD_FOLDER_HPP
#define BC_OS_FILE_GET_DOWNLOAD_FOLDER_HPP
const char* OsFileGetDownloadFolder();
#endif

View file

@ -0,0 +1,17 @@
#include "bc/os/file/GetFileAttributes.hpp"
#include "bc/file/GetFileInfo.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsGetFileAttributes(const char* fileName) {
if (!fileName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
Blizzard::File::FileInfo info;
if (!Blizzard::File::GetFileInfo(fileName, &info)) {
return -1;
}
return info.attributes;
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_GET_FILE_ATTRIBUTES_HPP
#define BC_OS_FILE_GET_FILE_ATTRIBUTES_HPP
#include <cstdint>
int32_t OsGetFileAttributes(const char* fileName);
#endif

View file

@ -0,0 +1,8 @@
#include "bc/os/file/GetFileSize.hpp"
#include "bc/file/GetFileInfo.hpp"
#include <limits>
uint64_t OsGetFileSize(HOSFILE fileHandle) {
auto info = Blizzard::File::GetFileInfo(reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle));
return info ? info->size : std::numeric_limits<uint64_t>::max();
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_GET_FILE_SIZE_HPP
#define BC_OS_FILE_GET_FILE_SIZE_HPP
#include "bc/os/file/Types.hpp"
uint64_t OsGetFileSize(HOSFILE fileHandle);
#endif

12
bc/os/file/MoveFile.cpp Normal file
View file

@ -0,0 +1,12 @@
#include "bc/os/file/MoveFile.hpp"
#include "bc/os/file/Defines.hpp"
#include "bc/file/Move.hpp"
int32_t OsMoveFile(const char* existingFileName, const char* newFileName) {
if (!existingFileName || !newFileName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::Move(existingFileName, newFileName);
}

8
bc/os/file/MoveFile.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_MOVE_FILE_HPP
#define BC_OS_FILE_MOVE_FILE_HPP
#include <cstdint>
int32_t OsMoveFile(const char* existingFileName, const char* newFileName);
#endif

13
bc/os/file/ReadFile.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "bc/os/file/ReadFile.hpp"
#include "bc/os/file/Defines.hpp"
#include "bc/file/Read.hpp"
int32_t OsReadFile(HOSFILE fileHandle, void* buffer, uint32_t bytesToRead, uint32_t* bytesRead) {
if (!buffer || !bytesRead) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
*bytesRead = bytesToRead;
return Blizzard::File::Read(reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle), buffer, reinterpret_cast<int32_t*>(bytesRead));
}

9
bc/os/file/ReadFile.hpp Normal file
View file

@ -0,0 +1,9 @@
#ifndef BC_OS_FILE_READ_FILE_HPP
#define BC_OS_FILE_READ_FILE_HPP
#include "bc/os/file/Types.hpp"
#include <cstdint>
int32_t OsReadFile(HOSFILE fileHandle, void* buffer, uint32_t bytesToRead, uint32_t* bytesRead);
#endif

View file

@ -0,0 +1,12 @@
#include "bc/os/file/RemoveDirectory.hpp"
#include "bc/file/RemoveDirectory.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsRemoveDirectory(const char* pathName) {
if (!pathName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::RemoveDirectory(pathName);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_REMOVE_DIRECTORY_HPP
#define BC_OS_FILE_REMOVE_DIRECTORY_HPP
#include <cstdint>
int32_t OsRemoveDirectory(const char* pathName);
#endif

View file

@ -0,0 +1,12 @@
#include "bc/os/file/RemoveDirectoryRecurse.hpp"
#include "bc/file/RemoveDirectory.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsRemoveDirectoryRecurse(const char* pathName, uint32_t flags) {
if (!pathName) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::RemoveDirectoryAndContents(pathName, (flags & 0x1) != 0);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_REMOVE_DIRECTORY_HPP
#define BC_OS_FILE_REMOVE_DIRECTORY_HPP
#include <cstdint>
int32_t OsRemoveDirectoryRecurse(const char* pathName, uint32_t flags);
#endif

View file

@ -0,0 +1,13 @@
#include "bc/os/file/SetCurrentDirectory.hpp"
#include "bc/os/file/Defines.hpp"
#include "bc/file/SetWorkingDirectory.hpp"
int32_t OsSetCurrentDirectory(const char* pathName) {
if (pathName == nullptr) {
// SetLastError(0x57);
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::SetWorkingDirectory(pathName);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_SET_CURRENT_DIRECTORY_HPP
#define BC_OS_FILE_SET_CURRENT_DIRECTORY_HPP
#include <cstdint>
int32_t OsSetCurrentDirectory(const char* pathName);
#endif

View file

@ -0,0 +1,13 @@
#include "bc/os/file/SetFileAttributes.hpp"
#include "bc/file/SetAttributes.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsSetFileAttributes(const char* fileName, uint32_t attributes) {
if (!fileName) {
// SetLastError(0x57);
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
return Blizzard::File::SetAttributes(fileName, attributes);
}

View file

@ -0,0 +1,8 @@
#ifndef BC_OS_FILE_SET_FILE_ATTRIBUTES_HPP
#define BC_OS_FILE_SET_FILE_ATTRIBUTES_HPP
#include <cstdint>
int32_t OsSetFileAttributes(const char* fileName, uint32_t attributes);
#endif

View file

@ -0,0 +1,28 @@
#include "bc/os/file/SetFilePointer.hpp"
#include "bc/Debug.hpp"
#include "bc/file/GetPos.hpp"
#include "bc/file/SetPos.hpp"
#include "bc/file/Defines.hpp"
int64_t OsSetFilePointer(HOSFILE fileHandle, int64_t distanceToMove, uint32_t moveMethod) {
BLIZZARD_ASSERT(moveMethod <= 2);
auto file = reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle);
int64_t offset;
if (moveMethod != 0 && !Blizzard::File::GetPos(file, offset)) {
return -1LL;
}
uint32_t whence[] = {
BC_FILE_SEEK_START,
BC_FILE_SEEK_CURRENT,
BC_FILE_SEEK_END
};
if (!Blizzard::File::SetPos(file, offset, whence[moveMethod])) {
return -1LL;
}
return offset + distanceToMove;
}

View file

@ -0,0 +1,9 @@
#ifndef BC_OS_FILE_SET_FILE_POINTER_HPP
#define BC_OS_FILE_SET_FILE_POINTER_HPP
#include <cstdint>
#include "bc/os/file/Types.hpp"
int64_t OsSetFilePointer(HOSFILE fileHandle, int64_t distanceToMove, uint32_t moveMethod);
#endif

40
bc/os/file/Types.hpp Normal file
View file

@ -0,0 +1,40 @@
#ifndef BC_OS_FILE_TYPES_HPP
#define BC_OS_FILE_TYPES_HPP
#include <cstdint>
#define OS_FILE_ATTRIBUTE_NORMAL 0x80
// this is passed into last argument of OsCreateFile
#define OS_FILE_TYPE_DEFAULT 0x3F3F3F3F
enum EOSFileDisposition {
OS_CREATE_NEW = 1,
OS_CREATE_ALWAYS = 2,
OS_OPEN_EXISTING = 3,
OS_OPEN_ALWAYS = 4,
OS_TRUNCATE_EXISTING = 5
};
enum EOSFileAccess {
OS_GENERIC_ALL = 0x10000000,
OS_GENERIC_EXECUTE = 0x20000000,
OS_GENERIC_WRITE = 0x40000000,
OS_GENERIC_READ = 0x80000000
};
enum EOSFileShare {
OS_FILE_SHARE_READ = 0x00000001,
OS_FILE_SHARE_WRITE = 0x00000002
};
// TODO: generate a proper handle here
struct HOSFILE__ {
int32_t unused;
};
typedef HOSFILE__* HOSFILE;
constexpr HOSFILE HOSFILE_INVALID = nullptr;
#endif

13
bc/os/file/WriteFile.cpp Normal file
View file

@ -0,0 +1,13 @@
#include "bc/os/file/WriteFile.hpp"
#include "bc/file/Write.hpp"
#include "bc/os/file/Defines.hpp"
int32_t OsWriteFile(HOSFILE fileHandle, void* buffer, uint32_t bytesToWrite, uint32_t* bytesWritten) {
if (!buffer || !bytesWritten) {
OS_FILE_SET_LAST_ERROR(OS_FILE_ERROR_INVALID_PARAMETER);
return 0;
}
*bytesWritten = bytesToWrite;
return Blizzard::File::Write(reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle), buffer, reinterpret_cast<int32_t*>(bytesWritten));
}

9
bc/os/file/WriteFile.hpp Normal file
View file

@ -0,0 +1,9 @@
#ifndef BC_OS_FILE_WRITE_FILE_HPP
#define BC_OS_FILE_WRITE_FILE_HPP
#include "bc/os/file/Types.hpp"
#include <cstdint>
int32_t OsWriteFile(HOSFILE fileHandle, void* buffer, uint32_t bytesToWrite, uint32_t* bytesWritten);
#endif

View file

@ -1,13 +1,14 @@
#ifndef BC_FILE_SYSTEM_DEFINES_HPP #ifndef BC_SYSTEM_FILE_DEFINES_HPP
#define BC_FILE_SYSTEM_DEFINES_HPP #define BC_SYSTEM_FILE_DEFINES_HPP
// Constants // how much data to buffer when copying with File::Copy
#define BC_SYSTEM_FILE_COPYBUFFER_SIZE 0xA00000LL
// How much data to buffer when copying with File::Copy // this bit field controls which file information is set by SetFileInfo
#define BC_FILE_SYSTEM_COPYBUFFER_SIZE 0xA00000UL #define BC_SYSTEM_FILE_INFO_UNK_0 0x01
#define BC_SYSTEM_FILE_INFO_UNK_1 0x02
// Utility macros #define BC_SYSTEM_FILE_INFO_ATTRIBUTES 0x04
#define BC_SYSTEM_FILE_INFO_UNK_3 0x08
#define BC_FILE_PATH(localname) char localname[BC_FILE_MAX_PATH] = {0} #define BC_SYSTEM_FILE_INFO_TIMES 0x10
#endif #endif

View file

@ -5,105 +5,104 @@
#include "bc/String.hpp" #include "bc/String.hpp"
#include "bc/Memory.hpp" #include "bc/Memory.hpp"
namespace Blizzard {
namespace System_File { namespace System_File {
namespace Stacked { namespace Stacked {
bool null_cd(File::Filesystem* fs, FileParms* parms) { bool null_cd(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_close(File::Filesystem* fs, FileParms* parms) { bool null_close(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_create(File::Filesystem* fs, FileParms* parms) { bool null_create(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_cwd(File::Filesystem* fs, FileParms* parms) { bool null_cwd(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_dirwalk(File::Filesystem* fs, FileParms* parms) { bool null_dirwalk(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_exists(File::Filesystem* fs, FileParms* parms) { bool null_exists(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_flush(File::Filesystem* fs, FileParms* parms) { bool null_flush(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_getfileinfo(File::Filesystem* fs, FileParms* parms) { bool null_getfileinfo(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_getfreespace(File::Filesystem* fs, FileParms* parms) { bool null_getfreespace(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_getpos(File::Filesystem* fs, FileParms* parms) { bool null_getpos(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_getrootchars(File::Filesystem* fs, FileParms* parms) { bool null_getrootchars(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_isabspath(File::Filesystem* fs, FileParms* parms) { bool null_isabspath(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_isreadonly(File::Filesystem* fs, FileParms* parms) { bool null_isreadonly(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_makeabspath(File::Filesystem* fs, FileParms* parms) { bool null_makeabspath(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_mkdir(File::Filesystem* fs, FileParms* parms) { bool null_mkdir(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_move(File::Filesystem* fs, FileParms* parms) { bool null_move(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_copy(File::Filesystem* fs, FileParms* parms) { bool null_copy(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_open(File::Filesystem* fs, FileParms* parms) { bool null_open(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_read(File::Filesystem* fs, FileParms* parms) { bool null_read(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_readp(File::Filesystem* fs, FileParms* parms) { bool null_readp(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_rmdir(File::Filesystem* fs, FileParms* parms) { bool null_rmdir(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_setcachemode(File::Filesystem* fs, FileParms* parms) { bool null_setcachemode(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_seteof(File::Filesystem* fs, FileParms* parms) { bool null_seteof(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_setfileinfo(File::Filesystem* fs, FileParms* parms) { bool null_setfileinfo(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_setpos(File::Filesystem* fs, FileParms* parms) { bool null_setpos(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_unlink(File::Filesystem* fs, FileParms* parms) { bool null_unlink(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_write(File::Filesystem* fs, FileParms* parms) { bool null_write(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_writep(File::Filesystem* fs, FileParms* parms) { bool null_writep(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
bool null_shutdown(File::Filesystem* fs, FileParms* parms) { bool null_shutdown(Blizzard::File::Filesystem* fs, FileParms* parms) {
return false; return false;
} }
// Null stack: this stack does absolutely nothing. Its only purpose is to store fallback functions. // null stack: does absolutely nothing
static File::Filesystem s_nullstack = { // only purpose is to store fallback functions
static Blizzard::File::Filesystem s_nullstack = {
&s_nullstack, &s_nullstack,
nullptr, nullptr,
{
null_cd, null_cd,
null_close, null_close,
null_create, null_create,
@ -133,16 +132,14 @@ static File::Filesystem s_nullstack = {
null_write, null_write,
null_writep, null_writep,
null_shutdown null_shutdown
}
}; };
// Base stack: this stack contains the base System_File functions. // base stack: contains the base System_File functions.
static File::Filesystem s_basestack = { static Blizzard::File::Filesystem s_basestack = {
&s_basestack, &s_basestack,
nullptr, nullptr,
{
System_File::SetWorkingDirectory, System_File::SetWorkingDirectory,
System_File::Close, System_File::Close,
System_File::Create, System_File::Create,
@ -172,16 +169,14 @@ static File::Filesystem s_basestack = {
System_File::Write, System_File::Write,
System_File::WriteP, System_File::WriteP,
System_File::Shutdown System_File::Shutdown
}
}; };
// File initialization stack: this is the default // File initialization stack: this is the default
static File::Filesystem s_fileinit = { static Blizzard::File::Filesystem s_fileinit = {
&s_fileinit, &s_fileinit,
nullptr, nullptr,
{
file_init, file_init,
file_init, file_init,
file_init, file_init,
@ -211,81 +206,90 @@ static File::Filesystem s_fileinit = {
file_init, file_init,
file_init, file_init,
file_init file_init
}
}; };
// Manager will be initialized upon first use // manager will be initialized upon first use
static File::Filesystem* s_manager = &s_fileinit; Blizzard::File::Filesystem* s_manager = &s_fileinit;
// Manager getter // push a Filesystem onto the stack
File::Filesystem* Manager() { void Push(Blizzard::File::Filesystem* fs) {
return s_manager; auto head = reinterpret_cast<Blizzard::File::Filesystem*>(Blizzard::Memory::Allocate(sizeof(Blizzard::File::Filesystem)));
} Blizzard::String::MemFill(head, sizeof(Blizzard::File::Filesystem), 0);
Blizzard::String::MemCopy(head, fs, sizeof(Blizzard::File::Filesystem));
// Push a filesystem stack to manager linked list head->next = s_manager;
void Push(File::Filesystem* fs) { s_manager = head;
auto stack = reinterpret_cast<File::Filesystem*>(Memory::Allocate(sizeof(File::Filesystem)));
String::MemFill(stack, sizeof(File::Filesystem), 0);
// Add stack
String::MemCopy(stack, fs, sizeof(File::Filesystem));
stack->next = s_manager;
s_manager = stack;
HoistAll(); HoistAll();
} }
// file_init is part of the default filesystem stack // file_init is part of the default filesystem stack
// The first use of s_manager will call this function only once; it is a fallback function in case s_basestack's funcs are not yet hoisted. // the first use of s_manager will call this function only once; it is a fallback function in case s_basestack's funcs are not yet hoisted.
bool file_init(File::Filesystem* fs, FileParms* parms) { bool file_init(Blizzard::File::Filesystem* fs, FileParms* parms) {
// Allocate a null stack, replacing what was previously a pointer to s_fileinit // allocate a null stack, replacing what was previously a pointer to s_fileinit
s_manager = reinterpret_cast<File::Filesystem*>(Memory::Allocate(sizeof(File::Filesystem))); s_manager = reinterpret_cast<Blizzard::File::Filesystem*>(Blizzard::Memory::Allocate(sizeof(Blizzard::File::Filesystem)));
if (s_manager == nullptr) { if (s_manager == nullptr) {
return false; return false;
} }
// Add null fs calls to stack // add null fs calls to stack
// After Push/HoistAll, if a filesystem call is unimplemented, the func from s_nullstack gets called instead. // after Push/HoistAll, if a filesystem call is unimplemented, the func from s_nullstack gets called instead.
String::MemCopy(s_manager, &s_nullstack, sizeof(File::Filesystem)); Blizzard::String::MemCopy(s_manager, &s_nullstack, sizeof(Blizzard::File::Filesystem));
// Hoist basic file functions // add basic file functions
Push(&s_basestack); Push(&s_basestack);
// fs manager is now ready to use! if (s_manager == nullptr) {
// Execute the original call.
if (s_manager != nullptr) {
auto func = *reinterpret_cast<File::Filesystem::CallFunc*>(reinterpret_cast<uintptr_t>(s_manager) + parms->offset);
return func(fs, parms);
}
return false; return false;
} }
// Ensures that the filesystem manager will always have a corresponding function address for enum Call call. // do the original operation
void Hoist(uint32_t call) { auto op = *reinterpret_cast<Blizzard::File::Operation*>(reinterpret_cast<uintptr_t>(s_manager) + parms->op);
if (s_manager->funcs[call] == nullptr) { return op(fs, parms);
auto topStack = s_manager;
auto prev = s_manager;
auto next = s_manager->next;
while (next && topStack->funcs[call] == nullptr) {
topStack->funcs[call] = next->funcs[call];
prev = next;
next = next->next;
}
// Remove call from lower stack
prev->funcs[call] = nullptr;
}
} }
// Hoist all functions in the filesystem stack to the top, i.e. the manager // Hoist all functions in the filesystem stack to the top, i.e. the manager
void HoistAll() { void HoistAll() {
for (uint32_t call = 0; call < File::Filesystem::s_numCalls; call++) { #define HOIST_OP(op) if (s_manager->op == nullptr) { \
Hoist(call); auto cur = s_manager; \
while (cur->next) { \
cur->op = cur->next->op; \
cur = cur->next; \
} \
} }
HOIST_OP(cd);
HOIST_OP(close);
HOIST_OP(create);
HOIST_OP(cwd);
HOIST_OP(dirwalk);
HOIST_OP(exists);
HOIST_OP(flush);
HOIST_OP(getfileinfo);
HOIST_OP(getfreespace);
HOIST_OP(getpos);
HOIST_OP(getrootchars);
HOIST_OP(isabspath);
HOIST_OP(isreadonly);
HOIST_OP(makeabspath);
HOIST_OP(mkdir);
HOIST_OP(move);
HOIST_OP(copy);
HOIST_OP(open);
HOIST_OP(read);
HOIST_OP(readp);
HOIST_OP(rmdir);
HOIST_OP(setcachemode);
HOIST_OP(seteof);
HOIST_OP(setfileinfo);
HOIST_OP(setpos);
HOIST_OP(unlink);
HOIST_OP(write);
HOIST_OP(writep);
HOIST_OP(shutdown);
#undef HOIST_OP
} }
} // namespace Stacked } // namespace Stacked
} // namespace System_File } // namespace System_File
} // namespace Blizzard

View file

@ -3,83 +3,54 @@
#include "bc/file/Types.hpp" #include "bc/file/Types.hpp"
#include "bc/file/Filesystem.hpp" #include "bc/file/Filesystem.hpp"
#include "bc/file/File.hpp"
#include "bc/system/file/System_File.hpp" #include "bc/system/file/System_File.hpp"
#include <cstdint> #include <cstdint>
namespace Blizzard {
namespace System_File { namespace System_File {
namespace Stacked { namespace Stacked {
extern Blizzard::File::Filesystem* s_manager;
// Functions // Functions
bool Open(FileParms* parms); bool file_init(Blizzard::File::Filesystem* fs, FileParms* parms);
bool file_init(File::Filesystem* fs, FileParms* parms);
File::Filesystem* Manager();
void HoistAll(); void HoistAll();
void Push(File::Filesystem* fs); void Push(Blizzard::File::Filesystem* fs);
// Stacked file functions // Stacked file functions
bool SetWorkingDirectory(FileParms* parms); bool (SetWorkingDirectory)(FileParms* parms);
bool (Close)(FileParms* parms);
bool Close(FileParms* parms); bool (Create)(FileParms* parms);
bool (GetWorkingDirectory)(FileParms* parms);
bool GetWorkingDirectory(FileParms* parms); bool (ProcessDirFast)(FileParms* parms);
bool (Exists)(FileParms* parms);
bool ProcessDirFast(FileParms* parms); bool (Flush)(FileParms* parms);
bool (GetFileInfo)(FileParms* parms);
bool Exists(FileParms* parms); bool (GetFreeSpace)(FileParms* parms);
bool (GetPos)(FileParms* parms);
bool Flush(FileParms* parms); bool (GetRootChars)(FileParms* parms);
bool (IsAbsolutePath)(FileParms* parms);
bool GetFileInfo(FileParms* parms); bool (IsReadOnly)(FileParms* parms);
bool (MakeAbsolutePath)(FileParms* parms);
bool GetFreeSpace(FileParms* parms); bool (CreateDirectory)(FileParms* parms);
bool (Move)(FileParms* parms);
bool GetPos(FileParms* parms); bool (Copy)(FileParms* parms);
bool (Open)(FileParms* parms);
bool GetRootChars(FileParms* parms); bool (Read)(FileParms* parms);
bool (ReadP)(FileParms* parms);
bool IsAbsolutePath(FileParms* parms); bool (RemoveDirectory)(FileParms* parms);
bool (SetCacheMode)(FileParms* parms);
bool IsReadOnly(FileParms* parms); bool (SetEOF)(FileParms* parms);
bool (SetAttributes)(FileParms* parms);
bool MakeAbsolutePath(FileParms* parms); bool (SetPos)(FileParms* parms);
bool (Delete)(FileParms* parms);
bool CreateDirectory(FileParms* parms); bool (Write)(FileParms* parms);
bool (WriteP)(FileParms* parms);
bool Move(FileParms* parms); bool (Shutdown)(FileParms* parms);
bool Copy(FileParms* parms);
bool Open(FileParms* parms);
bool Read(FileParms* parms);
bool ReadP(FileParms* parms);
bool RemoveDirectory(FileParms* parms);
bool SetCacheMode(FileParms* parms);
bool SetEOF(FileParms* parms);
bool SetAttributes(FileParms* parms);
bool SetPos(FileParms* parms);
bool Delete(FileParms* parms);
bool Write(FileParms* parms);
bool WriteP(FileParms* parms);
} // namespace Stacked } // namespace Stacked
} // namespace System_File } // namespace System_File
} // namespace Blizzard
#endif #endif

Some files were not shown because too many files have changed in this diff Show more