From abb763d1e1049de0ae16d1848c0cf0619b747b88 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 16 Dec 2007 23:11:00 +0000 Subject: [PATCH] added amb618 - binary file i/o --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401802 --- core/smn_filesystem.cpp | 195 ++++++++++++++++++++++++++++++++++++++ plugins/include/files.inc | 121 ++++++++++++++++++++--- 2 files changed, 303 insertions(+), 13 deletions(-) diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index b209bfd3..d54bc9f0 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -640,6 +640,197 @@ static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + FILE *pFile; + size_t read = 0; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + if (params[4] != 1 && params[4] != 2 && params[4] != 4) + { + return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]); + } + + cell_t *data; + pContext->LocalToPhysAddr(params[2], &data); + + if (params[4] == 4) + { + read = fread(data, sizeof(cell_t), params[3], pFile); + } + else if (params[4] == 2) + { + int16_t val; + for (cell_t i = 0; i < params[3]; i++) + { + if (fread(&val, sizeof(int16_t), 1, pFile) != 1) + { + break; + } + data[read++] = val; + } + } + else if (params[4] == 1) + { + int8_t val; + for (cell_t i = 0; i < params[3]; i++) + { + if (fread(&val, sizeof(int8_t), 1, pFile) != 1) + { + break; + } + data[read++] = val; + } + } + + if (read != (size_t)params[3] && ferror(pFile) != 0) + { + return -1; + } + + return read; +} + +static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + FILE *pFile; + cell_t num_read = 0; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *buffer; + pContext->LocalToString(params[2], &buffer); + + char val; + while (1) + { + /* If we're in stop mode, break as soon as the buffer is full. */ + if (params[4] && (params[3] == 0 || num_read >= params[3] - 1)) + { + break; + } + if (fread(&val, sizeof(val), 1, pFile) != 1) + { + if (ferror(pFile)) + { + return -1; + } + break; + } + if (val == '\0') + { + break; + } + if (params[3] > 0 && num_read < params[3] - 1) + { + buffer[num_read++] = val; + } + } + + if (params[3] > 0) + { + buffer[num_read] = '\0'; + } + + return num_read; +} + +static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + FILE *pFile; + size_t read = 0; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + cell_t *data; + pContext->LocalToPhysAddr(params[2], &data); + + if (params[4] != 1 && params[4] != 2 && params[4] != 4) + { + return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]); + } + + /* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */ + + if (params[4] == 4) + { + if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3]) + { + return 0; + } + } + else if (params[4] == 2) + { + for (cell_t i = 0; i < params[3]; i++) + { + if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1) + { + return 0; + } + } + } + else if (params[4] == 1) + { + for (cell_t i = 0; i < params[3]; i++) + { + if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1) + { + return 0; + } + } + } + + return 1; +} + +static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + FILE *pFile; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); + } + + char *buffer; + pContext->LocalToString(params[2], &buffer); + + size_t len = strlen(buffer); + + if (params[3]) + { + len++; + } + + return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0; +} + REGISTER_NATIVES(filesystem) { {"OpenDirectory", sm_OpenDirectory}, @@ -664,5 +855,9 @@ REGISTER_NATIVES(filesystem) {"GetFileTime", sm_GetFileTime}, {"LogToOpenFile", sm_LogToOpenFile}, {"LogToOpenFileEx", sm_LogToOpenFileEx}, + {"ReadFile", sm_ReadFile}, + {"ReadFileString", sm_ReadFileString}, + {"WriteFile", sm_WriteFile}, + {"WriteFileString", sm_WriteFileString}, {NULL, NULL}, }; diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 41aa979a..54445510 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -158,6 +158,112 @@ native bool:DeleteFile(const String:path[]); */ native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength); +/** + * Reads binary data from a file. + * + * @param hndl Handle to the file. + * @param items Array to store each item read. + * @param num_items Number of items to read into the array. + * @param size Size of each element, in bytes, to be read. + * Valid sizes are 1, 2, or 4. + * @return Number of elements read, or -1 on error. + */ +native ReadFile(Handle:hndl, items[], num_items, size); + +/** + * Reads a UTF8 or ANSI string from a file. + * + * @param hndl Handle to the file. + * @param buffer Buffer to store the string. + * @param max_size Maximum size of the string buffer. + * @param stop If true, reading will stop once max_size-1 bytes have + * been read. If false, reading will stop once a NUL + * terminator is reached. The buffer will simply be + * terminated in either case, the difference is in how + * the far the file position is changed. + * @return Number of characters written to the buffer, or -1 + * if an error was encountered. + * @error Invalid Handle, or read_count > max_size. + */ +native ReadFileString(Handle:hndl, String:buffer[], max_size, read_count=-1); + +/** + * Writes binary data to a file. + * + * @param hndl Handle to the file. + * @param items Array of items to write. The data is read directly. + * That is, in 1 or 2-byte mode, the lower byte(s) in + * each cell are used directly, rather than performing + * any casts from a 4-byte number to a smaller number. + * @param num_items Number of items in the array. + * @param size Size of each item in the array in bytes. + * Valid sizes are 1, 2, or 4. + * @return True on success, false on error. + */ +native bool:WriteFile(Handle:hndl, const items[], num_items, size); + +/** + * Writes a binary string to a file. + * + * @param hndl Handle to th efile. + * @param buffer String to write. + * @param term True to append NUL terminator, false otherwise. + * @return True on success, false on error. + */ +native bool:WriteFileString(Handle:hndl, const String:buffer[], bool:term); + +/** + * Writes a line of text to a text file. A newline is automatically appended. + * + * @param hndl Handle to the file. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @return True on success, false otherwise. + */ +native bool:WriteFileLine(Handle:hndl, const String:format[], any:...); + +/** + * Reads a single binary cell from a file. + * + * @param hndl Handle to the file. + * @param data Variable to store the data read. + * @param size Size of the data to read in bytes. Valid + * sizes are 1, 2, or 4 bytes. + * @return Number of elements read (max 1), or -1 on error. + */ +stock ReadFileCell(Handle:hndl, &data, size) +{ + new array[1], ret; + + if ((ret = ReadFile(hndl, array, 1, size)) == 1) + { + data = array[0]; + } + + return ret; +} + +/** + * Writes a single binary cell to a file. + * + * @param hndl Handle to the file. + * @param data Cell to write to the file. + * @param size Size of the data to read in bytes. Valid + * sizes are 1, 2, or 4 bytes. If the size + * is less than 4 bytes, the data is truncated + * rather than casted. That is, only the lower + * bits will be read. + * @return True on success, false on error. + */ +stock bool:WriteFileCell(Handle:hndl, data, size) +{ + new array[1]; + + array[0] = data; + + return WriteFile(hndl, array, 1, size); +} + /** * Tests if the end of file has been reached. * @@ -171,10 +277,10 @@ native bool:IsEndOfFile(Handle:file); * * @param file Handle to the file. * @param position Position relative to what is specified in whence. - * @param whence Look at the SEEK_* definitions. + * @param where SEEK_ constant value of where to see from. * @return True on success, false otherwise. */ -native bool:FileSeek(Handle:file, position, whence); +native bool:FileSeek(Handle:file, position, where); /** * Get current position in the file. @@ -235,17 +341,6 @@ native FlushFile(Handle:file); */ native bool:RemoveDir(const String:path[]); -/** - * Writes a line of text in a file. - * @note This native will append the newline character. - * - * @param hndl Handle to the file. - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @return True on success, false otherwise. - */ -native bool:WriteFileLine(Handle:hndl, const String:format[], any:...); - /** * Returns a file timestamp as a unix timestamp. *