summaryrefslogtreecommitdiff
path: root/sourcemod-1.5-dev/scripting/include/smlib/files.inc
diff options
context:
space:
mode:
Diffstat (limited to 'sourcemod-1.5-dev/scripting/include/smlib/files.inc')
-rw-r--r--sourcemod-1.5-dev/scripting/include/smlib/files.inc458
1 files changed, 458 insertions, 0 deletions
diff --git a/sourcemod-1.5-dev/scripting/include/smlib/files.inc b/sourcemod-1.5-dev/scripting/include/smlib/files.inc
new file mode 100644
index 0000000..3fda876
--- /dev/null
+++ b/sourcemod-1.5-dev/scripting/include/smlib/files.inc
@@ -0,0 +1,458 @@
+#if defined _smlib_files_included
+ #endinput
+#endif
+#define _smlib_files_included
+
+#include <sourcemod>
+#include <sdktools>
+#include <smlib/arrays>
+
+/**
+ * Gets the Base name of a path.
+ * Examples:
+ * blub.txt -> "blub.txt"
+ * /sourcemod/extensions/example.ext.so -> "example.ext.so"
+ *
+ * @param path File path
+ * @param buffer String buffer array
+ * @param size Size of string buffer
+ * @noreturn
+ */
+stock bool:File_GetBaseName(const String:path[], String:buffer[], size)
+{
+ if (path[0] == '\0') {
+ buffer[0] = '\0';
+ return;
+ }
+
+ new pos_start = FindCharInString(path, '/', true);
+
+ if (pos_start == -1) {
+ pos_start = FindCharInString(path, '\\', true);
+ }
+
+ pos_start++;
+
+ strcopy(buffer, size, path[pos_start]);
+}
+
+/**
+ * Gets the Directory of a path (without the file name).
+ * Does not work with "." as the path.
+ * Examples:
+ * blub.txt -> "blub.txt"
+ * /sourcemod/extensions/example.ext.so -> "example.ext.so"
+ *
+ * @param path File path
+ * @param buffer String buffer array
+ * @param size Size of string buffer
+ * @noreturn
+ */
+stock bool:File_GetDirName(const String:path[], String:buffer[], size)
+{
+ if (path[0] == '\0') {
+ buffer[0] = '\0';
+ return;
+ }
+
+ new pos_start = FindCharInString(path, '/', true);
+
+ if (pos_start == -1) {
+ pos_start = FindCharInString(path, '\\', true);
+
+ if (pos_start == -1) {
+ buffer[0] = '\0';
+ return;
+ }
+ }
+
+ strcopy(buffer, size, path);
+ buffer[pos_start] = '\0';
+}
+
+/**
+ * Gets the File name of a path.
+ * blub.txt -> "blub"
+ * /sourcemod/extensions/example.ext.so -> "example.ext"
+ *
+ * @param path File path
+ * @param buffer String buffer array
+ * @param size Size of string buffer
+ * @noreturn
+ */
+stock bool:File_GetFileName(const String:path[], String:buffer[], size)
+{
+ if (path[0] == '\0') {
+ buffer[0] = '\0';
+ return;
+ }
+
+ File_GetBaseName(path, buffer, size);
+
+ new pos_ext = FindCharInString(buffer, '.', true);
+
+ if (pos_ext != -1) {
+ buffer[pos_ext] = '\0';
+ }
+}
+
+/**
+ * Gets the Extension of a file.
+ * Examples:
+ * blub.inc.txt -> "txt"
+ * /sourcemod/extensions/example.ext.so -> "so"
+ *
+ * @param path Path String
+ * @param buffer String buffer array
+ * @param size Max length of string buffer
+ * @noreturn
+ */
+stock File_GetExtension(const String:path[], String:buffer[], size)
+{
+ new extpos = FindCharInString(path, '.', true);
+
+ if (extpos == -1) {
+ buffer[0] = '\0';
+ return;
+ }
+
+ strcopy(buffer, size, path[++extpos]);
+}
+
+/**
+ * Adds a path to the downloadables network string table.
+ * This can be a file or directory and also works recursed.
+ * You can optionally specify file extensions that should be ignored.
+ * Bz2 and ztmp are automatically ignored.
+ * It only adds files that actually exist.
+ * You can also specify a wildcard * after the ., very useful for models.
+ * This forces a client to download the file if they do not already have it.
+ *
+ * @param path Path String
+ * @param recursive Whether to do recursion or not.
+ * @param ignoreExts Optional: 2 dimensional String array.You can define it like this: new String:ignore[][] = { ".ext1", ".ext2" };
+ * @param size This should be set to the number of file extensions in the ignoreExts array (sizeof(ignore) for the example above)
+ * @noreturn
+ */
+
+// Damn you SourcePawn :( I didn't want to
+new String:_smlib_empty_twodimstring_array[][] = { { '\0' } };
+stock File_AddToDownloadsTable(const String:path[], bool:recursive=true, const String:ignoreExts[][]=_smlib_empty_twodimstring_array, size=0)
+{
+ if (path[0] == '\0') {
+ return;
+ }
+
+ if (FileExists(path)) {
+
+ new String:fileExtension[5];
+ File_GetExtension(path, fileExtension, sizeof(fileExtension));
+
+ if (StrEqual(fileExtension, "bz2", false) || StrEqual(fileExtension, "ztmp", false)) {
+ return;
+ }
+
+ if (Array_FindString(ignoreExts, size, fileExtension) != -1) {
+ return;
+ }
+
+ decl String:path_new[PLATFORM_MAX_PATH];
+ strcopy(path_new, sizeof(path_new), path);
+ ReplaceString(path_new, sizeof(path_new), "//", "/");
+
+ AddFileToDownloadsTable(path_new);
+ }
+ else if (recursive && DirExists(path)) {
+
+ decl String:dirEntry[PLATFORM_MAX_PATH];
+ new Handle:__dir = OpenDirectory(path);
+
+ while (ReadDirEntry(__dir, dirEntry, sizeof(dirEntry))) {
+
+ if (StrEqual(dirEntry, ".") || StrEqual(dirEntry, "..")) {
+ continue;
+ }
+
+ Format(dirEntry, sizeof(dirEntry), "%s/%s", path, dirEntry);
+ File_AddToDownloadsTable(dirEntry, recursive, ignoreExts, size);
+ }
+
+ CloseHandle(__dir);
+ }
+ else if (FindCharInString(path, '*', true)) {
+
+ new String:fileExtension[4];
+ File_GetExtension(path, fileExtension, sizeof(fileExtension));
+
+ if (StrEqual(fileExtension, "*")) {
+
+ decl
+ String:dirName[PLATFORM_MAX_PATH],
+ String:fileName[PLATFORM_MAX_PATH],
+ String:dirEntry[PLATFORM_MAX_PATH];
+
+ File_GetDirName(path, dirName, sizeof(dirName));
+ File_GetFileName(path, fileName, sizeof(fileName));
+ StrCat(fileName, sizeof(fileName), ".");
+
+ new Handle:__dir = OpenDirectory(dirName);
+ while (ReadDirEntry(__dir, dirEntry, sizeof(dirEntry))) {
+
+ if (StrEqual(dirEntry, ".") || StrEqual(dirEntry, "..")) {
+ continue;
+ }
+
+ if (strncmp(dirEntry, fileName, strlen(fileName)) == 0) {
+ Format(dirEntry, sizeof(dirEntry), "%s/%s", dirName, dirEntry);
+ File_AddToDownloadsTable(dirEntry, recursive, ignoreExts, size);
+ }
+ }
+
+ CloseHandle(__dir);
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Adds all files/paths in the given text file to the download table.
+ * Recursive mode enabled, see File_AddToDownloadsTable()
+ * Comments are allowed ! Supported comment types are ; // #
+ *
+ * @param path Path to the .txt file.
+ * @noreturn
+ */
+stock File_ReadDownloadList(const String:path[])
+{
+ new Handle:file = OpenFile(path, "r");
+
+ if (file == INVALID_HANDLE) {
+ return;
+ }
+
+ new String:buffer[PLATFORM_MAX_PATH];
+ while (!IsEndOfFile(file)) {
+ ReadFileLine(file, buffer, sizeof(buffer));
+
+ new pos;
+ pos = StrContains(buffer, "//");
+ if (pos != -1) {
+ buffer[pos] = '\0';
+ }
+
+ pos = StrContains(buffer, "#");
+ if (pos != -1) {
+ buffer[pos] = '\0';
+ }
+
+ pos = StrContains(buffer, ";");
+ if (pos != -1) {
+ buffer[pos] = '\0';
+ }
+
+ TrimString(buffer);
+
+ if (buffer[0] == '\0') {
+ continue;
+ }
+
+ File_AddToDownloadsTable(buffer);
+ }
+
+ CloseHandle(file);
+}
+
+/*
+ * Attempts to load a translation file and optionally unloads the plugin if the file
+ * doesn't exist (also prints an error message).
+ *
+ * @param file Filename of the translations file (eg. <pluginname>.phrases).
+ * @param setFailState If true, it sets the failstate if the translations file doesn't exist
+ * @return True on success, false otherwise (only if setFailState is set to false)
+ */
+stock File_LoadTranslations(const String:file[], setFailState=true)
+{
+ decl String:path[PLATFORM_MAX_PATH];
+
+ BuildPath(Path_SM, path, sizeof(path), "translations/%s", file);
+
+ if (FileExists(path)) {
+ LoadTranslations(file);
+ return true;
+ }
+
+ Format(path,sizeof(path), "%s.txt", path);
+
+ if (!FileExists(path)) {
+
+ if (setFailState) {
+ SetFailState("Unable to locate translation file (%s).", path);
+ }
+
+ return false;
+ }
+
+ LoadTranslations(file);
+
+ return true;
+}
+
+/*
+ * Reads the contents of a given file into a string buffer in binary mode.
+ *
+ * @param path Path to the file
+ * @param buffer String buffer
+ * @param size If -1, reads until a null terminator is encountered in the file. Otherwise, read_count bytes are read into the buffer provided. In this case the buffer is not explicitly null terminated, and the buffer will contain any null terminators read from the file.
+ * @return Number of characters written to the buffer, or -1 if an error was encountered.
+ */
+stock File_ToString(const String:path[], String:buffer[], size)
+{
+ new Handle:file = OpenFile(path, "rb");
+
+ if (file == INVALID_HANDLE) {
+ buffer[0] = '\0';
+ return -1;
+ }
+
+ new num_bytes_written = ReadFileString(file, buffer, size);
+ CloseHandle(file);
+
+ return num_bytes_written;
+}
+
+/*
+ * Writes a string into a file in binary mode.
+ *
+ * @param file Path to the file
+ * @param str String to write
+ * @return True on success, false otherwise
+ */
+stock bool:File_StringToFile(const String:path[], String:str[])
+{
+ new Handle:file = OpenFile(path, "wb");
+
+ if (file == INVALID_HANDLE) {
+ return false;
+ }
+
+ new bool:success = WriteFileString(file, str, false);
+ CloseHandle(file);
+
+ return success;
+}
+
+/*
+ * Copies file source to destination
+ * Based on code of javalia:
+ * http://forums.alliedmods.net/showthread.php?t=159895
+ *
+ * @param source Input file
+ * @param destination Output file
+ */
+stock bool:File_Copy(const String:source[], const String:destination[])
+{
+ new Handle:file_source = OpenFile(source, "rb");
+
+ if (file_source == INVALID_HANDLE) {
+ return false;
+ }
+
+ new Handle:file_destination = OpenFile(destination, "wb");
+
+ if (file_destination == INVALID_HANDLE) {
+ CloseHandle(file_source);
+ return false;
+ }
+
+ new buffer[32];
+ new cache;
+
+ while (!IsEndOfFile(file_source)) {
+ cache = ReadFile(file_source, buffer, 32, 1);
+ WriteFile(file_destination, buffer, cache, 1);
+ }
+
+ CloseHandle(file_source);
+ CloseHandle(file_destination);
+
+ return true;
+}
+
+/*
+ * Recursively copies (the content) of a directory or file specified
+ * by "path" to "destination".
+ * Note that because of Sourcemod API limitations this currently does not
+ * takeover the file permissions (it leaves them default).
+ * Links will be resolved.
+ *
+ * @param path Source path
+ * @param destination Destination directory (This can only be a directory)
+ * @param stop_on_error Optional: Set to true to stop on error (ie can't read a file)
+ * @param dirMode Optional: File mode for directories that will be created (Default = 0755), don't forget to convert FROM octal
+ */
+stock bool:File_CopyRecursive(const String:path[], const String:destination[], bool:stop_on_error=false, dirMode=493)
+{
+ if (FileExists(path)) {
+ return File_Copy(path, destination);
+ }
+ else if (DirExists(path)) {
+ return Sub_File_CopyRecursive(path, destination, stop_on_error, FileType_Directory, dirMode);
+ }
+ else {
+ return false;
+ }
+}
+
+static stock bool:Sub_File_CopyRecursive(const String:path[], const String:destination[], bool:stop_on_error=false, FileType:fileType, dirMode)
+{
+ if (fileType == FileType_File) {
+ return File_Copy(path, destination);
+ }
+ else if (fileType == FileType_Directory) {
+
+ if (!CreateDirectory(destination, dirMode) && stop_on_error) {
+ return false;
+ }
+
+ new Handle:directory = OpenDirectory(path);
+
+ if (directory == INVALID_HANDLE) {
+ return false;
+ }
+
+ decl
+ String:source_buffer[PLATFORM_MAX_PATH],
+ String:destination_buffer[PLATFORM_MAX_PATH];
+ new FileType:type;
+
+ while (ReadDirEntry(directory, source_buffer, sizeof(source_buffer), type)) {
+
+ if (StrEqual(source_buffer, "..") || StrEqual(source_buffer, ".")) {
+ continue;
+ }
+
+ Format(destination_buffer, sizeof(destination_buffer), "%s/%s", destination, source_buffer);
+ Format(source_buffer, sizeof(source_buffer), "%s/%s", path, source_buffer);
+
+ if (type == FileType_File) {
+ File_Copy(source_buffer, destination_buffer);
+ }
+ else if (type == FileType_Directory) {
+
+ if (!File_CopyRecursive(source_buffer, destination_buffer, stop_on_error, dirMode) && stop_on_error) {
+ CloseHandle(directory);
+ return false;
+ }
+ }
+ }
+
+ CloseHandle(directory);
+ }
+ else if (fileType == FileType_Unknown) {
+ return false;
+ }
+
+ return true;
+}