Files
amxmodx/amxmodx/file.cpp
Arkshine 52c73126e1 VFS: Fix various things
- The "ALL" fake pathID is replaced by what does SM, having a public var NULL_STRING which will acts as NULL when needed.
  To make compiler accepting public array, this patch was needed: https://hg.alliedmods.net/sourcemod-central/rev/b12f329def09
- The offset thing in read_dir: considering that's something very specific to this native and that implementation in CDirectory doesn't make sense because of the offset compatibility for windows, all code is now in the native.
2015-03-25 13:50:07 +01:00

1235 lines
24 KiB
C++
Executable File

// vim: set ts=4 sw=4 tw=99 noet:
//
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
// Copyright (C) The AMX Mod X Development Team.
//
// This software is licensed under the GNU General Public License, version 3 or higher.
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
// https://alliedmods.net/amxmodx-license
#include "amxmodx.h"
#include "CFileSystem.h"
#include "CLibrarySys.h"
using namespace ke;
// native read_dir(const dirname[], pos, output[], len, &outlen = 0);
static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
const char* realpath = build_pathname("%s", path);
AutoPtr<CDirectory> dir(g_LibSys.OpenDirectory(realpath));
if (!dir)
{
return 0;
}
cell offset = Max(0, params[2]);
if (offset >= 0)
{
#if defined PLATFORM_WINDOWS
// Should be declared after so entry starts to '.' and not '..'
// But old code did that, so keep this for compatibility.
++offset;
for (cell i = 0; i < offset && dir->MoreFiles(); ++i)
{
dir->NextEntry();
}
#elif defined PLATFORM_POSIX
seekdir(dir->GetHandle(), offset);
dir->NextEntry();
if (dir->IsValid())
{
offset = telldir(dir->GetHandle());
}
#endif
}
if (!dir->IsValid())
{
return 0;
}
const char* entry = dir->GetEntryName();
cell* outputLen = get_amxaddr(amx, params[5]);
*outputLen = set_amxstring_utf8(amx, params[3], entry, strlen(entry), params[4] + 1);
return offset;
}
// native read_file(const file[], line, text[], len, &txtlen = 0);
static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
const char* realpath = build_pathname("%s", path);
AutoPtr<SystemFile> fp(SystemFile::Open(realpath, "r"));
if (!fp)
{
LogError(amx, AMX_ERR_NATIVE, "Couldn't read file \"%s\"", path);
return 0;
}
static char buffer[2048];
size_t currentLine = 0;
size_t targetLine = Max(0, params[2]);
while (currentLine <= targetLine && fp->ReadLine(buffer, sizeof(buffer) - 1))
{
++currentLine;
}
if (currentLine > targetLine)
{
length = strlen(buffer);
if (buffer[length - 1] == '\n')
buffer[--length] = '\0';
if (buffer[length - 1] == '\r')
buffer[--length] = '\0';
cell* textLen = get_amxaddr(amx, params[5]);
*textLen = set_amxstring_utf8(amx, params[3], buffer, length, params[4] + 1); // + EOS
return currentLine;
}
return 0;
}
// native write_file(const file[], const text[], line = -1);
static cell AMX_NATIVE_CALL write_file(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
const char* text = get_amxstring(amx, params[2], 1, length);
int targetLine = params[3];
const char* realpath = build_pathname("%s", path);
AutoPtr<SystemFile>fp;
if (targetLine < 0)
{
if (!(fp = SystemFile::Open(realpath, "a")))
{
LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath);
return 0;
}
fp->Write(text, length);
fp->Write("\n", 1);
return 1;
}
if (!(fp = SystemFile::Open(realpath, "r")))
{
if (!(fp = SystemFile::Open(realpath, "w")))
{
LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath);
return 0;
}
for (int i = 0; i < targetLine; ++i)
{
fp->Write("\n", 1);
}
fp->Write(text, length);
fp->Write("\n", 1);
return 1;
}
SystemFile fptemp(tmpfile());
if (!fptemp.handle())
{
LogError(amx, AMX_ERR_NATIVE, "Couldn't create temp file");
return 0;
}
static char buffer[2048];
for (int i = 0;; ++i)
{
if (i == targetLine)
{
fp->ReadLine(buffer, sizeof(buffer) - 1);
fptemp.Write(text, length);
fptemp.Write("\n", 1);
}
else if (fp->ReadLine(buffer, sizeof(buffer) - 1))
{
fptemp.Write(buffer, strlen(buffer));
}
else if (i < targetLine)
{
fptemp.Write("\n", 1);
}
else
{
break;
}
}
rewind(fptemp.handle());
if (!(fp = AutoPtr<SystemFile>(SystemFile::Open(realpath, "w"))))
{
LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", realpath);
return 0;
}
while (fptemp.ReadLine(buffer, sizeof(buffer) - 1))
{
fp->Write(buffer, strlen(buffer));
}
return 1;
}
// native delete_file(const file[], bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG");
static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params)
{
int length;
const char* file = get_amxstring(amx, params[1], 0, length);
if (*params / sizeof(cell) >= 2 && params[2] > 0)
{
const char* pathID = get_amxstring_null(amx, params[3], 1, length);
return ValveFile::Delete(file, pathID);
}
return SystemFile::Delete(build_pathname("%s", file));
}
// native file_exists(const file[], bool:use_valve_fs = false);
static cell AMX_NATIVE_CALL file_exists(AMX *amx, cell *params)
{
int length;
const char* file = get_amxstring(amx, params[1], 0, length);
if (*params / sizeof(cell) >= 2 && params[2] > 0)
{
return g_FileSystem->FileExists(file);
}
return g_LibSys.IsPathFile(build_pathname("%s", file));
}
// native dir_exists(const dir[], bool:use_valve_fs = false);
static cell AMX_NATIVE_CALL dir_exists(AMX *amx, cell *params)
{
int length;
const char *path = get_amxstring(amx, params[1], 0, length);
if (*params / sizeof(cell) >= 2 && params[2] > 0)
{
return g_FileSystem->IsDirectory(path);
}
return g_LibSys.IsPathDirectory(build_pathname("%s", path));
}
#define FSOPT_BYTES_COUNT 0
#define FSOPT_LINES_COUNT 1
#define FSOPT_END_WITH_LF 2
// native file_size(const file[], flag = 0, bool:use_valve_fs = false, const valve_path_id[] = "GAME");
static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
int flag = FSOPT_BYTES_COUNT;
AutoPtr<FileObject> fp;
size_t numParams = *params / sizeof(cell);
if (numParams >= 3 && params[3] > 0)
{
const char* pathID = get_amxstring_null(amx, params[4], 1, length);
fp = ValveFile::Open(path, "r", pathID);
}
else
{
fp = SystemFile::Open(build_pathname("%s", path), "r");
}
if (!fp)
{
return -1;
}
if (numParams >= 2)
{
flag = params[2];
}
switch (flag)
{
case FSOPT_BYTES_COUNT:
{
fp->Seek(0, SEEK_END);
return fp->Tell();
}
case FSOPT_LINES_COUNT:
{
int8_t ch = 0;
size_t lines = 0;
while (!fp->EndOfFile() && !fp->HasError())
{
++lines;
while (fp->Read(&ch, 1) == 1 && ch != '\n' && ch != EOF);
}
return lines;
}
case FSOPT_END_WITH_LF:
{
int8_t ch = 0;
fp->Seek(-1, SEEK_END);
fp->Read(&ch, 1);
return ch == '\n';
}
}
return -1;
}
// native fopen(const filename[], const mode[], bool:use_valve_fs = false, const valve_path_id[] = "GAME");
static cell AMX_NATIVE_CALL amx_fopen(AMX *amx, cell *params)
{
int length;
const char* file = get_amxstring(amx, params[1], 0, length);
const char* flags = get_amxstring(amx, params[2], 1, length);
FileObject* fp = nullptr;
if (*params / sizeof(cell) >= 3 && params[3] > 0)
{
const char* pathID = get_amxstring_null(amx, params[4], 2, length);
fp = ValveFile::Open(file, flags, pathID);
}
else
{
fp = SystemFile::Open(build_pathname("%s", file), flags);
}
if (!fp)
{
return 0;
}
return reinterpret_cast<cell>(fp);
}
#define BLOCK_INT 4
#define BLOCK_SHORT 2
#define BLOCK_CHAR 1
// native fwrite_blocks(file, const data[], blocks, mode);
static cell AMX_NATIVE_CALL amx_fwrite_blocks(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell* data = get_amxaddr(amx, params[2]);
cell blocks = params[3];
cell size = params[4];
size_t read = 0;
switch (size)
{
case BLOCK_CHAR:
{
for (cell i = 0; i < blocks; ++i)
{
char value = data[i];
if (fp->Write(&value, sizeof(value)) != sizeof(value))
{
break;
}
read += sizeof(value);
}
break;
}
case BLOCK_SHORT:
{
for (cell i = 0; i < blocks; ++i)
{
short value = data[i];
if (fp->Write(&value, sizeof(value)) != sizeof(value))
{
break;
}
read += sizeof(value);
}
break;
}
case BLOCK_INT:
{
read = fp->Write(data, sizeof(cell) * blocks);
break;
}
default:
{
return 0;
}
}
return read / size;
}
// native fwrite(file, data, mode);
static cell AMX_NATIVE_CALL amx_fwrite(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell data = params[2];
size_t size = params[3];
switch (size)
{
case BLOCK_CHAR:
{
char value = static_cast<char>(data);
return fp->Write(&value, sizeof(value));
}
case BLOCK_SHORT:
{
short value = static_cast<short>(data);
return fp->Write(&value, sizeof(value));
}
case BLOCK_INT:
{
int value = static_cast<int>(data);
return fp->Write(&value, sizeof(value));
}
}
return 0;
}
// native fwrite_raw(file, const stream[], blocksize, mode);
static cell AMX_NATIVE_CALL amx_fwrite_raw(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell* data = get_amxaddr(amx, params[2]);
return fp->Write(&data, params[3] * params[4]);
}
// native fread_raw(file, stream[], blocksize, blocks);
static cell AMX_NATIVE_CALL amx_fread_raw(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell* data = get_amxaddr(amx, params[2]);
return fp->Read(data, params[3] * params[4]);
}
// native fread(file, &data, mode);
static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell *data = get_amxaddr(amx, params[2]);
switch (params[3])
{
case BLOCK_CHAR:
{
char value;
size_t res = fp->Read(&value, sizeof(value));
*data = static_cast<cell>(value);
return res;
}
case BLOCK_SHORT:
{
short value;
size_t res = fp->Read(&value, sizeof(value));
*data = static_cast<cell>(value);
return res;
}
case BLOCK_INT:
{
int value;
size_t res = fp->Read(&value, sizeof(value));
*data = static_cast<cell>(value);
return res;
}
}
return 0;
}
// native fread_blocks(file, data[], blocks, mode);
static cell AMX_NATIVE_CALL amx_fread_blocks(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell *data = get_amxaddr(amx, params[2]);
cell blocks = params[3];
cell size = params[4];
size_t read = 0;
switch (size)
{
case BLOCK_CHAR:
{
for (cell i = 0; i < blocks; ++i)
{
char value;
if (fp->Read(&value, sizeof(value)) != sizeof(value))
{
break;
}
read += sizeof(value);
*data++ = value;
}
break;
}
case BLOCK_SHORT:
{
for (cell i = 0; i < blocks; ++i)
{
short value;
if (fp->Read(&value, sizeof(value)) != sizeof(value))
{
break;
}
read += sizeof(value);
*data++ = value;
}
break;
}
case BLOCK_INT:
{
read = fp->Read(data, sizeof(cell) * blocks);
break;
}
default:
{
return 0;
}
}
return read / size;
}
// native fputs(file, const text[], bool:null_term = false);
static cell AMX_NATIVE_CALL amx_fputs(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
int length;
char *string = get_amxstring(amx, params[2], 0, length);
if (*params / sizeof(cell) >= 3 && params[3] > 0)
{
++length;
}
if (fp->Write(string, length) != length)
{
return -1;
}
return 0;
}
// native fgets(file, buffer[], maxlength);
static cell AMX_NATIVE_CALL amx_fgets(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
static char buffer[4096];
buffer[0] = '\0';
if (!fp->ReadLine(buffer, sizeof(buffer) - 1))
{
return 0;
}
return set_amxstring_utf8(amx, params[2], buffer, strlen(buffer), params[3] + 1); // + EOS
}
// native fseek(file, position, start);
static cell AMX_NATIVE_CALL amx_fseek(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
return !fp->Seek(params[2], params[3]);
}
// native ftell(file);
static cell AMX_NATIVE_CALL amx_ftell(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
return fp->Tell();
}
// native fprintf(file, const fmt[], any:...);
static cell AMX_NATIVE_CALL amx_fprintf(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
int length;
const char* string = format_amxstring(amx, params, 2, length);
if (ValveFile *vfile = fp->AsValveFile())
{
return g_FileSystem->FPrintf(vfile->handle(), const_cast<char*>("%s"), string);
}
else if (SystemFile *sysfile = fp->AsSystemFile())
{
return fprintf(sysfile->handle(), "%s", string);
}
else
{
assert(false);
}
return 0;
}
// native feof(file);
static cell AMX_NATIVE_CALL amx_feof(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (fp)
{
return fp->EndOfFile();
}
return 1;
}
// native fclose(file);
static cell AMX_NATIVE_CALL amx_fclose(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (fp)
{
fp->Close();
}
return 1;
}
// native filesize(const filename[], any:...);
static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params)
{
int length;
const char *realpath = build_pathname("%s", format_amxstring(amx, params, 1, length));
AutoPtr<SystemFile> fp(SystemFile::Open(realpath, "rb"));
if (fp)
{
fp->Seek(0, SEEK_END);
return fp->Tell();
}
return -1;
}
// Undocumented.
static cell AMX_NATIVE_CALL amx_build_pathname(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
return set_amxstring(amx, params[2], build_pathname("%s", path), params[3]);
}
enum FileType
{
FileType_Unknown, /* Unknown file type (device/socket) */
FileType_Directory, /* File is a directory */
FileType_File, /* File is a file */
};
struct DirectoryHandle
{
DirectoryHandle(void* handle_, bool valvefs_) : handle(handle_), valvefs(valvefs_) {}
void* handle;
bool valvefs;
};
// native open_dir(dir[], firstfile[], length, &FileType:type = FileType_Unknown, bool:use_valve_fs=false, const valve_path_id[] = "GAME");
static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params)
{
int length;
const char* path = get_amxstring(amx, params[1], 0, length);
if (!*path)
{
return 0;
}
size_t numParams = *params / sizeof(cell);
if (numParams >= 4 && params[5] > 0)
{
const char* wildcardedPath = g_LibSys.PathFormat("%s%s*", path, (path[length - 1] != '/' && path[length - 1] != '\\') ? "/" : "");
const char* pathID = get_amxstring_null(amx, params[6], 1, length);
static FileFindHandle_t handle;
const char* pFirst = g_FileSystem->FindFirst(wildcardedPath, &handle, pathID);
if (!pFirst)
{
return 0;
}
set_amxstring_utf8(amx, params[2], pFirst, strlen(pFirst), params[3] + 1);
cell* fileType = get_amxaddr(amx, params[4]);
*fileType = g_FileSystem->FindIsDirectory(handle) ? FileType_Directory : FileType_File;
return reinterpret_cast<cell>(new DirectoryHandle(reinterpret_cast<void*>(&handle), true));
}
CDirectory* dir = g_LibSys.OpenDirectory(build_pathname("%s", path));
if (!dir)
{
return 0;
}
if (numParams >= 4)
{
cell* fileType = get_amxaddr(amx, params[4]);
*fileType = dir->IsEntryDirectory() ? FileType_Directory : FileType_File;
}
const char* entry = dir->GetEntryName();
set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1);
return reinterpret_cast<cell>(new DirectoryHandle(reinterpret_cast<void*>(dir), false));
}
// native close_dir(dirh);
static cell AMX_NATIVE_CALL amx_close_dir(AMX *amx, cell *params)
{
AutoPtr<DirectoryHandle> p(reinterpret_cast<DirectoryHandle*>(params[1]));
if (!p)
{
return 0;
}
if (p->valvefs)
{
FileFindHandle_t* handle = reinterpret_cast<FileFindHandle_t*>(p->handle);
g_FileSystem->FindClose(*handle);
}
else
{
CDirectory* handle = reinterpret_cast<CDirectory*>(p->handle);
g_LibSys.CloseDirectory(handle);
}
return 1;
}
// native next_file(dirh, buffer[], length, &FileType:type = FileType_Unknown);
static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params)
{
DirectoryHandle* p = reinterpret_cast<DirectoryHandle*>(params[1]);
if (!p)
{
return 0;
}
size_t numParams = *params / sizeof(cell);
if (p->valvefs)
{
FileFindHandle_t* handle = reinterpret_cast<FileFindHandle_t*>(p->handle);
if (!handle)
{
return 0;
}
const char* entry = g_FileSystem->FindNext(*handle);
if (!entry)
{
return 0;
}
if (numParams >= 4)
{
cell* fileType = get_amxaddr(amx, params[4]);
*fileType = g_FileSystem->FindIsDirectory(*handle) ? FileType_Directory : FileType_File;
}
set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1);
}
else
{
CDirectory* handle = reinterpret_cast<CDirectory*>(p->handle);
if (!handle)
{
return 0;
}
handle->NextEntry();
if (!handle->MoreFiles())
{
return 0;
}
if (numParams >= 4)
{
cell* fileType = get_amxaddr(amx, params[4]);
*fileType = handle->IsEntryDirectory() ? FileType_Directory : FileType_File;
}
const char* entry = handle->GetEntryName();
set_amxstring_utf8(amx, params[2], entry, strlen(entry), params[3] + 1);
}
return 1;
}
//native fgetc(file);
static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
uint8_t val;
if (fp->Read(&val, sizeof(val)) != sizeof(val))
{
return -1;
}
return static_cast<cell>(val);
}
//native fputc(file, data);
static cell AMX_NATIVE_CALL amx_fputc(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
uint8_t val = static_cast<uint8_t>(params[2]);
if (fp->Write(&val, sizeof(val)) != sizeof(val))
{
return -1;
}
return val;
}
//native ungetc(file, data);
static cell AMX_NATIVE_CALL amx_ungetc(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
SystemFile* sysfile = fp->AsSystemFile();
if (!sysfile)
{
LogError(amx, AMX_ERR_NATIVE, "Can not ungetc to file in the Valve file system");
return 0;
}
return ungetc(static_cast<int>(params[2]), sysfile->handle());
}
// native rmdir(const path[]);
static cell AMX_NATIVE_CALL amx_rmdir(AMX *amx, cell *params)
{
int length;
const char* realpath = build_pathname("%s", get_amxstring(amx, params[1], 0, length));
return rmdir(realpath) == 0;
}
// native mkdir(const dirname[], mode, bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG");
static cell AMX_NATIVE_CALL amx_mkdir(AMX *amx, cell *params)
{
int length;
char *path = get_amxstring(amx, params[1], 0, length);
size_t numParams = *params / sizeof(cell);
if (numParams >= 3 && params[3] > 0)
{
const char* pathID = get_amxstring_null(amx, params[4], 1, length);
if (g_FileSystem->IsDirectory(path))
{
return -1;
}
g_FileSystem->CreateDirHierarchy(path, pathID);
if (g_FileSystem->IsDirectory(path))
{
return 0;
}
}
const char* realpath = build_pathname("%s", path);
#if defined PLATFORM_WINDOWS
return mkdir(realpath);
#else
if (numParams >= 2)
{
return mkdir(realpath, params[2]);
}
return mkdir(realpath, 0755);
#endif
}
// native rename_file(const oldname[], const newname[], relative = 0);
static cell AMX_NATIVE_CALL rename_file(AMX *amx, cell *params)
{
int length;
char file_old_r[PLATFORM_MAX_PATH];
char file_new_r[PLATFORM_MAX_PATH];
const char* file_old = get_amxstring(amx, params[1], 0, length);
const char* file_new = get_amxstring(amx, params[2], 1, length);
if (params[0] / sizeof(cell) >= 3 && params[3] > 0)
{
build_pathname_r(file_old_r, sizeof(file_old_r) - 1, "%s", file_old);
build_pathname_r(file_new_r, sizeof(file_new_r) - 1, "%s", file_new);
}
else
{
g_LibSys.PathFormat(file_old_r, sizeof(file_old_r) - 1, "%s", file_old);
g_LibSys.PathFormat(file_new_r, sizeof(file_new_r) - 1, "%s", file_new);
}
#if defined PLATFORM_POSIX
return (rename(file_old_r, file_new_r) == 0);
#elif defined PLATFORM_WINDOWS
return MoveFileA(file_old_r, file_new_r);
#endif
}
// native LoadFileForMe(const file[], buffer[], maxlength, &length = 0);
static cell LoadFileForMe(AMX *amx, cell *params)
{
int length;
char *file = get_amxstring(amx, params[1], 0, length);
char path[PLATFORM_MAX_PATH];
build_pathname_r(path, sizeof(path), "%s", file);
byte* addr = LOAD_FILE_FOR_ME(path, &length);
if (!addr)
{
return -1;
}
cell *buffer = get_amxaddr(amx, params[2]);
cell maxlength = params[3];
cell *bytes_avail = get_amxaddr(amx, params[4]);
*bytes_avail = length;
cell count;
for (count = 0; count < length && count < maxlength; count++)
{
buffer[count] = addr[count];
}
FREE_FILE(addr);
return count;
}
// native fflush(file);
static cell AMX_NATIVE_CALL amx_fflush(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (fp)
{
return fp->Flush();
}
return -1;
}
// native GetFileTime(const file[], FileTimeType:tmode);
static cell AMX_NATIVE_CALL GetFileTime(AMX *amx, cell *params)
{
int length;
const char* file = get_amxstring(amx, params[1], 0, length);
time_t time_val;
if (!g_LibSys.FileTime(build_pathname("%s", file), static_cast<FileTimeType>(params[2]), &time_val))
{
return -1;
}
return static_cast<cell>(time_val);
}
#define FPERM_U_READ 0x0100 /* User can read. */
#define FPERM_U_WRITE 0x0080 /* User can write. */
#define FPERM_U_EXEC 0x0040 /* User can exec. */
#define FPERM_G_READ 0x0020 /* Group can read. */
#define FPERM_G_WRITE 0x0010 /* Group can write. */
#define FPERM_G_EXEC 0x0008 /* Group can exec. */
#define FPERM_O_READ 0x0004 /* Anyone can read. */
#define FPERM_O_WRITE 0x0002 /* Anyone can write. */
#define FPERM_O_EXEC 0x0001 /* Anyone can exec. */
// native bool:SetFilePermissions(const path[], int mode);
static cell SetFilePermissions(AMX *amx, cell *params)
{
int length;
const char* realpath = build_pathname(get_amxstring(amx, params[1], 0, length));
#if defined PLATFORM_WINDOWS
int mask = 0;
if (params[2] & (FPERM_U_WRITE | FPERM_G_WRITE | FPERM_O_WRITE))
{
mask |= _S_IWRITE;
}
if (params[2] & (FPERM_U_READ | FPERM_G_READ | FPERM_O_READ | FPERM_U_EXEC | FPERM_G_EXEC | FPERM_O_EXEC))
{
mask |= _S_IREAD;
}
return _chmod(realpath, mask) == 0;
#else
return chmod(realpath, params[2]) == 0;
#endif
}
template <typename T>
static cell File_ReadTyped(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
cell* data = get_amxaddr(amx, params[2]);
T value;
if (fp->Read(&value, sizeof(value)) != sizeof(value))
{
return 0;
}
*data = value;
return 1;
}
template <typename T>
static cell File_WriteTyped(AMX *amx, cell *params)
{
FileObject* fp = reinterpret_cast<FileObject*>(params[1]);
if (!fp)
{
return 0;
}
T value = static_cast<T>(params[2]);
return !!(fp->Write(&value, sizeof(value)) == sizeof(value));
}
AMX_NATIVE_INFO file_Natives[] =
{
{"read_dir", read_dir},
{"read_file", read_file},
{"write_file", write_file},
{"rename_file", rename_file},
{"delete_file", delete_file},
{"unlink", delete_file},
{"file_exists", file_exists},
{"file_size", file_size},
{"filesize", amx_filesize},
{"fopen", amx_fopen},
{"fclose", amx_fclose},
{"fread", amx_fread},
{"fread_blocks", amx_fread_blocks},
{"fread_raw", amx_fread_raw},
{"fwrite", amx_fwrite},
{"fwrite_blocks", amx_fwrite_blocks},
{"fwrite_raw", amx_fwrite_raw},
{"feof", amx_feof},
{"fprintf", amx_fprintf},
{"fgets", amx_fgets},
{"fseek", amx_fseek},
{"ftell", amx_ftell},
{"fgetc", amx_fgetc},
{"fputc", amx_fputc},
{"fungetc", amx_ungetc},
{"fputs", amx_fputs},
{"fflush", amx_fflush},
{"build_pathname", amx_build_pathname},
{"dir_exists", dir_exists},
{"open_dir", amx_open_dir},
{"close_dir", amx_close_dir},
{"next_file", amx_get_dir},
{"rmdir", amx_rmdir},
{"mkdir", amx_mkdir},
{"LoadFileForMe", LoadFileForMe},
{"GetFileTime", GetFileTime},
{"SetFilePermissions", SetFilePermissions},
{"FileReadInt8", File_ReadTyped<int8_t>},
{"FileReadUint8", File_ReadTyped<uint8_t>},
{"FileReadInt16", File_ReadTyped<int16_t>},
{"FileReadUint16", File_ReadTyped<uint16_t>},
{"FileReadInt32", File_ReadTyped<int32_t>},
{"FileWriteInt8", File_WriteTyped<int8_t>},
{"FileWriteInt16", File_WriteTyped<int16_t>},
{"FileWriteInt32", File_WriteTyped<int32_t>},
{NULL, NULL}
};