From 1e8f6cdc3ea55fa76884ccb31c068306a56ea13d Mon Sep 17 00:00:00 2001 From: steph Date: Mon, 23 Aug 2021 20:37:17 -0400 Subject: [PATCH 1/3] don't strip newlines or chars under ascii value 32 or over ascii value 126 --- .gitignore | 3 + configure.py | 0 extension.cpp | 163 ++++++++++++++++++++++++++++++++----------------- extension.h | 12 +++- smsdk_config.h | 23 +++---- 5 files changed, 133 insertions(+), 68 deletions(-) create mode 100644 .gitignore mode change 100644 => 100755 configure.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..163b962 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +build/* +obj-linux-*/* diff --git a/configure.py b/configure.py old mode 100644 new mode 100755 diff --git a/extension.cpp b/extension.cpp index bdffb41..edc62a5 100644 --- a/extension.cpp +++ b/extension.cpp @@ -1,7 +1,7 @@ #include "extension.h" #include "sigs.h" -#define TIER0_NAME SOURCE_BIN_PREFIX "tier0" SOURCE_BIN_SUFFIX SOURCE_BIN_EXT +#define TIER0_NAME SOURCE_BIN_PREFIX "tier0" SOURCE_BIN_SUFFIX SOURCE_BIN_EXT Cleaner g_Cleaner; SMEXT_LINK(&g_Cleaner); @@ -12,93 +12,144 @@ char ** g_szStrings; int g_iStrings = 0; #if SOURCE_ENGINE >= SE_LEFT4DEAD2 -DETOUR_DECL_MEMBER4(Detour_LogDirect, LoggingResponse_t, LoggingChannelID_t, channelID, LoggingSeverity_t, severity, Color, color, const tchar *, pMessage) -{ - for(int i=0;i 1 && strstr(pMessage, g_szStrings[i]) != 0) + { + return LR_CONTINUE; + } + } + return DETOUR_MEMBER_CALL(Detour_LogDirect)(channelID, severity, color, pMessage); + } #else -DETOUR_DECL_STATIC2(Detour_DefSpew, SpewRetval_t, SpewType_t, channel, char *, text) -{ - for(int i=0;i 1 && strstr(text, g_szStrings[i]) != 0) + { + return SPEW_CONTINUE; + } + } + return DETOUR_STATIC_CALL(Detour_DefSpew)(channel, text); + } #endif +// https://stackoverflow.com/questions/10178700/c-strip-non-ascii-characters-from-string +static bool badChar(char c) +{ + // everything below space excluding null term and del or above + return (c != 0 && (c < 32 || c > 126)); +} + +static void stripBadChars(std::string & str) +{ + // remove all chars matching our "badchar" func + str.erase(remove_if(str.begin(),str.end(), badChar), str.end()); +} + bool Cleaner::SDK_OnLoad(char *error, size_t maxlength, bool late) { CDetourManager::Init(g_pSM->GetScriptingEngine(), 0); char szPath[256]; g_pSM->BuildPath(Path_SM, szPath, sizeof(szPath), "configs/cleaner.cfg"); + FILE * file = fopen(szPath, "r"); - if(file==NULL) + if (file == NULL) { - snprintf(error, maxlength, "Could not read configs/cleaner.cfg."); + rootconsole->ConsolePrint("[CLEANER] Could not read configs/cleaner.cfg."); return false; } + // step thru the file char by char and log the number of newlines we have + // this is more or less the number of lines we have int c, lines = 0; do { c = fgetc(file); - if (c == '\n') ++lines; + if (c == '\n') + { + ++lines; + } } while (c != EOF); + rootconsole->ConsolePrint("[CLEANER] %i lines", lines); rewind(file); - int len; g_szStrings = new char*[lines]; - while(!feof(file)) + + while (!feof(file)) { - g_szStrings[g_iStrings] = new char[256]; - if (fgets(g_szStrings[g_iStrings], 255, file) != NULL) + g_szStrings[g_iStrings] = new char[128]; + // fgets stops at n - 1 aka 255 + if (fgets(g_szStrings[g_iStrings], 128, file) != NULL) { - len = strlen(g_szStrings[g_iStrings]); - if(g_szStrings[g_iStrings][len-1]=='\r' || g_szStrings[g_iStrings][len-1]=='\n') - g_szStrings[g_iStrings][len-1]=0; - if(g_szStrings[g_iStrings][len-2]=='\r') - g_szStrings[g_iStrings][len-2]=0; + // make things a little easier on ourselves + std::string thisstring = g_szStrings[g_iStrings]; + + // significantly more robust way of stripping evil chars from our string so we don't crash + stripBadChars( thisstring ); + + // copy our std::string back to char* + char* c_thisstring = &thisstring[0]; + + int len = strlen(c_thisstring); + + // don't strip 0 len strings + if (len <= 0) + { + //rootconsole->ConsolePrint("[CLEANER] Refusing to strip a string with 0 or less length - line %i", g_iStrings ); + } + else + { + rootconsole->ConsolePrint("[CLEANER] Stripping string on line %i: \"%s\" - length = %i", g_iStrings+1, c_thisstring, strlen(c_thisstring)); + } + + strcpy(g_szStrings[g_iStrings], c_thisstring); + ++g_iStrings; } } fclose(file); -#if SOURCE_ENGINE >= SE_LEFT4DEAD2 -#ifdef PLATFORM_WINDOWS - HMODULE tier0 = GetModuleHandle(TIER0_NAME); - void * fn = memutils->FindPattern(tier0, SIG_WINDOWS, SIG_WIN_SIZE); -#elif defined PLATFORM_LINUX - void * tier0 = dlopen(TIER0_NAME, RTLD_NOW); - void * fn = memutils->ResolveSymbol(tier0, SIG_LINUX); - dlclose(tier0); -#else - #error "Unsupported OS" -#endif - if(!fn) - { - snprintf(error, maxlength, "Failed to find signature. Please contact the author."); - return false; - } -#if defined SIG_LINUX_OFFSET -#ifdef PLATFORM_LINUX - fn = (void *)((intptr_t)fn + SIG_LINUX_OFFSET); -#endif -#endif - g_pDetour = DETOUR_CREATE_MEMBER(Detour_LogDirect, fn); -#else - g_pDetour = DETOUR_CREATE_STATIC(Detour_DefSpew, (gpointer)GetSpewOutputFunc()); -#endif - + // init our detours + #if SOURCE_ENGINE >= SE_LEFT4DEAD2 + #ifdef PLATFORM_WINDOWS + HMODULE tier0 = GetModuleHandle(TIER0_NAME); + void * fn = memutils->FindPattern(tier0, SIG_WINDOWS, SIG_WIN_SIZE); + #elif defined PLATFORM_LINUX + void * tier0 = dlopen(TIER0_NAME, RTLD_NOW); + void * fn = memutils->ResolveSymbol(tier0, SIG_LINUX); + dlclose(tier0); + #else + #error "Unsupported OS" + #endif + + if (!fn) + { + rootconsole->ConsolePrint("[CLEANER] Failed to find signature. Please contact the author."); + return false; + } + #if defined SIG_LINUX_OFFSET + #ifdef PLATFORM_LINUX + fn = (void *)((intptr_t)fn + SIG_LINUX_OFFSET); + #endif + #endif + g_pDetour = DETOUR_CREATE_MEMBER(Detour_LogDirect, fn); + #else + g_pDetour = DETOUR_CREATE_STATIC(Detour_DefSpew, (gpointer)GetSpewOutputFunc()); + #endif + if (g_pDetour == NULL) { - snprintf(error, maxlength, "Failed to initialize the detours. Please contact the author."); + rootconsole->ConsolePrint("[CLEANER] Failed to initialize the detours. Please contact the author."); return false; } @@ -115,8 +166,10 @@ void Cleaner::SDK_OnUnload() g_pDetour = NULL; } - for(int i = 0; i < g_iStrings; ++i) + for (int i = 0; i < g_iStrings; ++i) + { delete [] g_szStrings[i]; + } delete [] g_szStrings; } diff --git a/extension.h b/extension.h index ef51b2a..0c67e44 100644 --- a/extension.h +++ b/extension.h @@ -8,7 +8,7 @@ * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more @@ -41,6 +41,14 @@ #include "CDetour/detours.h" #include + +// for string manipulation +#include +#include +#include +#include + + //HalfLife2.h #if defined _WIN32 #define SOURCE_BIN_PREFIX "" @@ -84,7 +92,7 @@ public: * @return True to succeed loading, false to fail. */ virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); - + /** * @brief This is called right before the extension is unloaded. */ diff --git a/smsdk_config.h b/smsdk_config.h index 2a087ff..3aeb412 100644 --- a/smsdk_config.h +++ b/smsdk_config.h @@ -8,7 +8,7 @@ * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more @@ -38,16 +38,16 @@ */ /* Basic information exposed publicly */ -#define SMEXT_CONF_NAME "Console Cleaner" -#define SMEXT_CONF_DESCRIPTION "Console warning suppressor" -#define SMEXT_CONF_VERSION "1.2.0" -#define SMEXT_CONF_AUTHOR "Accelerator, Zephyrus" -#define SMEXT_CONF_URL "https://github.com/Accelerator74/Cleaner" -#define SMEXT_CONF_LOGTAG "Cleaner" -#define SMEXT_CONF_LICENSE "GPLv3" -#define SMEXT_CONF_DATESTRING __DATE__ +#define SMEXT_CONF_NAME "Console Cleaner" +#define SMEXT_CONF_DESCRIPTION "Console warning suppressor" +#define SMEXT_CONF_VERSION "1.2.1" +#define SMEXT_CONF_AUTHOR "Accelerator, Zephyrus" +#define SMEXT_CONF_URL "https://github.com/Accelerator74/Cleaner" +#define SMEXT_CONF_LOGTAG "Cleaner" +#define SMEXT_CONF_LICENSE "GPLv3" +#define SMEXT_CONF_DATESTRING __DATE__ -/** +/** * @brief Exposes plugin's main interface. */ #define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; @@ -56,7 +56,7 @@ * @brief Sets whether or not this plugin required Metamod. * NOTE: Uncomment to enable, comment to disable. */ -//#define SMEXT_CONF_METAMOD +//#define SMEXT_CONF_METAMOD /** Enable interfaces you want to use here by uncommenting lines */ //#define SMEXT_ENABLE_FORWARDSYS @@ -77,5 +77,6 @@ //#define SMEXT_ENABLE_USERMSGS //#define SMEXT_ENABLE_TRANSLATOR //#define SMEXT_ENABLE_NINVOKE +#define SMEXT_ENABLE_ROOTCONSOLEMENU #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ From 73660b64638e8de6307c019ae6a36b6d8bc30862 Mon Sep 17 00:00:00 2001 From: steph Date: Mon, 23 Aug 2021 21:14:50 -0400 Subject: [PATCH 2/3] better prints for errors and logging - tell the user when we don't print their string --- extension.cpp | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/extension.cpp b/extension.cpp index edc62a5..104a2f3 100644 --- a/extension.cpp +++ b/extension.cpp @@ -17,7 +17,8 @@ int g_iStrings = 0; for (int i = 0; i < g_iStrings; ++i) { // make sure we're stripping at least 2 or more chars just in case we accidentally inhale a \0 - if (strlen(g_szStrings[i]) > 1 && strstr(pMessage, g_szStrings[i]) != 0) + // also there's no reason to strip a single char ever + if (strlen(g_szStrings[i]) >= 2 && strstr(pMessage, g_szStrings[i]) != 0) { return LR_CONTINUE; } @@ -30,7 +31,8 @@ int g_iStrings = 0; for (int i = 0; i < g_iStrings; ++i) { // make sure we're stripping at least 2 or more chars just in case we accidentally inhale a \0 - if (strlen(g_szStrings[i]) > 1 && strstr(text, g_szStrings[i]) != 0) + // also there's no reason to strip a single char ever + if (strlen(g_szStrings[i]) >= 2 && strstr(text, g_szStrings[i]) != 0) { return SPEW_CONTINUE; } @@ -42,14 +44,14 @@ int g_iStrings = 0; // https://stackoverflow.com/questions/10178700/c-strip-non-ascii-characters-from-string static bool badChar(char c) { - // everything below space excluding null term and del or above - return (c != 0 && (c < 32 || c > 126)); + // everything below space excluding null term and del or above + return (c != 0 && (c < 32 || c > 126)); } static void stripBadChars(std::string & str) { - // remove all chars matching our "badchar" func - str.erase(remove_if(str.begin(),str.end(), badChar), str.end()); + // remove all chars matching our "badchar" func + str.erase(remove_if(str.begin(),str.end(), badChar), str.end()); } bool Cleaner::SDK_OnLoad(char *error, size_t maxlength, bool late) @@ -67,48 +69,50 @@ bool Cleaner::SDK_OnLoad(char *error, size_t maxlength, bool late) return false; } - // step thru the file char by char and log the number of newlines we have - // this is more or less the number of lines we have - int c, lines = 0; - do + // step thru the file char by char and log the number of lines we have + int lines = 0; + for (int c = fgetc(file); c != EOF; c = fgetc(file)) { - c = fgetc(file); if (c == '\n') { ++lines; } - } while (c != EOF); + } + + rootconsole->ConsolePrint("[CLEANER] %i lines in cleaner.cfg", lines); - rootconsole->ConsolePrint("[CLEANER] %i lines", lines); rewind(file); g_szStrings = new char*[lines]; while (!feof(file)) { + // we don't need to have 256 chars to work with here as most strings are far smaller than that g_szStrings[g_iStrings] = new char[128]; - // fgets stops at n - 1 aka 255 + // fgets stops at n - 1 aka 127 if (fgets(g_szStrings[g_iStrings], 128, file) != NULL) { // make things a little easier on ourselves std::string thisstring = g_szStrings[g_iStrings]; // significantly more robust way of stripping evil chars from our string so we don't crash - stripBadChars( thisstring ); + // when we try to strip them. this includes newlines, control chars, non ascii unicde, etc. + stripBadChars(thisstring); // copy our std::string back to char* + // Disgusting. char* c_thisstring = &thisstring[0]; int len = strlen(c_thisstring); - // don't strip 0 len strings - if (len <= 0) + // don't strip tiny (including 0 len or less) strings + if (len <= 1) { - //rootconsole->ConsolePrint("[CLEANER] Refusing to strip a string with 0 or less length - line %i", g_iStrings ); + rootconsole->ConsolePrint("[CLEANER] Not stripping string on -> L%i with 1 or less length! Length: %i", g_iStrings+1, strlen(c_thisstring)); } else { - rootconsole->ConsolePrint("[CLEANER] Stripping string on line %i: \"%s\" - length = %i", g_iStrings+1, c_thisstring, strlen(c_thisstring)); + rootconsole->ConsolePrint("[CLEANER] Stripping string on -> L%i: \"%s\" - length: %i", g_iStrings+1, c_thisstring, strlen(c_thisstring)); } strcpy(g_szStrings[g_iStrings], c_thisstring); From a8148454bb66da9cd38df0878571524db7a658d6 Mon Sep 17 00:00:00 2001 From: sapphonie Date: Mon, 23 Aug 2021 21:16:38 -0400 Subject: [PATCH 3/3] Update Readme.md --- Readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Readme.md b/Readme.md index c101a4b..81339d6 100644 --- a/Readme.md +++ b/Readme.md @@ -2,3 +2,5 @@ This is an extension for Sourcemod that allows you to strip lines from your console log. Most often different types of spam messages that are normal, but provide no useful info. + +Note: This extension ignores nonprintable or non-ascii unicode characters, as removing them can lead to crashes.