├── .gitignore ├── README.md ├── Textractor.GptApiTranslate ├── README.md ├── img │ ├── config-example.png │ ├── copy-extension.png │ ├── curl-check.png │ ├── example1.png │ └── extension-order.png └── src │ ├── Textractor.GptApiTranslate.sln │ └── Textractor.GptApiTranslate │ ├── Config │ ├── Common.h │ ├── ExtensionConfig.cpp │ └── ExtensionConfig.h │ ├── ExtExecRequirements.h │ ├── Extension.cpp │ ├── Extension.h │ ├── ExtensionDepsContainer.h │ ├── ExtensionImpl.cpp │ ├── History │ ├── MsgHistoryTrack.h │ └── MultiThreadMsgHistoryTrack.h │ ├── Logger.h │ ├── NameMapping │ ├── CharMappings.h │ ├── GenderStrMapper.h │ ├── NameRetriever.h │ ├── ProcessNameRetriever.h │ └── VnIdsRetriever.h │ ├── Network │ ├── GptApiCaller.h │ ├── HttpClient.cpp │ └── HttpClient.h │ ├── Text │ ├── ApiMsgHelper.h │ ├── GptLineParser.h │ ├── GptMsgCreator.h │ ├── GptSysMsgCreator.h │ ├── GptUserMsgCreator.h │ └── TranslationFormat.h │ ├── Textractor.GptApiTranslate.vcxproj │ ├── Textractor.GptApiTranslate.vcxproj.filters │ ├── Threading │ ├── ThreadFilter.h │ ├── ThreadKeyGenerator.h │ └── ThreadTracker.h │ ├── Translator.h │ └── _Libraries │ ├── FileTracker.h │ ├── Locker.h │ ├── curlproc.cpp │ ├── curlproc.h │ ├── datetime.h │ ├── inihandler.cpp │ ├── inihandler.h │ ├── regex │ ├── RE2Regex.h │ ├── Regex.h │ └── StdLibRegex.h │ ├── strhelper.h │ └── winmsg.h ├── Textractor.PythonInterpretter ├── README.md ├── img │ ├── config-example.png │ ├── copy-extension.png │ ├── example1.png │ └── extension-order.png ├── scripts │ ├── JpToRomaji │ │ ├── README.md │ │ ├── jp-to-romaji-script.py │ │ └── requirements.txt │ └── ScriptExample │ │ ├── README.md │ │ └── extension-script-ex.py └── src │ ├── Textractor.PythonInterpretter.sln │ └── Textractor.PythonInterpretter │ ├── ConfigAdjustmentEvents.h │ ├── ExtExecRequirements.h │ ├── Extension.cpp │ ├── Extension.h │ ├── ExtensionConfig.cpp │ ├── ExtensionConfig.h │ ├── ExtensionImpl.cpp │ ├── File │ ├── FileDeleter.h │ ├── FileReader.h │ ├── FileTruncater.h │ └── Writer │ │ ├── FileWriter.h │ │ ├── FireAndForgetFileWriter.h │ │ ├── FstreamFileWriter.h │ │ ├── TruncatableFileWriter.h │ │ └── WinApiFileWriter.h │ ├── KeyValSplitter.h │ ├── Libraries │ ├── FileTracker.h │ ├── Locker.h │ ├── datetime.h │ ├── inihandler.cpp │ ├── inihandler.h │ ├── strhelper.h │ └── winmsg.h │ ├── ScriptCmdStrHandler.h │ ├── ScriptManager.h │ ├── Textractor.PythonInterpretter.vcxproj │ ├── Textractor.PythonInterpretter.vcxproj.filters │ ├── ThreadIdGenerator.h │ ├── containers │ ├── ExtensionDepsContainer.h │ ├── LoggerFactory.h │ └── PythonContainer.h │ ├── environment │ ├── DirectoryCreator.h │ └── EnvironmentVarRetriever.h │ ├── logging │ ├── LoggerBase.h │ ├── LoggerEvents.h │ └── Loggers.h │ └── python │ ├── PathFormatter.h │ ├── PipeManager.h │ ├── ProcessManager.h │ ├── ProcessStateTracker.h │ ├── PythonInitCodeReserve.h │ ├── PythonProcess.h │ ├── PythonThread.h │ ├── WinApiHelper.h │ ├── WinEventHandler.h │ └── pip │ ├── CustomPackageToModuleMapper.h │ ├── PipCmdStrBuilder.h │ ├── PipPackageInstaller.h │ └── RequirementsTxtParser.h ├── Textractor.TextLogger ├── README.md ├── img │ ├── concepts-example.png │ ├── config-example.png │ ├── copy-extension.png │ ├── example1.png │ ├── extension-order1.png │ └── extension-order2.png └── src │ ├── Textractor.TextLogger.sln │ └── Textractor.TextLogger │ ├── ExtExecRequirements.h │ ├── Extension.cpp │ ├── Extension.h │ ├── ExtensionConfig.cpp │ ├── ExtensionConfig.h │ ├── ExtensionDepsContainer.h │ ├── ExtensionImpl.cpp │ ├── File │ ├── DirectoryCreator.h │ ├── FileDeleter.h │ ├── FileReader.h │ ├── FileTruncater.h │ └── Writer │ │ ├── DirCreatorFileWriter.h │ │ ├── FileWriter.h │ │ ├── FireAndForgetFileWriter.h │ │ ├── FstreamFileWriter.h │ │ ├── TruncatableFileWriter.h │ │ └── WinApiFileWriter.h │ ├── LoggerTextHandle.h │ ├── ProcessNameRetriever.h │ ├── TextLogger.h │ ├── Textractor.TextLogger.vcxproj │ ├── Textractor.TextLogger.vcxproj.filters │ ├── Threading │ ├── ThreadFilter.h │ ├── ThreadKeyGenerator.h │ └── ThreadTracker.h │ └── _Libraries │ ├── FileTracker.h │ ├── Locker.h │ ├── datetime.h │ ├── inihandler.cpp │ ├── inihandler.h │ ├── strhelper.h │ └── winmsg.h ├── Textractor.TranslationCache ├── README.md ├── img │ ├── config-example.png │ ├── copy-extension.png │ └── extension-order.png └── src │ ├── Textractor.TranslationCache.Base │ ├── Cache │ │ ├── FileTextMapCache.h │ │ ├── MemoryTextMapCache.h │ │ ├── SharedMemTextMapCache.h │ │ └── TextMapCache.h │ ├── CacheFilePathFormatter.h │ ├── CacheManager.h │ ├── ConfigAdjustmentEvents.h │ ├── ExtExecRequirements.h │ ├── Extension.h │ ├── ExtensionConfig.cpp │ ├── ExtensionConfig.h │ ├── ExtensionDepsContainer.h │ ├── File │ │ ├── FileDeleter.h │ │ ├── FileReader.h │ │ ├── FileTruncater.h │ │ └── Writer │ │ │ ├── FileWriter.h │ │ │ ├── FireAndForgetFileWriter.h │ │ │ ├── FstreamFileWriter.h │ │ │ ├── TruncatableFileWriter.h │ │ │ └── WinApiFileWriter.h │ ├── SharedMemory │ │ ├── SharedMemoryInstance.h │ │ └── SharedMemoryManager.h │ ├── TextFormatter.h │ ├── TextMapper.h │ ├── TextTempStore.h │ ├── Textractor.TranslationCache.Base.vcxproj │ ├── Textractor.TranslationCache.Base.vcxproj.filters │ ├── Threading │ │ ├── ThreadFilter.h │ │ ├── ThreadKeyGenerator.h │ │ └── ThreadTracker.h │ └── _Libraries │ │ ├── FileTracker.h │ │ ├── Locker.h │ │ ├── inihandler.cpp │ │ ├── inihandler.h │ │ ├── strhelper.h │ │ └── winmsg.h │ ├── Textractor.TranslationCache.Read │ ├── Extension.cpp │ ├── ExtensionImpl.cpp │ ├── Textractor.TranslationCache.Read.vcxproj │ └── Textractor.TranslationCache.Read.vcxproj.filters │ ├── Textractor.TranslationCache.Write │ ├── Extension.cpp │ ├── ExtensionImpl.cpp │ ├── Textractor.TranslationCache.Write.vcxproj │ └── Textractor.TranslationCache.Write.vcxproj.filters │ └── Textractor.TranslationCache.sln └── Textractor.VndbCharNameMapper ├── README.md ├── img ├── appname-example.png ├── config-example.png ├── copy-extension.png ├── curl-check.png ├── example1.png ├── extension-order.png └── vnid-tab-example.png └── src ├── Textractor.VndbCharNameMapper.sln └── Textractor.VndbCharNameMapper ├── CharMappingConverter.h ├── Common.h ├── ExtExecRequirements.h ├── Extension.cpp ├── Extension.h ├── ExtensionConfig.cpp ├── ExtensionConfig.h ├── ExtensionDepsContainer.h ├── ExtensionImpl.cpp ├── GenderStrMapper.h ├── HtmlParsers ├── HtmlParser.h ├── RegexVndbHtmlParser.h └── StrFindVndbHtmlParser.h ├── HttpClient.h ├── Libraries ├── FileTracker.h ├── Locker.h ├── curlproc.cpp ├── curlproc.h ├── inihandler.cpp ├── inihandler.h ├── strhelper.h └── winmsg.h ├── NameMapper.h ├── NameMappingManager.h ├── NameRetriever.h ├── ProcessNameRetriever.h ├── Textractor.VndbCharNameMapper.vcxproj ├── Textractor.VndbCharNameMapper.vcxproj.filters └── VnIdsParser.h /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | build/ 14 | [Bb]in/ 15 | [Oo]bj/ 16 | **/.vs/ 17 | **/packages/ 18 | 19 | node_modules/ 20 | package-lock.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Textractor-ExtraExtensions 2 | 3 | This repo provides several useful Textractor extensions created by me, which are not available by default in Textactor. 4 | 5 | [**Textractor**](https://github.com/Artikash/Textractor) is a tool used to extract text from video games and visual novels in real-time, often used to leverage translation tools to read text in other languages. 6 | 7 | 8 | All extension releases can be found [**here**](https://github.com/voidpenguin-28/Textractor-ExtraExtensions/releases). 9 | 10 |
11 | 12 | Here is a list of currently available extensions: 13 | 1. [**GptApiTranslate**](Textractor.GptApiTranslate): Leverages the GPT Completions API to translate text/lines, with a reasonable degree of flexibility in configuration. 14 | 2. [**VndbCharNameMapper**](Textractor.VndbCharNameMapper): Auto-maps character names from Japanese to Romaji using the character database of vndb.org for specified visual novels. 15 | 3. [**TextLogger**](Textractor.TextLogger): Provides the capability to write text from each/any thread/hook to a log file. This essentially allows you to export data/text piped by Textractor. 16 | 4. [**PythonInterpretter**](Textractor.PythonInterpretter): Allows you to write and use python scripts in Textractor. This is essentially the equivalent of a python Textractor extension. Below are python scripts currently available from this repo. 17 | 1. **[Example Script](Textractor.PythonInterpretter/scripts/ScriptExample)**: Merely an example of how to implement a python script compatible with this extension. The code itself merely prepends an incrementing number to the currently processed sentence. 18 | 2. **[JP to Romaji](Textractor.PythonInterpretter/scripts/JpToRomaji)**: Leverages NLP to append the romaji form of the currently processed sentence. 19 | 20 | 5. [**TranslationCache**](Textractor.TranslationCache): Provides an extension-agnostic way to cache real-time translations (to a cache file), to prevent re-processing previously translated lines. Should work with most translation extensions, including "GptApiTranslate". 21 | 22 |
23 | Documentation for each extension is available in their corresponding page in this repo. -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/img/config-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.GptApiTranslate/img/config-example.png -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/img/copy-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.GptApiTranslate/img/copy-extension.png -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/img/curl-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.GptApiTranslate/img/curl-check.png -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/img/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.GptApiTranslate/img/example1.png -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/img/extension-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.GptApiTranslate/img/extension-order.png -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.GptApiTranslate", "Textractor.GptApiTranslate\Textractor.GptApiTranslate.vcxproj", "{9880E765-5EF1-428B-9399-8D1E9AF238B8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Debug|x64.ActiveCfg = Debug|x64 17 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Debug|x64.Build.0 = Debug|x64 18 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Debug|x86.ActiveCfg = Debug|Win32 19 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Debug|x86.Build.0 = Debug|Win32 20 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Release|x64.ActiveCfg = Release|x64 21 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Release|x64.Build.0 = Release|x64 22 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Release|x86.ActiveCfg = Release|Win32 23 | {9880E765-5EF1-428B-9399-8D1E9AF238B8}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2A73130C-D092-4143-A2A5-88293839B3B8} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Config/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | const string GPT_MODEL3_5 = "gpt-3.5-turbo"; 6 | const string GPT_MODEL4 = "gpt-4"; 7 | const string GPT_MODEL4_TURBO = "gpt-4-turbo"; 8 | const string GPT_MODEL4_O = "gpt-4o"; 9 | 10 | //"content": "\n\nHello there, how may I assist you today?", 11 | const string GPT_REQUEST_TEMPLATE = "{\"model\":\"{0}\",\"messages\":[{\"role\":\"system\",\"content\":\"{1}\"},{\"role\":\"user\",\"content\":\"{2}\"}]}"; 12 | const string GPT_RESPONSE_MSG_PATTERN = "\"[Cc]ontent\":\\s{0,}\"((?:\\\\\"|[^\"])*)\""; 13 | const string GPT_ERROR_MSG_PATTERN = "\"[Mm]essage\":\\s{0,}\"((?:\\\\\"|[^\"])*)\""; 14 | const string GPT_HTTP_HEADERS = "Content-Type: application/json | Authorization: Bearer {0}"; 15 | 16 | static constexpr wchar_t ZERO_WIDTH_SPACE = L'\x200b'; 17 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/ExtExecRequirements.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Extension.h" 4 | #include "Config/ExtensionConfig.h" 5 | #include "Threading/ThreadFilter.h" 6 | 7 | 8 | class ExtExecRequirements { 9 | public: 10 | virtual ~ExtExecRequirements() { } 11 | virtual bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 12 | const ExtensionConfig& config, const wstring& text) const = 0; 13 | }; 14 | 15 | 16 | class NoExtExecRequirements : public ExtExecRequirements { 17 | public: 18 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 19 | const ExtensionConfig& config, const wstring& text) const override 20 | { 21 | return true; 22 | } 23 | }; 24 | 25 | 26 | class DefaultExtExecRequirements : public ExtExecRequirements { 27 | public: 28 | DefaultExtExecRequirements(const ThreadFilter& threadFilter) : _threadFilter(threadFilter) { } 29 | 30 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 31 | const ExtensionConfig& config, const wstring& text) const override 32 | { 33 | if (config.disabled) return false; 34 | if (config.activeThreadOnly && !sentInfoWrapper.isActiveThread()) return false; 35 | if (!_threadFilter.isThreadAllowed(sentInfoWrapper, config)) return false; 36 | if (!meetsConsoleAndClipboardRequirements(sentInfoWrapper, config)) return false; 37 | if (config.skipAsciiText && isAllAscii(text)) return false; 38 | 39 | return true; 40 | } 41 | private: 42 | const ThreadFilter& _threadFilter; 43 | 44 | bool meetsConsoleAndClipboardRequirements( 45 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const 46 | { 47 | static const wstring _consoleThreadName = L"Console"; 48 | static const wstring _clipboardThreadName = L"Clipboard"; 49 | wstring threadName = sentInfoWrapper.getThreadNameW(); 50 | 51 | switch (config.skipConsoleAndClipboard) { 52 | case ExtensionConfig::ConsoleClipboardMode::SkipAll: 53 | if (sentInfoWrapper.threadIsConsoleOrClipboard()) return false; 54 | break; 55 | case ExtensionConfig::ConsoleClipboardMode::SkipConsole: 56 | if (threadName == _consoleThreadName) return false; 57 | break; 58 | case ExtensionConfig::ConsoleClipboardMode::SkipClipboard: 59 | if (threadName == _clipboardThreadName) return false; 60 | break; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | bool isAllAscii(const wstring& str) const { 67 | static constexpr int ASCII_END_CODE = 127; 68 | 69 | for (size_t i = 0; i < str.length(); i++) { 70 | if ((int)str[i] > ASCII_END_CODE) return false; 71 | } 72 | 73 | return true; 74 | } 75 | }; 76 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Extension.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "_Libraries/winmsg.h" 3 | #include "Extension.h" 4 | #include "ExtensionDepsContainer.h" 5 | #include 6 | 7 | 8 | void applyTranslationToSentence(wstring& sentence, const wstring& translation); 9 | 10 | ExtensionDepsContainer* _deps = nullptr; 11 | 12 | inline void allocateResources() { 13 | _deps = new DefaultExtensionDepsContainer(); 14 | } 15 | 16 | inline void deallocateResources() { 17 | if(_deps != nullptr) delete _deps; 18 | _deps = nullptr; 19 | } 20 | 21 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 22 | { 23 | switch (ul_reason_for_call) 24 | { 25 | case DLL_PROCESS_ATTACH: 26 | allocateResources(); 27 | _deps->getConfigRetriever().getConfig(true); // initialize ini config for extension if not found 28 | break; 29 | case DLL_PROCESS_DETACH: 30 | deallocateResources(); 31 | break; 32 | } 33 | 34 | return TRUE; 35 | } 36 | 37 | /* 38 | Param sentence: sentence received by Textractor (UTF-16). Can be modified, Textractor will receive this modification only if true is returned. 39 | Param sentenceInfo: contains miscellaneous info about the sentence (see README). 40 | Return value: whether the sentence was modified. 41 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 42 | The sentence will be destroyed if it is empty or if you call Skip(). 43 | This function may be run concurrently with itself: please make sure it's thread safe. 44 | It will not be run concurrently with DllMain. 45 | */ 46 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) 47 | { 48 | try { 49 | SentenceInfoWrapper sentInfoWrapper(sentenceInfo); 50 | wstring translation = _deps->getTranslator().translateW(sentInfoWrapper, sentence); 51 | if (translation.empty()) return false; 52 | 53 | applyTranslationToSentence(sentence, translation); 54 | return true; 55 | } 56 | catch (const exception& ex) { 57 | wstring extId = _deps->getIdentifier(); 58 | showErrorMessage(ex.what(), StrHelper::convertFromW(extId)); 59 | return false; 60 | } 61 | } 62 | 63 | void applyTranslationToSentence(wstring& sentence, const wstring& translation) { 64 | size_t zeroWdSpaceIndex = sentence.rfind(ZERO_WIDTH_SPACE); 65 | 66 | // if a translation already exists in the string, then replace it with the gpt translation 67 | if (zeroWdSpaceIndex != wstring::npos) 68 | sentence = sentence.substr(0, zeroWdSpaceIndex); 69 | 70 | (sentence += ZERO_WIDTH_SPACE) += L" \n"; 71 | sentence += translation; 72 | } 73 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Extension.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include "_Libraries/strhelper.h" 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | struct InfoForExtension 13 | { 14 | const char* name; 15 | int64_t value; 16 | }; 17 | 18 | struct SentenceInfo 19 | { 20 | const InfoForExtension* infoArray; 21 | int64_t operator[](std::string propertyName) 22 | { 23 | for (auto info = infoArray; info->name; ++info) // nullptr name marks end of info array 24 | if (propertyName == info->name) return info->value; 25 | return *(int*)0xcccc = 0; // gives better error message than alternatives 26 | } 27 | }; 28 | 29 | struct SKIP {}; 30 | inline void Skip() { throw SKIP(); } 31 | 32 | 33 | 34 | class SentenceInfoWrapper { 35 | public: 36 | SentenceInfoWrapper(SentenceInfo& sentenceInfo) : _sentenceInfo(sentenceInfo) { } 37 | 38 | bool isActiveThread() { 39 | return getCurrentSelect(); 40 | } 41 | 42 | bool threadIsConsoleOrClipboard() { 43 | return getProcessId() == 0; 44 | } 45 | 46 | int64_t getCurrentSelect() { 47 | return _sentenceInfo["current select"]; 48 | } 49 | 50 | wstring getProcessIdW() { 51 | return to_wstring(getProcessId()); 52 | } 53 | 54 | DWORD getProcessIdD() { 55 | return static_cast(getProcessId()); 56 | } 57 | 58 | int64_t getProcessId() { 59 | return _sentenceInfo["process id"]; 60 | } 61 | 62 | wstring getThreadNumberW() { 63 | int64_t threadNum = getThreadNumber(); 64 | return to_wstring(threadNum); 65 | } 66 | 67 | int64_t getThreadNumber() { 68 | return _sentenceInfo["text number"]; 69 | } 70 | 71 | string getThreadName() { 72 | wstring threadNameW = getThreadNameW(); 73 | return StrHelper::convertFromW(threadNameW); 74 | } 75 | 76 | wstring getThreadNameW() { 77 | int64_t threadNamePtr = _sentenceInfo["text name"]; 78 | return wstring(reinterpret_cast(threadNamePtr)); 79 | } 80 | private: 81 | SentenceInfo _sentenceInfo; 82 | }; 83 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | 23 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 24 | { 25 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 26 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 27 | } 28 | } 29 | catch (SKIP) 30 | { 31 | *sentence = L'\0'; 32 | } 33 | return sentence; 34 | } -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/History/MsgHistoryTrack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../_Libraries/Locker.h" 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | class MsgHistoryTracker { 11 | public: 12 | virtual ~MsgHistoryTracker() { } 13 | virtual vector getFromHistory(int numHistory) const = 0; 14 | virtual void addToHistory(wstring str) = 0; 15 | }; 16 | 17 | 18 | class MapMsgHistoryTracker : public MsgHistoryTracker { 19 | public: 20 | static constexpr long MAX_HISTORY_SIZE = 20; 21 | 22 | vector getFromHistory(int numHistory) const override { 23 | vector history; 24 | 25 | _locker.lock([this, numHistory, &history]() { 26 | history = getFromHistoryBase(numHistory); 27 | }); 28 | 29 | return history; 30 | } 31 | 32 | void addToHistory(wstring str) override { 33 | _locker.lock([this, &str]() { 34 | addToHistoryBase(str); 35 | }); 36 | } 37 | 38 | private: 39 | mutable BasicLocker _locker; 40 | unordered_map _msgHistory = { }; 41 | long _firstMsgIndex = 0, _lastMsgIndex = -1; 42 | 43 | vector getFromHistoryBase(int numHistory) const { 44 | vector subHistory; 45 | long start = max((_lastMsgIndex - numHistory) + 1, _firstMsgIndex); 46 | 47 | for (long i = start; i <= _lastMsgIndex; i++) { 48 | subHistory.push_back(_msgHistory.at(i)); 49 | } 50 | 51 | return subHistory; 52 | } 53 | 54 | void addToHistoryBase(wstring str) { 55 | _msgHistory[++_lastMsgIndex] = str; 56 | deleteFromHistory(); 57 | } 58 | 59 | void deleteFromHistory(long maxHistorySize = MAX_HISTORY_SIZE) { 60 | while (historyMaxed(maxHistorySize)) _msgHistory.erase(_firstMsgIndex++); 61 | } 62 | 63 | bool historyMaxed(long maxHistorySize = MAX_HISTORY_SIZE) const { 64 | return _lastMsgIndex - _firstMsgIndex > maxHistorySize; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/History/MultiThreadMsgHistoryTrack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Extension.h" 3 | #include "../_Libraries/Locker.h" 4 | #include "../Threading/ThreadKeyGenerator.h" 5 | #include "../Threading/ThreadTracker.h" 6 | #include "MsgHistoryTrack.h" 7 | #include 8 | #include 9 | 10 | 11 | class MultiThreadMsgHistoryTracker { 12 | public: 13 | virtual ~MultiThreadMsgHistoryTracker() { } 14 | 15 | virtual vector getFromHistory(SentenceInfoWrapper& sentInfoWrapper, int numHistory) = 0; 16 | virtual void addToHistory(SentenceInfoWrapper& sentInfoWrapper, wstring str) = 0; 17 | }; 18 | 19 | class DefaultMultiThreadMsgHistoryTracker : public MultiThreadMsgHistoryTracker { 20 | public: 21 | DefaultMultiThreadMsgHistoryTracker(const ThreadKeyGenerator& keyGenerator, 22 | ThreadTracker& threadTracker, const function histTrackerGenerator) 23 | : _keyGenerator(keyGenerator), _threadTracker(threadTracker), 24 | _histTrackerGenerator(histTrackerGenerator) { } 25 | 26 | vector getFromHistory(SentenceInfoWrapper& sentInfoWrapper, int numHistory) override { 27 | shared_ptr histTracker = getHistTracker(sentInfoWrapper); 28 | return histTracker->getFromHistory(numHistory); 29 | } 30 | 31 | void addToHistory(SentenceInfoWrapper& sentInfoWrapper, wstring str) override { 32 | shared_ptr histTracker = getHistTracker(sentInfoWrapper); 33 | return histTracker->addToHistory(str); 34 | } 35 | private: 36 | const ThreadKeyGenerator& _keyGenerator; 37 | ThreadTracker& _threadTracker; 38 | const function _histTrackerGenerator; 39 | unordered_map> _trackerMap; 40 | mutable BasicLocker _locker; 41 | 42 | wstring getThreadKey(SentenceInfoWrapper& sentInfoWrapper) const { 43 | size_t threadIndex = _threadTracker.trackThreadNameIndex(sentInfoWrapper); 44 | wstring threadKey = _keyGenerator.getThreadKey(threadIndex, sentInfoWrapper); 45 | return threadKey; 46 | } 47 | 48 | shared_ptr getHistTracker(SentenceInfoWrapper& sentInfoWrapper) { 49 | wstring threadKey = getThreadKey(sentInfoWrapper); 50 | return getHistTracker(threadKey); 51 | } 52 | 53 | shared_ptr getHistTracker(const wstring& threadKey) { 54 | shared_ptr trackerPtr = nullptr; 55 | 56 | _locker.lock([this, &threadKey, &trackerPtr]() { 57 | addHistTrackerIfNotExist(threadKey); 58 | trackerPtr = _trackerMap[threadKey]; 59 | }); 60 | 61 | return trackerPtr; 62 | } 63 | 64 | void addHistTrackerIfNotExist(const wstring& threadKey) { 65 | if (mapHasKey(threadKey)) return; 66 | 67 | auto tracker = shared_ptr(_histTrackerGenerator()); 68 | _trackerMap[threadKey] = tracker; 69 | } 70 | 71 | bool mapHasKey(const wstring& threadKey) const { 72 | return _trackerMap.find(threadKey) != _trackerMap.end(); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Logger.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "_Libraries/datetime.h" 4 | #include "_Libraries/Locker.h" 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class Logger { 11 | public: 12 | enum Level { Debug, Info, Warning, Error, Fatal }; 13 | Logger(const Level minLogLevel = Level::Debug) : _minLogLevel(minLogLevel) { } 14 | virtual ~Logger() { } 15 | 16 | virtual void logDebug(const string& msg) { 17 | log(Level::Debug, msg); 18 | } 19 | virtual void logInfo(const string& msg) { 20 | log(Level::Info, msg); 21 | } 22 | virtual void logWarning(const string& msg) { 23 | log(Level::Warning, msg); 24 | } 25 | virtual void logError(const string& msg) { 26 | log(Level::Error, msg); 27 | } 28 | virtual void logFatal(const string& msg) { 29 | log(Level::Fatal, msg); 30 | } 31 | 32 | virtual void log(const Level logLevel, const string& msg) const { 33 | if (logLevel < _minLogLevel) return; 34 | 35 | string fullMsg = createLogMsg(logLevel, msg); 36 | writeToLog(fullMsg); 37 | } 38 | 39 | virtual void setMinLogLevel(const Level minLogLevel) { 40 | _minLogLevel = minLogLevel; 41 | } 42 | protected: 43 | Level _minLogLevel; 44 | 45 | virtual void writeToLog(const string& msg) const = 0; 46 | 47 | virtual string createLogMsg(const Level logLevel, const string& baseMsg) const { 48 | string levelStr = toStr(logLevel); 49 | string msg = "[" + getCurrentDateTime() + "] [" + levelStr + "] " + baseMsg; 50 | return msg; 51 | } 52 | 53 | virtual string toStr(Level level) const { 54 | switch (level) { 55 | case Level::Debug: 56 | return "DEBUG"; 57 | case Level::Info: 58 | return "INFO"; 59 | case Level::Warning: 60 | return "WARN"; 61 | case Level::Error: 62 | return "ERROR"; 63 | case Level::Fatal: 64 | return "FATAL"; 65 | default: 66 | return "DEBUG"; 67 | } 68 | } 69 | }; 70 | 71 | class NoLogger : public Logger { 72 | public: 73 | void logDebug(const string& msg) const { } 74 | void logInfo(const string& msg) const { } 75 | void logWarning(const string& msg) const { } 76 | void logError(const string& msg) const { } 77 | void logFatal(const string& msg) const { } 78 | void log(const Level level, const string& msg) const { } 79 | }; 80 | 81 | 82 | class FileLogger : public Logger { 83 | public: 84 | FileLogger(const string& logFilePath, Level minLogLevel = Level::Debug) 85 | : Logger(minLogLevel), _logFilePath(logFilePath) { } 86 | 87 | protected: 88 | string _logFilePath; 89 | mutable BasicLocker _locker; 90 | 91 | void writeToLog(const string& msg) const { 92 | _locker.lock([this, &msg]() { 93 | ofstream file(_logFilePath, ios_base::app); 94 | file << msg << endl; 95 | file.close(); 96 | }); 97 | } 98 | }; 99 | 100 | 101 | class COutLogger : public Logger { 102 | public: 103 | COutLogger(Level minLogLevel = Level::Debug) : Logger(minLogLevel) { } 104 | 105 | protected: 106 | void writeToLog(const string& msg) const { 107 | cout << msg << endl; 108 | } 109 | }; -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/NameMapping/CharMappings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | enum class Gender { Unknown = 0, Male, Female }; 8 | 9 | template using templ_map = unordered_map; 10 | typedef templ_map wstring_map; 11 | typedef templ_map gender_map; 12 | 13 | 14 | struct CharMappings { 15 | wstring_map fullNameMap; 16 | wstring_map singleNameMap; 17 | gender_map genderMap; 18 | 19 | CharMappings(wstring_map fullNameMap_ = {}, wstring_map singleNameMap_ = {}, gender_map genderMap_ = {}) 20 | : fullNameMap(fullNameMap_), singleNameMap(singleNameMap_), genderMap(genderMap_) { } 21 | }; 22 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/NameMapping/GenderStrMapper.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "CharMappings.h" 4 | 5 | class GenderStrMapper { 6 | public: 7 | virtual ~GenderStrMapper() { } 8 | virtual wstring map(Gender gender) const = 0; 9 | virtual Gender map(wstring gender) const = 0; 10 | }; 11 | 12 | 13 | class DefaultGenderStrMapper : public GenderStrMapper { 14 | public: 15 | wstring map(Gender gender) const { 16 | switch (gender) { 17 | case Gender::Male: 18 | return L"M"; 19 | case Gender::Female: 20 | return L"F"; 21 | default: 22 | return L"U"; 23 | } 24 | } 25 | 26 | Gender map(wstring gender) const { 27 | if (gender == L"M") 28 | return Gender::Male; 29 | else if (gender == L"F") 30 | return Gender::Female; 31 | else 32 | return Gender::Unknown; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/NameMapping/ProcessNameRetriever.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | class ProcessNameRetriever { 10 | public: 11 | virtual ~ProcessNameRetriever() { } 12 | virtual wstring getProcessName(DWORD pid) const = 0; 13 | }; 14 | 15 | class WinApiProcessNameRetriever : public ProcessNameRetriever { 16 | public: 17 | wstring getProcessName(DWORD pid) const override { 18 | HANDLE hProcess = GetProcessHandle(pid); 19 | 20 | if (isInvalidHandle(hProcess)) { 21 | cerr << "Error opening process. Error code: " << GetLastError() << endl; 22 | return L""; 23 | } 24 | 25 | wstring processNameW = getProcessName(hProcess); 26 | CloseHandle(hProcess); 27 | return processNameW; 28 | } 29 | private: 30 | static constexpr wchar_t PERIOD_CH = L'.'; 31 | 32 | HANDLE GetProcessHandle(DWORD pid) const { 33 | return OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); 34 | } 35 | 36 | bool isInvalidHandle(HANDLE handle) const { 37 | return handle == nullptr || handle == INVALID_HANDLE_VALUE; 38 | } 39 | 40 | wstring getProcessName(HANDLE handle) const { 41 | TCHAR szProcessName[MAX_PATH] = TEXT(""); 42 | 43 | if (!GetModuleBaseName(handle, nullptr, szProcessName, sizeof(szProcessName) / sizeof(TCHAR))) { 44 | cerr << "Error getting process name. Error code: " << GetLastError() << endl; 45 | return L""; 46 | } 47 | 48 | wstring processName = wstring(szProcessName); 49 | return formatProcessName(processName); 50 | } 51 | 52 | wstring formatProcessName(wstring processName) const { 53 | size_t periodIndex = processName.rfind(PERIOD_CH); 54 | if (periodIndex != wstring::npos) { 55 | processName = processName.substr(0, periodIndex); 56 | } 57 | 58 | return processName; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Network/GptApiCaller.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../Config/ExtensionConfig.h" 4 | #include "../Text/ApiMsgHelper.h" 5 | #include "../Logger.h" 6 | #include "HttpClient.h" 7 | #include 8 | using namespace std; 9 | 10 | 11 | class GptApiCaller { 12 | public: 13 | virtual ~GptApiCaller() { } 14 | 15 | virtual pair callCompletionApi(const string& model, 16 | const string& sysMsg, const string& userMsg, bool contentOnly = true) const = 0; 17 | }; 18 | 19 | 20 | class DefaultGptApiCaller : public GptApiCaller { 21 | public: 22 | DefaultGptApiCaller(HttpClient& httpClient, const Logger& logger, const ApiMsgHelper& msgHelper) 23 | : _httpClient(httpClient), _logger(logger), _msgHelper(msgHelper) { } 24 | 25 | pair callCompletionApi(const string& model, 26 | const string& sysMsg, const string& userMsg, bool contentOnly) const override 27 | { 28 | GptConfig config = _msgHelper.getConfig(); 29 | 30 | try { 31 | string request = _msgHelper.createRequestMsg(sysMsg, userMsg); 32 | 33 | pair output = callCompletionApi(config, request); 34 | string& response = output.second; 35 | bool msgError, httpError = output.first; 36 | string parsedResponse = _msgHelper.parseMessageFromResponse(response, msgError); 37 | 38 | bool anyError = httpError || msgError; 39 | if (config.logRequest) writeToLog(request, response, anyError); 40 | if (contentOnly) response = parsedResponse; 41 | return pair(anyError, response); 42 | } 43 | catch (const exception& ex) { 44 | if (config.logRequest) writeToLog(sysMsg + '\n' + userMsg, ex.what(), true); 45 | throw; 46 | } 47 | } 48 | private: 49 | static const string _logFileName; 50 | HttpClient& _httpClient; 51 | const Logger& _logger; 52 | const ApiMsgHelper& _msgHelper; 53 | 54 | pair callCompletionApi(const GptConfig& config, const string& request) const { 55 | static const function callRetryCondition = 56 | [this](const string& r) { return _msgHelper.hasProcessingError(r); }; 57 | 58 | string response; 59 | bool httpError; 60 | 61 | try { 62 | response = _httpClient.httpPost(config.url, request, 63 | config.httpHeaders, config.timeoutSecs, config.numRetries, callRetryCondition); 64 | } 65 | catch (const exception& ex) { 66 | response = ex.what(); 67 | httpError = true; 68 | } 69 | 70 | return pair(httpError, response); 71 | } 72 | 73 | void writeToLog(const string& request, const string& response, bool error) const { 74 | string msg = request + "\n" + response + "\n"; 75 | Logger::Level logLevel = error ? Logger::Error : Logger::Info; 76 | 77 | _logger.log(logLevel, msg); 78 | } 79 | 80 | }; 81 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Network/HttpClient.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "HttpClient.h" 3 | 4 | BasicLocker LibCurlHttpClient::_instanceLocker; 5 | int LibCurlHttpClient::_instances = 0; 6 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Text/GptLineParser.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../_Libraries/strhelper.h" 4 | #include 5 | 6 | 7 | class GptLineParser { 8 | public: 9 | virtual ~GptLineParser() { } 10 | virtual wstring parseLastLine(const wstring& response) const = 0; 11 | }; 12 | 13 | 14 | class DefaultGptLineParser : public GptLineParser { 15 | public: 16 | wstring parseLastLine(const wstring& response) const override { 17 | size_t startIndex = response.length(), newStartIndex; 18 | 19 | do { 20 | startIndex = response.rfind(L'\n', startIndex - 1); 21 | 22 | if (startIndex == wstring::npos) { 23 | startIndex = 0; 24 | if (!isTransLineStart(response, startIndex, newStartIndex)) 25 | newStartIndex = startIndex; 26 | 27 | break; 28 | } 29 | } while (!isTransLineStart(response, startIndex + 1, newStartIndex)); 30 | 31 | return response.substr(newStartIndex); 32 | } 33 | private: 34 | bool isTransLineStart(const wstring& str, size_t startIndex, size_t& newStartIndex) const { 35 | static const unordered_set _seps{ L':', L'.' }; 36 | newStartIndex = wstring::npos; 37 | int i = 0; 38 | while (startIndex + i < str.length() && isdigit(str[startIndex + i])) i++; 39 | 40 | if (i == 0 || startIndex + i >= str.length() - 1) return false; 41 | if (_seps.find(str[startIndex + i]) == _seps.end()) return false; 42 | if (str[startIndex + ++i] != L' ') return false; 43 | 44 | newStartIndex = startIndex + i + 1; 45 | return true; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Text/GptMsgCreator.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../_Libraries/strhelper.h" 4 | #include "../Extension.h" 5 | #include "../Config/ExtensionConfig.h" 6 | #include 7 | 8 | 9 | class GptMsgCreator { 10 | public: 11 | virtual ~GptMsgCreator() { } 12 | virtual wstring createMsg(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) = 0; 13 | }; 14 | 15 | 16 | class MultiGptMsgCreator : public GptMsgCreator { 17 | public: 18 | MultiGptMsgCreator(const vector>& msgCreators) 19 | : _msgCreators(msgCreators) { } 20 | 21 | wstring createMsg(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) override { 22 | wstring userMsg = L"", currMsg; 23 | 24 | for (auto& creator : _msgCreators) { 25 | currMsg = creator.get().createMsg(config, sentInfoWrapper); 26 | if (!currMsg.empty()) userMsg += currMsg + NEW_LINE; 27 | } 28 | 29 | return StrHelper::rtrim(userMsg, NEW_LINE); 30 | } 31 | private: 32 | const wstring NEW_LINE = L"\n"; 33 | vector> _msgCreators; 34 | }; 35 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Text/GptUserMsgCreator.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "GptMsgCreator.h" 4 | #include "../History/MultiThreadMsgHistoryTrack.h" 5 | 6 | 7 | class DefaultUserGptMsgCreator : public GptMsgCreator { 8 | public: 9 | wstring createMsg(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) override { 10 | return config.userMsgPrefix; 11 | } 12 | }; 13 | 14 | class MsgHistoryUserGptMsgCreator : public GptMsgCreator { 15 | public: 16 | MsgHistoryUserGptMsgCreator(MultiThreadMsgHistoryTracker& msgHistTracker) 17 | : _msgHistTracker(msgHistTracker) { } 18 | 19 | wstring createMsg(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) override { 20 | int msgHistCount = !config.useHistoryForNonActiveThreads && !sentInfoWrapper.isActiveThread() ? 0 : config.msgHistoryCount; 21 | vector msgHist = _msgHistTracker.getFromHistory(sentInfoWrapper, msgHistCount + 1); 22 | return createMsgFromHistory(msgHist, config.msgCharLimit, config.historySoftCharLimit); 23 | } 24 | private: 25 | const wstring LINE_SEP = L": "; 26 | MultiThreadMsgHistoryTracker& _msgHistTracker; 27 | 28 | wstring createMsgFromHistory(const vector& msgHist, int msgCharLimit, int histSoftCharLimit) { 29 | wstring finalMsg = L""; 30 | wstring currMsg; 31 | int msgLen, msgHistLen = 0, msgChLimit = histSoftCharLimit; 32 | int msgPrefix = 99, start = ((int)msgHist.size()) - 1; 33 | 34 | for (int i = start; i >= 0; i--, msgPrefix--) { 35 | currMsg = StrHelper::rtruncate(msgHist[i], msgCharLimit); 36 | 37 | if (msgChLimit > 0) { 38 | msgLen = (int)currMsg.length(); 39 | if (i < start && (msgHistLen + msgLen) > msgChLimit) break; 40 | msgHistLen += msgLen; 41 | } 42 | 43 | finalMsg = to_wstring(msgPrefix) + LINE_SEP + currMsg + L"\n" + finalMsg; 44 | } 45 | 46 | return StrHelper::rtrim(finalMsg, L"\n"); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Text/TranslationFormat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class TranslationFormatter { 8 | public: 9 | virtual ~TranslationFormatter() { } 10 | virtual wstring formatJp(wstring jpSent) const = 0; 11 | virtual wstring formatTranslation(wstring translation) const = 0; 12 | }; 13 | 14 | class DefaultTranslationFormatter : public TranslationFormatter { 15 | public: 16 | wstring formatJp(wstring jpSent) const override { 17 | for (const pair& qtMrks : JP_QUOTE_MARKS) { 18 | if (contains(jpSent, qtMrks.first) && !contains(jpSent, qtMrks.second)) 19 | jpSent += qtMrks.second; 20 | else if (contains(jpSent, qtMrks.second) && !contains(jpSent, qtMrks.first)) 21 | jpSent = qtMrks.first + jpSent; 22 | } 23 | 24 | return jpSent; 25 | } 26 | 27 | wstring formatTranslation(wstring translation) const override { 28 | if (translation.empty()) return translation; 29 | 30 | // ensure jp quote marks are placed with english equivalent " 31 | translation = jpToEnQuoteMarks(translation); 32 | 33 | size_t quotIndex = translation.find(QUOT_CH); 34 | 35 | if (between(quotIndex, 0) && translation[translation.length() - 1] == QUOT_CH) { 36 | // ensure a space exists before dialogue line starts 37 | if (translation[quotIndex - 1] != SPACE_CH) 38 | translation = translation.insert(quotIndex++, 1, SPACE_CH); 39 | 40 | // ensure that speaker name before dialogue line is proceeded by a ':' 41 | size_t spaceIndex = quotIndex - 1; 42 | if (between(spaceIndex, 2, 12, false) && !isSpaceOrPunct(translation[spaceIndex - 1])) 43 | translation = translation.insert(spaceIndex, 1, COLON_CH); 44 | } 45 | 46 | return translation; 47 | } 48 | private: 49 | static constexpr wchar_t QUOT_CH = L'\"'; 50 | static constexpr wchar_t SPACE_CH = L' '; 51 | static constexpr wchar_t COLON_CH = L':'; 52 | #pragma warning(suppress: 4566) 53 | const vector> JP_QUOTE_MARKS = { 54 | pair(L"「", L"」"), 55 | pair(L"『", L"』") 56 | }; 57 | 58 | bool contains(const wstring& str, const wstring substr) const { 59 | return str.find(substr) != wstring::npos; 60 | } 61 | 62 | wstring jpToEnQuoteMarks(wstring text) const { 63 | static wstring quoteChStr = wstring(1, QUOT_CH); 64 | 65 | for (const pair& qtMrks : JP_QUOTE_MARKS) { 66 | text = StrHelper::replace(text, qtMrks.first, quoteChStr); 67 | text = StrHelper::replace(text, qtMrks.second, quoteChStr); 68 | } 69 | 70 | return text; 71 | } 72 | 73 | bool between(size_t i, size_t atLeast, size_t atMost = wstring::npos, bool exclusive = true) const { 74 | return exclusive ? 75 | i > atLeast && i < atMost : 76 | i >= atLeast && i <= atMost; 77 | } 78 | 79 | bool isSpaceOrPunct(wchar_t c) const { 80 | return isspace(c) || ispunct(c); 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Threading/ThreadFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include "../Config/ExtensionConfig.h" 5 | #include "ThreadKeyGenerator.h" 6 | #include "ThreadTracker.h" 7 | using FilterMode = ExtensionConfig::FilterMode; 8 | 9 | 10 | class ThreadFilter { 11 | public: 12 | virtual ~ThreadFilter() { } 13 | virtual bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 14 | }; 15 | 16 | 17 | class NoThreadFilter : public ThreadFilter { 18 | public: 19 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 20 | const ExtensionConfig& config) const override { 21 | return true; 22 | } 23 | }; 24 | 25 | class AllThreadFilter : public ThreadFilter { 26 | public: 27 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 28 | const ExtensionConfig& config) const override { 29 | return false; 30 | } 31 | }; 32 | 33 | 34 | class DefaultThreadFilter : public ThreadFilter { 35 | public: 36 | DefaultThreadFilter(const ThreadKeyGenerator& keyGenerator, ThreadTracker& threadTracker) 37 | : _keyGenerator(keyGenerator), _threadTracker(threadTracker) { } 38 | 39 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 40 | const ExtensionConfig& config) const override 41 | { 42 | size_t threadIndex = _threadTracker.trackThreadNameIndex(sentInfoWrapper); 43 | wstring threadKey = _keyGenerator.getThreadKey(threadIndex, sentInfoWrapper); 44 | wstring threadName = sentInfoWrapper.getThreadNameW(); 45 | 46 | switch (config.threadKeyFilterMode) { 47 | case FilterMode::Blacklist: 48 | return isInList(threadKey, threadName, config) == false; 49 | case FilterMode::Whitelist: 50 | return isInList(threadKey, threadName, config) == true; 51 | default: 52 | return true; 53 | } 54 | } 55 | private: 56 | const ThreadKeyGenerator& _keyGenerator; 57 | ThreadTracker& _threadTracker; 58 | 59 | bool isInList(const wstring& threadKey, 60 | const wstring& threadName, const ExtensionConfig& config) const 61 | { 62 | if (isInList(config.threadKeyFilterList, threadKey, config.threadKeyFilterListDelim)) return true; 63 | if (isInList(config.threadKeyFilterList, threadName, config.threadKeyFilterListDelim)) return true; 64 | 65 | return false; 66 | } 67 | 68 | bool isInList(const wstring& list, const wstring& subStr, const wstring& delim) const { 69 | if (subStr.length() > list.length()) return false; 70 | wstring searchStr = subStr + delim; 71 | size_t index = list.find(searchStr); 72 | if (index != wstring::npos) return true; 73 | 74 | index = list.rfind(subStr); 75 | if (index == list.length() - subStr.length()) return true; 76 | 77 | return false; 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Threading/ThreadKeyGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include 5 | 6 | class ThreadKeyGenerator { 7 | public: 8 | virtual ~ThreadKeyGenerator() { } 9 | virtual wstring getThreadKey(size_t threadIndex, SentenceInfoWrapper& sentInfoWrapper) const = 0; 10 | }; 11 | 12 | 13 | class DefaultThreadKeyGenerator : public ThreadKeyGenerator { 14 | public: 15 | wstring getThreadKey(size_t threadIndex, SentenceInfoWrapper& sentInfoWrapper) const override { 16 | wstring threadKey = sentInfoWrapper.getThreadNameW() + L"-" + to_wstring(threadIndex); 17 | return threadKey; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/Threading/ThreadTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../_Libraries/Locker.h" 4 | #include "../Extension.h" 5 | #include 6 | using namespace std; 7 | 8 | 9 | class ThreadTracker { 10 | public: 11 | virtual ~ThreadTracker() { } 12 | virtual size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) = 0; 13 | }; 14 | 15 | 16 | class MapThreadTracker : public ThreadTracker { 17 | public: 18 | size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) override { 19 | wstring threadName, threadId = createThreadId(sentInfoWrap, threadName); 20 | return trackThreadNameIndexBase(threadId, threadName); 21 | } 22 | private: 23 | const wstring THREAD_ID_DELIM = L":"; 24 | unordered_map _threadNameMap = { }; 25 | unordered_map _threadIdMap = { }; 26 | mutable DefaultLockerMap _lockerMap; 27 | 28 | size_t trackThreadNameIndexBase(const wstring& threadId, const wstring& threadName) { 29 | size_t index = 0; 30 | 31 | _lockerMap.getOrCreateLocker(threadId).lock([this, &threadId, &threadName, &index]() { 32 | if (!mapHasThreadId(threadId)) 33 | _threadIdMap[threadId] = addOrUpdateThreadNameMap(threadName); 34 | 35 | index = _threadIdMap[threadId]; 36 | }); 37 | 38 | return index; 39 | } 40 | 41 | wstring createThreadId(SentenceInfoWrapper& sentInfoWrap, wstring& threadNameOut) const { 42 | wstring processId = sentInfoWrap.getProcessIdW(); 43 | threadNameOut = sentInfoWrap.getThreadNameW(); 44 | wstring threadNum = sentInfoWrap.getThreadNumberW(); 45 | wstring delim = THREAD_ID_DELIM; 46 | 47 | wstring threadId = processId + delim + threadNameOut + delim + threadNum; 48 | return threadId; 49 | } 50 | 51 | bool mapHasThreadName(const wstring& threadName) const { 52 | return mapHasKey(_threadNameMap, threadName); 53 | } 54 | 55 | bool mapHasThreadId(const wstring& threadId) const { 56 | return mapHasKey(_threadIdMap, threadId); 57 | } 58 | 59 | bool mapHasKey(const unordered_map& map, const wstring& key) const { 60 | return map.find(key) != map.end(); 61 | } 62 | 63 | size_t addOrUpdateThreadNameMap(const wstring& threadName) { 64 | if (!mapHasThreadName(threadName)) _threadNameMap[threadName] = 1; 65 | else _threadNameMap[threadName]++; 66 | 67 | return _threadNameMap[threadName]; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/_Libraries/FileTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class FileTracker { 10 | public: 11 | virtual ~FileTracker() { } 12 | virtual int64_t getDateLastModifiedEpochs(const string& filePath) = 0; 13 | virtual int64_t getDateLastModifiedEpochs(const char* filePath) = 0; 14 | virtual int64_t getDateLastModifiedEpochs(const wstring& filePath) = 0; 15 | virtual int64_t getDateLastModifiedEpochs(const wchar_t* filePath) = 0; 16 | }; 17 | 18 | 19 | class WinApiFileTracker : public FileTracker { 20 | public: 21 | int64_t getDateLastModifiedEpochs(const string& filePath) override { 22 | return getDateLastModifiedEpochs(StrHelper::convertToW(filePath)); 23 | } 24 | 25 | int64_t getDateLastModifiedEpochs(const char* filePath) override { 26 | return getDateLastModifiedEpochs(string(filePath)); 27 | } 28 | 29 | int64_t getDateLastModifiedEpochs(const wstring& filePath) override { 30 | return getDateLastModifiedEpochs(filePath.c_str()); 31 | } 32 | 33 | int64_t getDateLastModifiedEpochs(const wchar_t* filePath) override { 34 | HANDLE fHandle = getFileHandle(filePath); 35 | if (!isValidHandle(fHandle)) return 0; 36 | 37 | FILETIME lastWrite = getFileLastWriteTime(fHandle); 38 | CloseHandle(fHandle); 39 | 40 | return convertTo64(lastWrite); 41 | } 42 | private: 43 | HANDLE getFileHandle(const wchar_t* filePath) { 44 | return CreateFile(filePath, GENERIC_READ, 45 | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); 46 | } 47 | 48 | bool isValidHandle(const HANDLE& handle) { 49 | return handle != INVALID_HANDLE_VALUE; 50 | } 51 | 52 | FILETIME getFileLastWriteTime(const HANDLE& handle) { 53 | FILETIME lastWrite; 54 | GetFileTime(handle, NULL, NULL, &lastWrite); 55 | return lastWrite; 56 | } 57 | 58 | int64_t convertTo64(FILETIME fTime) { 59 | ULARGE_INTEGER ularge{}; 60 | ularge.LowPart = fTime.dwLowDateTime; 61 | ularge.HighPart = fTime.dwHighDateTime; 62 | return static_cast(ularge.QuadPart); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/_Libraries/curlproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace curlproc { 8 | const string DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"; 9 | 10 | string httpGet(const string& url, const vector& headers = vector(), int connectTimeoutSecs = 10, const string& userAgent = DEFAULT_USER_AGENT, const string& customCurlPath = ""); 11 | string httpPost(const string& url, const string& body, const vector& headers = vector(), int connectTimeoutSecs = 10, const string& userAgent = DEFAULT_USER_AGENT, const string& customCurlPath = ""); 12 | } 13 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/_Libraries/datetime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | inline std::string getCurrentDateTime() { 7 | auto currentTime = std::chrono::system_clock::now(); 8 | time_t currentTime_t = std::chrono::system_clock::to_time_t(currentTime); 9 | 10 | struct tm currentTime_tm; 11 | localtime_s(¤tTime_tm, ¤tTime_t); 12 | 13 | char buffer[80]; 14 | strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ¤tTime_tm); 15 | return std::string(buffer); 16 | } 17 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/_Libraries/regex/StdLibRegex.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Regex.h" 4 | #include 5 | 6 | 7 | class StdLibRegex : public Regex { 8 | public: 9 | StdLibRegex(const string& pattern) : Regex(pattern, "$"), _regex(regex(pattern)) { } 10 | 11 | bool isMatch(const string& str) override { 12 | return regex_match(str, _regex); 13 | } 14 | 15 | string findMatch(const string& str) override { 16 | smatch match; 17 | return regex_search(str, match, _regex) ? match.str() : ""; 18 | } 19 | 20 | vector findMatchCaptures(const string& str) override { 21 | vector groups{}; 22 | smatch match; 23 | if (!regex_search(str, match, _regex)) return vector{}; 24 | 25 | for (const auto& group : match) { 26 | groups.push_back(group.str()); 27 | } 28 | 29 | return groups; 30 | } 31 | 32 | vector findMatches(const string& str) override { 33 | vector matches{}; 34 | sregex_iterator iter(str.begin(), str.end(), _regex); 35 | sregex_iterator end; 36 | 37 | while (iter != end) { 38 | matches.push_back(iter->str()); 39 | ++iter; 40 | } 41 | 42 | return matches; 43 | } 44 | 45 | vector> findMatchesCaptures(const string& str) override { 46 | vector> matches{}; 47 | vector captures; 48 | sregex_iterator iter(str.begin(), str.end(), _regex); 49 | sregex_iterator end; 50 | 51 | while (iter != end) { 52 | captures = vector{}; 53 | 54 | for (unsigned i = 0; i < iter->size(); ++i) { 55 | captures.push_back((*iter)[i].str()); 56 | } 57 | 58 | matches.push_back(captures); 59 | ++iter; 60 | } 61 | 62 | return matches; 63 | } 64 | 65 | string replace(string str, const string& replacement) override { 66 | return regex_replace(str, _regex, replacement); 67 | } 68 | 69 | vector split(const string& str) override { 70 | sregex_token_iterator it(str.begin(), str.end(), _regex, -1); 71 | sregex_token_iterator end; 72 | vector m; 73 | 74 | while (it != end) { 75 | m.push_back(*it); 76 | ++it; 77 | } 78 | 79 | return m; 80 | } 81 | private: 82 | regex _regex; 83 | }; 84 | 85 | -------------------------------------------------------------------------------- /Textractor.GptApiTranslate/src/Textractor.GptApiTranslate/_Libraries/winmsg.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | inline void showErrorMessage(const string& message, const string& appName) { 9 | string tag = appName + "-Error"; 10 | MessageBoxA(nullptr, message.c_str(), tag.c_str(), MB_ICONERROR | MB_OK); 11 | } 12 | 13 | inline string getModuleName(const HMODULE& handle) { 14 | try { 15 | wchar_t buffer[1024]; 16 | GetModuleFileName(handle, buffer, sizeof(buffer) / sizeof(wchar_t)); 17 | 18 | string module = StrHelper::convertFromW(buffer); 19 | size_t pathDelimIndex = module.rfind('\\'); 20 | if (pathDelimIndex != string::npos) module = module.substr(pathDelimIndex + 1); 21 | 22 | size_t extIndex = module.rfind('.'); 23 | if (extIndex != string::npos) module = module.erase(extIndex); 24 | 25 | return module; 26 | } 27 | catch (exception& ex) { 28 | string errMsg = "Failed to retrieve extension name.\n"; 29 | errMsg += ex.what(); 30 | showErrorMessage(errMsg.c_str(), "VndbNameMapper"); 31 | throw; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/img/config-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.PythonInterpretter/img/config-example.png -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/img/copy-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.PythonInterpretter/img/copy-extension.png -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/img/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.PythonInterpretter/img/example1.png -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/img/extension-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.PythonInterpretter/img/extension-order.png -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/scripts/JpToRomaji/README.md: -------------------------------------------------------------------------------- 1 | # JP to Romaji 2 | 3 | This script leverages NLP to append the romaji form of the currently processed sentence. It relies on the **[cutlet](https://github.com/polm/cutlet)** library to do so. 4 | 5 | **Requirements to run this script:** 6 | 1. Both the python script and the 'requirements.txt' file will be need. 7 | 2. Once these files are downloaded, add the path for the 'requirements.txt' file to the **PipRequirementsTxtPath** config value in your Textractor.ini file. 8 | - This is needed to installed required depedencies to run the cutlet library. 9 | 10 | **Additional notes:** 11 | 1. The 'cutlet' library may potentially be incompatible with 32-bit python on Windows, as well as python >=3.12. 12 | - Therefore make sure you are running this script with a compatiable python version. 13 | 2. Since 'cutlet' leverages natural language processing (NLP) to approximate the correct jp to romaji conversion, there is no guarantee that the resulting romaji is 100% accurate. 14 | 3. Any issues/inaccuracies pertaining to the 'cutlet' library should be reported in the **['cutlet' GitHub repo](https://github.com/polm/cutlet/issues)** rather than in this repo. 15 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/scripts/JpToRomaji/jp-to-romaji-script.py: -------------------------------------------------------------------------------- 1 | 2 | ### v1.0.0 3 | ### NOTE: The 'cutlet' library may potentially be incompatible with 32-bit python on Windows, as well as python >=3.12. 4 | 5 | import cutlet 6 | 7 | zero_width_space_ch = '\u200b' 8 | katsu = cutlet.Cutlet() 9 | 10 | def process_sentence(sentence, sentence_info, custom_vars): 11 | split_sents = sentence.split(zero_width_space_ch) 12 | romaji_sent = katsu.romaji(split_sents[0]) 13 | split_sents.insert(1, '\n' + romaji_sent) 14 | return zero_width_space_ch.join(split_sents) 15 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/scripts/JpToRomaji/requirements.txt: -------------------------------------------------------------------------------- 1 | cutlet 2 | unidic-lite -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/scripts/ScriptExample/README.md: -------------------------------------------------------------------------------- 1 | # Script Example 2 | 3 | This script is merely an example of how to implement a python script compatible with this extension. 4 | - Script file contains extensive documentation on script implementation details 5 | - The code itself merely prepends an incrementing number to the currently processed sentence. 6 | 7 | **It is highly recommended you review this script before you try implementing your own python script for the PythonInterpetter extension.** 8 | 9 | No additional dependencies, custom configurations, or steps needed to run this script in Textractor. 10 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.PythonInterpretter", "Textractor.PythonInterpretter\Textractor.PythonInterpretter.vcxproj", "{975010E5-7F91-421B-B99F-66C22ACEC96E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Debug|x64.ActiveCfg = Debug|x64 17 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Debug|x64.Build.0 = Debug|x64 18 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Debug|x86.ActiveCfg = Debug|Win32 19 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Debug|x86.Build.0 = Debug|Win32 20 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Release|x64.ActiveCfg = Release|x64 21 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Release|x64.Build.0 = Release|x64 22 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Release|x86.ActiveCfg = Release|Win32 23 | {975010E5-7F91-421B-B99F-66C22ACEC96E}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E1DCB5C2-245C-428D-A468-B18CE1419033} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/ExtExecRequirements.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "ExtensionConfig.h" 4 | #include "Extension.h" 5 | 6 | 7 | class ExtExecRequirements { 8 | public: 9 | virtual ~ExtExecRequirements() { } 10 | virtual bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 11 | }; 12 | 13 | 14 | class NoExtExecRequirements : public ExtExecRequirements { 15 | public: 16 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 17 | return true; 18 | } 19 | }; 20 | 21 | 22 | class DefaultExtExecRequirements : public ExtExecRequirements { 23 | public: 24 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 25 | if (config.disabled) return false; 26 | if (config.activeThreadOnly && !sentInfoWrapper.isActiveThread()) return false; 27 | if (!meetsConsoleAndClipboardRequirements(sentInfoWrapper, config)) return false; 28 | 29 | return true; 30 | } 31 | private: 32 | bool meetsConsoleAndClipboardRequirements( 33 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const 34 | { 35 | static const wstring _consoleThreadName = L"Console"; 36 | static const wstring _clipboardThreadName = L"Clipboard"; 37 | wstring threadName = sentInfoWrapper.getThreadNameW(); 38 | 39 | switch (config.skipConsoleAndClipboard) { 40 | case ExtensionConfig::ConsoleClipboardMode::SkipAll: 41 | if (sentInfoWrapper.threadIsConsoleOrClipboard()) return false; 42 | break; 43 | case ExtensionConfig::ConsoleClipboardMode::SkipConsole: 44 | if (threadName == _consoleThreadName) return false; 45 | break; 46 | case ExtensionConfig::ConsoleClipboardMode::SkipClipboard: 47 | if (threadName == _clipboardThreadName) return false; 48 | break; 49 | } 50 | 51 | return true; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/Extension.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include "Libraries/strhelper.h" 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | struct InfoForExtension 13 | { 14 | const char* name; 15 | int64_t value; 16 | }; 17 | 18 | struct SentenceInfo 19 | { 20 | const InfoForExtension* infoArray; 21 | int64_t operator[](std::string propertyName) 22 | { 23 | for (auto info = infoArray; info->name; ++info) // nullptr name marks end of info array 24 | if (propertyName == info->name) return info->value; 25 | return *(int*)0xcccc = 0; // gives better error message than alternatives 26 | } 27 | }; 28 | 29 | struct SKIP {}; 30 | inline void Skip() { throw SKIP(); } 31 | 32 | 33 | class SentenceInfoWrapper { 34 | public: 35 | SentenceInfoWrapper(SentenceInfo& sentenceInfo) : _sentenceInfo(sentenceInfo) { } 36 | 37 | bool isActiveThread() { 38 | return getCurrentSelect(); 39 | } 40 | 41 | bool threadIsConsoleOrClipboard() { 42 | return getProcessId() == 0; 43 | } 44 | 45 | int64_t getCurrentSelect() { 46 | return _sentenceInfo["current select"]; 47 | } 48 | 49 | wstring getProcessIdW() { 50 | return to_wstring(getProcessId()); 51 | } 52 | 53 | DWORD getProcessIdD() { 54 | return static_cast(getProcessId()); 55 | } 56 | 57 | int64_t getProcessId() { 58 | return _sentenceInfo["process id"]; 59 | } 60 | 61 | wstring getThreadNumberW() { 62 | int64_t threadNum = getThreadNumber(); 63 | return to_wstring(threadNum); 64 | } 65 | 66 | int64_t getThreadNumber() { 67 | return _sentenceInfo["text number"]; 68 | } 69 | 70 | string getThreadName() { 71 | wstring threadNameW = getThreadNameW(); 72 | return StrHelper::convertFromW(threadNameW); 73 | } 74 | 75 | wstring getThreadNameW() { 76 | int64_t threadNamePtr = _sentenceInfo["text name"]; 77 | return wstring(reinterpret_cast(threadNamePtr)); 78 | } 79 | private: 80 | SentenceInfo _sentenceInfo; 81 | }; 82 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 23 | { 24 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 25 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 26 | } 27 | } 28 | catch (SKIP) 29 | { 30 | *sentence = L'\0'; 31 | } 32 | return sentence; 33 | } -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/File/FileDeleter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | using namespace std; 5 | 6 | 7 | class FileDeleter { 8 | public: 9 | virtual ~FileDeleter() { } 10 | virtual void deleteFile(const string& filePath) = 0; 11 | }; 12 | 13 | 14 | class CRemoveFileDeleter : public FileDeleter { 15 | public: 16 | void deleteFile(const string& filePath) override { 17 | remove(filePath.c_str()); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/File/FileReader.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | class FileReader { 11 | public: 12 | virtual ~FileReader() { } 13 | virtual bool fileExists(const string& filePath) = 0; 14 | virtual vector readLines(const string& filePath) = 0; 15 | virtual void readLines(const string& filePath, const function& lineAction) = 0; 16 | virtual string readLine(const string& filePath, size_t i) = 0; 17 | virtual string readLine(const string& filePath, const function condition) = 0; 18 | virtual string readAll(const string& filePath) = 0; 19 | }; 20 | 21 | 22 | class NoFileReader : public FileReader { 23 | public: 24 | bool fileExists(const string& filePath) override { return false; } 25 | vector readLines(const string& filePath) override { return vector{}; }; 26 | void readLines(const string& filePath, const function& lineAction) override { } 27 | string readLine(const string& filePath, size_t i) override { return ""; } 28 | string readLine(const string& filePath, const function condition) override { return ""; } 29 | string readAll(const string& filePath) override { return ""; } 30 | }; 31 | 32 | 33 | class FstreamFileReader : public FileReader { 34 | public: 35 | bool fileExists(const string& filePath) override { 36 | ifstream f(filePath, ios_base::in); 37 | return fileExists(f); 38 | } 39 | 40 | vector readLines(const string& filePath) override { 41 | vector lines{}; 42 | readLines(filePath, [&lines](const string& line) { lines.push_back(line); }); 43 | return lines; 44 | } 45 | 46 | void readLines(const string& filePath, const function& lineAction) override { 47 | readLine(filePath, [&lineAction](const string& line) { 48 | lineAction(line); 49 | return false; 50 | }); 51 | } 52 | 53 | string readLine(const string& filePath, size_t i) override { 54 | size_t currI = 0; 55 | 56 | return readLine(filePath, [i, &currI](const string& line) { 57 | return i == currI++; 58 | }); 59 | } 60 | 61 | string readLine(const string& filePath, const function condition) override { 62 | ifstream f(filePath, ios_base::in); 63 | if (!fileExists(f)) return ""; 64 | char* line = new char[MAX_LENGTH]; 65 | 66 | while (f.getline(line, MAX_LENGTH)) { 67 | if (condition(line)) return line; 68 | } 69 | 70 | return ""; 71 | } 72 | 73 | string readAll(const string& filePath) override { 74 | ifstream f(filePath, ios_base::in); 75 | if (!fileExists(f)) return ""; 76 | 77 | stringstream buffer; 78 | buffer << f.rdbuf(); 79 | return buffer.str(); 80 | } 81 | private: 82 | static const int MAX_LENGTH = 524288; 83 | 84 | bool fileExists(const ifstream& f) const { 85 | return f.good(); 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/File/Writer/FileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | class FileWriter { 9 | public: 10 | virtual ~FileWriter() { } 11 | virtual void writeToFile(const string& filePath, const string& text) = 0; 12 | virtual void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 13 | virtual void appendToFile(const string& filePath, const string& text) = 0; 14 | virtual void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 15 | }; 16 | 17 | 18 | class NoFileWriter : public FileWriter { 19 | public: 20 | void writeToFile(const string& filePath, const string& text) override { } 21 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 22 | void appendToFile(const string& filePath, const string& text) override { } 23 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/File/Writer/FireAndForgetFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | class FireAndForgetFileWriter : public FileWriter { 11 | public: 12 | FireAndForgetFileWriter(FileWriter& mainWriter) : _mainWriter(mainWriter) { } 13 | 14 | ~FireAndForgetFileWriter() { 15 | // ensure all ongoing write activity is done before deallocating 16 | _destrCalled = true; 17 | waitForAllActionsDone(100, 5000); 18 | } 19 | 20 | void writeToFile(const string& filePath, const string& text) override { 21 | thread([this, filePath, text]() { writeToFileBase(filePath, text); }).detach(); 22 | } 23 | 24 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 25 | thread([this, filePath, lines, startIndex]() { 26 | writeToFileBase(filePath, lines, startIndex); }).detach(); 27 | } 28 | 29 | void appendToFile(const string& filePath, const string& text) override { 30 | thread([this, filePath, text]() { appendToFileBase(filePath, text); }).detach(); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | thread([this, filePath, lines, startIndex]() { 35 | appendToFileBase(filePath, lines, startIndex); }).detach(); 36 | } 37 | private: 38 | atomic _activeCount = 0; 39 | atomic_bool _destrCalled = false; 40 | FileWriter& _mainWriter; 41 | 42 | void writeToFileBase(const string& filePath, const string& text) { 43 | trackAction([this, &filePath, &text]() { 44 | _mainWriter.writeToFile(filePath, text); 45 | }); 46 | } 47 | 48 | void writeToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 49 | trackAction([this, &filePath, &lines, startIndex]() { 50 | _mainWriter.writeToFile(filePath, lines, startIndex); 51 | }); 52 | } 53 | 54 | void appendToFileBase(const string& filePath, const string& text) { 55 | trackAction([this, &filePath, &text]() { 56 | _mainWriter.appendToFile(filePath, text); 57 | }); 58 | } 59 | 60 | void appendToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 61 | trackAction([this, &filePath, &lines, startIndex]() { 62 | _mainWriter.appendToFile(filePath, lines, startIndex); 63 | }); 64 | } 65 | 66 | void trackAction(const function& action) { 67 | if (_destrCalled) return; 68 | _activeCount++; 69 | 70 | try { 71 | action(); 72 | _activeCount--; 73 | } 74 | catch (const exception&) { 75 | _activeCount--; 76 | throw; 77 | } 78 | } 79 | 80 | void waitForAllActionsDone(DWORD intervalMs, DWORD maxWaitMs) { 81 | DWORD waitMs = 0; 82 | 83 | while (_activeCount > 0 && waitMs < maxWaitMs) { 84 | Sleep(intervalMs); 85 | waitMs += intervalMs; 86 | } 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/File/Writer/TruncatableFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include "../FileTruncater.h" 5 | 6 | 7 | class TruncatableFileWriter : public FileWriter { 8 | public: 9 | TruncatableFileWriter(FileWriter& mainWriter, FileTruncater& truncater) 10 | : _mainWriter(mainWriter), _truncater(truncater) { } 11 | 12 | void writeToFile(const string& filePath, const string& text) override { 13 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 14 | _mainWriter.writeToFile(filePath, text); 15 | _truncater.truncateFile(filePath); 16 | }); 17 | } 18 | 19 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 20 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 21 | _mainWriter.writeToFile(filePath, lines, startIndex); 22 | _truncater.truncateFile(filePath); 23 | }); 24 | } 25 | 26 | void appendToFile(const string& filePath, const string& text) override { 27 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 28 | _mainWriter.appendToFile(filePath, text); 29 | _truncater.truncateFile(filePath); 30 | }); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 35 | _mainWriter.appendToFile(filePath, lines, startIndex); 36 | _truncater.truncateFile(filePath); 37 | }); 38 | } 39 | private: 40 | DefaultLockerMap _lockerMap; 41 | FileWriter& _mainWriter; 42 | FileTruncater& _truncater; 43 | }; 44 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/KeyValSplitter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class KeyValSplitter { 8 | public: 9 | virtual ~KeyValSplitter() { } 10 | virtual vector> splitToKeyVals( 11 | const string& vars, const string varsDelim, const string& keyValDelim = "=") = 0; 12 | }; 13 | 14 | 15 | class DefaultKeyValSplitter : public KeyValSplitter { 16 | public: 17 | virtual vector> splitToKeyVals( 18 | const string& vars, const string varsDelim, const string& keyValDelim = "=") override 19 | { 20 | vector> keyVals{}; 21 | string keyVal, key, val; 22 | 23 | const size_t delimLen = varsDelim.length(); 24 | size_t currOffset = 0, prevOffset = 0; 25 | 26 | while (currOffset < vars.length()) { 27 | prevOffset = currOffset; 28 | currOffset = vars.find(varsDelim, prevOffset); 29 | if (currOffset == string::npos) currOffset = vars.length(); 30 | 31 | keyVal = vars.substr(prevOffset, currOffset - prevOffset); 32 | keyVals.push_back(splitToPair(keyVal, keyValDelim)); 33 | currOffset += delimLen; 34 | } 35 | 36 | return keyVals; 37 | } 38 | 39 | private: 40 | pair splitToPair(const string& str, const string& delim) { 41 | size_t delimIndex = str.find(delim); 42 | if (delimIndex == string::npos) delimIndex = str.length(); 43 | 44 | string key = str.substr(0, delimIndex); 45 | string val = delimIndex < str.length() ? str.substr(delimIndex + delim.length()) : ""; 46 | return pair(key, val); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/Libraries/FileTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class FileTracker { 10 | public: 11 | virtual ~FileTracker() { } 12 | virtual int64_t getDateLastModifiedEpochs(const string& filePath) = 0; 13 | virtual int64_t getDateLastModifiedEpochs(const char* filePath) = 0; 14 | virtual int64_t getDateLastModifiedEpochs(const wstring& filePath) = 0; 15 | virtual int64_t getDateLastModifiedEpochs(const wchar_t* filePath) = 0; 16 | }; 17 | 18 | 19 | class WinApiFileTracker : public FileTracker { 20 | public: 21 | int64_t getDateLastModifiedEpochs(const string& filePath) override { 22 | return getDateLastModifiedEpochs(StrHelper::convertToW(filePath)); 23 | } 24 | 25 | int64_t getDateLastModifiedEpochs(const char* filePath) override { 26 | return getDateLastModifiedEpochs(string(filePath)); 27 | } 28 | 29 | int64_t getDateLastModifiedEpochs(const wstring& filePath) override { 30 | return getDateLastModifiedEpochs(filePath.c_str()); 31 | } 32 | 33 | int64_t getDateLastModifiedEpochs(const wchar_t* filePath) override { 34 | HANDLE fHandle = getFileHandle(filePath); 35 | if (!isValidHandle(fHandle)) return 0; 36 | 37 | FILETIME lastWrite = getFileLastWriteTime(fHandle); 38 | CloseHandle(fHandle); 39 | 40 | return convertTo64(lastWrite); 41 | } 42 | private: 43 | HANDLE getFileHandle(const wchar_t* filePath) { 44 | return CreateFile(filePath, GENERIC_READ, 45 | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); 46 | } 47 | 48 | bool isValidHandle(const HANDLE& handle) { 49 | return handle != INVALID_HANDLE_VALUE; 50 | } 51 | 52 | FILETIME getFileLastWriteTime(const HANDLE& handle) { 53 | FILETIME lastWrite; 54 | GetFileTime(handle, NULL, NULL, &lastWrite); 55 | return lastWrite; 56 | } 57 | 58 | int64_t convertTo64(FILETIME fTime) { 59 | ULARGE_INTEGER ularge{}; 60 | ularge.LowPart = fTime.dwLowDateTime; 61 | ularge.HighPart = fTime.dwHighDateTime; 62 | return static_cast(ularge.QuadPart); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/Libraries/datetime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | inline std::string getCurrentDateTime() { 7 | auto currentTime = std::chrono::system_clock::now(); 8 | time_t currentTime_t = std::chrono::system_clock::to_time_t(currentTime); 9 | 10 | struct tm currentTime_tm; 11 | localtime_s(¤tTime_tm, ¤tTime_t); 12 | 13 | char buffer[80]; 14 | strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ¤tTime_tm); 15 | return std::string(buffer); 16 | } 17 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/Libraries/winmsg.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | inline void showTextboxMsg(const string& message, const string& appName) { 10 | MessageBoxA(nullptr, message.c_str(), appName.c_str(), MB_OK); 11 | } 12 | 13 | inline void showErrorMessage(const string& message, const string& appName) { 14 | string tag = appName + "-Error"; 15 | MessageBoxA(nullptr, message.c_str(), tag.c_str(), MB_ICONERROR | MB_OK); 16 | } 17 | 18 | inline string getModuleName(const HMODULE& handle) { 19 | try { 20 | wchar_t buffer[1024]; 21 | GetModuleFileName(handle, buffer, sizeof(buffer) / sizeof(wchar_t)); 22 | 23 | string module = StrHelper::convertFromW(buffer); 24 | size_t pathDelimIndex = module.rfind('\\'); 25 | if (pathDelimIndex != string::npos) module = module.substr(pathDelimIndex + 1); 26 | 27 | size_t extIndex = module.rfind('.'); 28 | if (extIndex != string::npos) module = module.erase(extIndex); 29 | 30 | return module; 31 | } 32 | catch (exception& ex) { 33 | string errMsg = "Failed to retrieve extension name.\n"; 34 | errMsg += ex.what(); 35 | showErrorMessage(errMsg.c_str(), "PythonInterpretter"); 36 | throw; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/ThreadIdGenerator.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "Extension.h" 5 | #include 6 | using namespace std; 7 | 8 | 9 | class ThreadIdGenerator { 10 | public: 11 | virtual ~ThreadIdGenerator() { } 12 | virtual string generateId(SentenceInfoWrapper& sentInfoWrapper) = 0; 13 | }; 14 | 15 | 16 | class DefaultThreadIdGenerator : public ThreadIdGenerator { 17 | string generateId(SentenceInfoWrapper& sentInfoWrapper) { 18 | int64_t threadNum = sentInfoWrapper.getThreadNumber(); 19 | string threadName = sentInfoWrapper.getThreadName(); 20 | 21 | return to_string(threadNum) + "_" + threadName; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/containers/LoggerFactory.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../logging/Loggers.h" 4 | #include "../File/Writer/WinApiFileWriter.h" 5 | #include 6 | 7 | 8 | class LoggerFactory { 9 | public: 10 | virtual ~LoggerFactory() { } 11 | virtual Logger* createLogger(const string& logFilePath, 12 | Logger::Events& loggerEvents, Logger::Level logLevel) = 0; 13 | }; 14 | 15 | class NoLoggerFactory : public LoggerFactory { 16 | public: 17 | Logger* createLogger(const string& logFilePath, Logger::Events& loggerEvents, Logger::Level logLevel) override 18 | { 19 | return new NoLogger(); 20 | } 21 | }; 22 | 23 | class PersistentWinApiFileWriterLoggerManager : public LoggerFactory { 24 | public: 25 | PersistentWinApiFileWriterLoggerManager(const uint64_t logSizeLimitBytes = LOG_SIZE_LIMIT_BYTES_DEF) 26 | : _logSizeLimitBytes(logSizeLimitBytes) 27 | { 28 | _fileReader = make_unique(); 29 | _fileWriter = make_unique(); 30 | _fileTruncater = make_unique(*_fileReader, *_fileWriter, _logSizeLimitBytes); 31 | } 32 | 33 | Logger* createLogger(const string& logFilePath, Logger::Events& loggerEvents, Logger::Level logLevel) override 34 | { 35 | return new FileWriterLogger(*_fileWriter, *_fileTruncater, logFilePath, loggerEvents, logLevel); 36 | } 37 | private: 38 | static constexpr uint64_t LOG_SIZE_LIMIT_BYTES_DEF = 10 * 1024 * 1024; 39 | const uint64_t _logSizeLimitBytes; 40 | 41 | unique_ptr _fileReader = nullptr; 42 | unique_ptr _fileTruncater = nullptr; 43 | unique_ptr _fileWriter = nullptr; 44 | }; 45 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/environment/EnvironmentVarRetriever.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class EnvironmentVarRetriever { 8 | public: 9 | virtual ~EnvironmentVarRetriever() { } 10 | virtual string getTempDirVarName() const = 0; 11 | virtual string getEnvVar(const string& varName) = 0; 12 | }; 13 | 14 | 15 | class WinStdLibEnvironmentVarRetriever : public EnvironmentVarRetriever { 16 | public: 17 | string getTempDirVarName() const override { 18 | static const string varName = "TEMP"; 19 | return varName; 20 | } 21 | 22 | string getEnvVar(const string& varName) override { 23 | char* buf = nullptr; 24 | size_t sz = 0; 25 | 26 | if (_dupenv_s(&buf, &sz, varName.c_str()) != 0 || buf == nullptr) return ""; 27 | 28 | string val = buf; 29 | free(buf); 30 | return val; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/logging/LoggerBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Libraries/datetime.h" 4 | #include 5 | using namespace std; 6 | 7 | class Logger { 8 | public: 9 | enum Level { Debug = 0, Info, Warning, Error, Fatal }; 10 | class Events { 11 | public: 12 | ~Events() { } 13 | virtual void onLogLevelChanged(const Logger& logger, 14 | Logger::Level prevLogLevel, Logger::Level currLogLevel) const = 0; 15 | }; 16 | 17 | virtual ~Logger() { } 18 | virtual void logDebug(const string& msg) const = 0; 19 | virtual void logInfo(const string& msg) const = 0; 20 | virtual void logWarning(const string& msg) const = 0; 21 | virtual void logError(const string& msg) const = 0; 22 | virtual void logFatal(const string& msg) const = 0; 23 | virtual void log(const Level logLevel, const string& msg) const = 0; 24 | virtual Level getMinLogLevel() const = 0; 25 | virtual void setMinLogLevel(const Level minLogLevel) = 0; 26 | }; 27 | 28 | 29 | class LoggerBase : public Logger { 30 | public: 31 | LoggerBase(const Logger::Level minLogLevel, const Logger::Events& events) 32 | : _minLogLevel(minLogLevel), _events(events) { } 33 | virtual ~LoggerBase() { } 34 | 35 | virtual void logDebug(const string& msg) const { 36 | log(Level::Debug, msg); 37 | } 38 | virtual void logInfo(const string& msg) const { 39 | log(Level::Info, msg); 40 | } 41 | virtual void logWarning(const string& msg) const { 42 | log(Level::Warning, msg); 43 | } 44 | virtual void logError(const string& msg) const { 45 | log(Level::Error, msg); 46 | } 47 | virtual void logFatal(const string& msg) const { 48 | log(Level::Fatal, msg); 49 | } 50 | 51 | virtual void log(const Level logLevel, const string& msg) const { 52 | if (logLevel < _minLogLevel) return; 53 | 54 | string fullMsg = createLogMsg(logLevel, msg); 55 | writeToLog(logLevel, fullMsg); 56 | } 57 | 58 | virtual Level getMinLogLevel() const { 59 | return _minLogLevel; 60 | } 61 | 62 | virtual void setMinLogLevel(const Level minLogLevel) { 63 | if (_minLogLevel == minLogLevel) return; 64 | 65 | Level prevLevel = _minLogLevel; 66 | _minLogLevel = minLogLevel; 67 | _events.onLogLevelChanged(*this, prevLevel, minLogLevel); 68 | } 69 | protected: 70 | Level _minLogLevel; 71 | const Events& _events; 72 | virtual void writeToLog(Level logLevel, const string& msg) const = 0; 73 | 74 | virtual string createLogMsg(const Level logLevel, const string& baseMsg) const { 75 | string levelStr = toStr(logLevel); 76 | string msg = "[" + getCurrentDateTime() + "][" + levelStr + "] " + baseMsg; 77 | return msg; 78 | } 79 | 80 | virtual string toStr(Level level) const { 81 | switch (level) { 82 | case Level::Debug: 83 | return "DEBUG"; 84 | case Level::Info: 85 | return "INFO"; 86 | case Level::Warning: 87 | return "WARN"; 88 | case Level::Error: 89 | return "ERROR"; 90 | case Level::Fatal: 91 | return "FATAL"; 92 | default: 93 | return "DEBUG"; 94 | } 95 | } 96 | }; 97 | 98 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/logging/LoggerEvents.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Libraries/Locker.h" 4 | #include "LoggerBase.h" 5 | #include "LoggerEvents.h" 6 | #include 7 | #include 8 | 9 | class NoLoggerEvents : public Logger::Events { 10 | public: 11 | void onLogLevelChanged(const Logger& logger, 12 | Logger::Level prevLogLevel, Logger::Level currLogLevel) const override { } 13 | }; 14 | 15 | class StaticLoggerEvents : public Logger::Events { 16 | public: 17 | StaticLoggerEvents(const function onLogLevelChangedFunc_) 18 | : StaticLoggerEvents(vector>{onLogLevelChangedFunc_}) { } 19 | StaticLoggerEvents(const vector> onLogLevelChangedFuncs_) 20 | : _onLogLevelChangedFuncs(onLogLevelChangedFuncs_) { } 21 | 22 | void onLogLevelChanged(const Logger& logger, 23 | Logger::Level prevLogLevel, Logger::Level currLogLevel) const override 24 | { 25 | for (const auto& func : _onLogLevelChangedFuncs) { 26 | func(logger, prevLogLevel, currLogLevel); 27 | } 28 | } 29 | private: 30 | const vector> _onLogLevelChangedFuncs; 31 | }; 32 | 33 | class DynamicLoggerEvents : public Logger::Events { 34 | public: 35 | void onLogLevelChanged(const Logger& logger, 36 | Logger::Level prevLogLevel, Logger::Level currLogLevel) const override 37 | { 38 | _locker.lock([this, &logger, &prevLogLevel, &currLogLevel]() { 39 | for (auto& func : _onLogLevelChangedFuncs) { 40 | func(logger, prevLogLevel, currLogLevel); 41 | } 42 | }); 43 | } 44 | 45 | void addToOnLogLevelChangedEvent(function func) { 46 | _locker.lock([this, &func]() { 47 | _onLogLevelChangedFuncs.push_back(func); 48 | }); 49 | } 50 | private: 51 | vector> _onLogLevelChangedFuncs; 52 | mutable BasicLocker _locker; 53 | }; 54 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/python/PathFormatter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | using namespace std; 5 | 6 | class PathFormatter { 7 | public: 8 | virtual ~PathFormatter() { } 9 | virtual string formatDirPath(string dirPath) = 0; 10 | }; 11 | 12 | 13 | class DefaultPathFormatter : public PathFormatter { 14 | public: 15 | virtual string formatDirPath(string dirPath) override { 16 | if (!dirPath.empty()) { 17 | if (dirPath.rfind('/') < dirPath.length() - 1) dirPath += '/'; 18 | else if (dirPath.rfind('\\') != dirPath.length() - 1) dirPath += '\\'; 19 | } 20 | 21 | return dirPath; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/python/ProcessStateTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WinApiHelper.h" 4 | #include 5 | #include 6 | #include 7 | 8 | class ProcessStateTracker { 9 | public: 10 | static constexpr DWORD WAIT_MS_DEFAULT = WinApiHelper::WAIT_MS_DEFAULT; 11 | virtual ~ProcessStateTracker() { } 12 | 13 | virtual bool isProcessActive(const HANDLE& hProcess, DWORD waitForExitMs = 0) const = 0; 14 | virtual bool waitForProcessExit(const HANDLE& hProcess, DWORD& waitStatus, DWORD& errCode, DWORD waitMs = WAIT_MS_DEFAULT) const = 0; 15 | virtual bool exitedSuccessfully(const HANDLE& hProcess, DWORD& exitStatus, DWORD& errCode) const = 0; 16 | }; 17 | 18 | 19 | class WinApiProcessStateTracker : public ProcessStateTracker { 20 | public: 21 | bool isProcessActive(const HANDLE& hProcess, DWORD waitForExitMs = 0) const override { 22 | DWORD waitStatus, errCode; 23 | waitForProcessExit(hProcess, waitStatus, errCode, waitForExitMs); 24 | 25 | return !WinApiHelper::isErr(errCode) && !WinApiHelper::waitStatusExited(waitStatus); 26 | } 27 | 28 | bool waitForProcessExit(const HANDLE& hProcess, DWORD& waitStatus, 29 | DWORD& errCode, DWORD waitMs = WAIT_MS_DEFAULT) const override 30 | { 31 | waitStatus = WAIT_OBJECT_0; 32 | errCode = NO_ERROR; 33 | 34 | if (!WinApiHelper::isValidHandleValue(hProcess)) return true; 35 | waitStatus = WaitForSingleObject(hProcess, waitMs); 36 | 37 | if (waitStatus == WAIT_FAILED) { 38 | errCode = GetLastError(); 39 | return false; 40 | } 41 | 42 | return WinApiHelper::waitStatusExited(waitStatus); 43 | } 44 | 45 | bool exitedSuccessfully(const HANDLE& hProcess, DWORD& exitStatus, DWORD& errCode) const { 46 | if (!GetExitCodeProcess(hProcess, &exitStatus)) { 47 | errCode = GetLastError(); 48 | return false; 49 | } 50 | 51 | return exitStatus == EXIT_SUCCESS; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/python/WinApiHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | 7 | class WinApiHelper { 8 | public: 9 | static constexpr DWORD WAIT_MS_DEFAULT = 5000; 10 | static constexpr size_t BUFFER_SIZE_DEFAULT = 32 * 1024; 11 | 12 | static bool isValidHandleValue(const HANDLE& handle) { 13 | return handle != nullptr && handle != INVALID_HANDLE_VALUE; 14 | } 15 | 16 | static bool isErr(DWORD errCode) { 17 | return errCode != NO_ERROR; 18 | } 19 | 20 | static bool waitStatusExited(DWORD waitStatus) { 21 | return waitStatus == WAIT_OBJECT_0; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/python/pip/CustomPackageToModuleMapper.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class CustomPackageToModuleMapper { 9 | public: 10 | virtual ~CustomPackageToModuleMapper() { } 11 | virtual string mapToModule(const string& packageName) = 0; 12 | virtual vector mapToModules(const vector& packageNames) = 0; 13 | }; 14 | 15 | 16 | class DefaultCustomPackageToModuleMapper : public CustomPackageToModuleMapper { 17 | public: 18 | virtual string mapToModule(const string& packageName) override { 19 | return isCustomMappedPackage(packageName) ? getModuleMapping(packageName) : packageName; 20 | } 21 | 22 | virtual vector mapToModules(const vector& packageNames) override { 23 | vector modules{}; 24 | 25 | for (const auto& package : packageNames) { 26 | modules.push_back(mapToModule(package)); 27 | } 28 | 29 | return modules; 30 | } 31 | private: 32 | const unordered_map _customPackageToModuleMap = { 33 | { "pypiwin32", "win32file" } 34 | }; 35 | 36 | bool isCustomMappedPackage(const string& packageName) { 37 | return _customPackageToModuleMap.find(packageName) != _customPackageToModuleMap.end(); 38 | } 39 | 40 | string getModuleMapping(const string& packageName) { 41 | return _customPackageToModuleMap.at(packageName); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /Textractor.PythonInterpretter/src/Textractor.PythonInterpretter/python/pip/RequirementsTxtParser.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../../Libraries/strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class RequirementsTxtParser { 10 | public: 11 | virtual ~RequirementsTxtParser() { } 12 | virtual vector getPackageNames(const string& reqsTxtFilePath) = 0; 13 | }; 14 | 15 | 16 | class DefaultRequirementsTxtParser : public RequirementsTxtParser { 17 | public: 18 | vector getPackageNames(const string& reqsTxtFilePath) override { 19 | ifstream f(reqsTxtFilePath); 20 | vector packages{}; 21 | string line, packageName; 22 | 23 | while (getline(f, line)) { 24 | packageName = formatPackageName(line); 25 | if (!isValidPackageName(packageName)) continue; 26 | packages.push_back(packageName); 27 | } 28 | 29 | return packages; 30 | } 31 | private: 32 | const string SPACE = " "; 33 | unordered_map _customPackageToModuleMap = { 34 | { "pypiwin32", "win32file" } 35 | }; 36 | 37 | string formatPackageName(string packageName) { 38 | packageName = StrHelper::trim(packageName, SPACE); 39 | return StrHelper::replace(packageName, "-", "_"); 40 | } 41 | 42 | bool isValidPackageName(const string& packageName) { 43 | if (packageName.empty()) return false; 44 | if (!isalpha(packageName[0]) && packageName[0] != '_') return false; 45 | 46 | for (const char ch : packageName) { 47 | if (!isalnum(ch) && ch != '_') return false; 48 | } 49 | 50 | return true; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /Textractor.TextLogger/img/concepts-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/concepts-example.png -------------------------------------------------------------------------------- /Textractor.TextLogger/img/config-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/config-example.png -------------------------------------------------------------------------------- /Textractor.TextLogger/img/copy-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/copy-extension.png -------------------------------------------------------------------------------- /Textractor.TextLogger/img/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/example1.png -------------------------------------------------------------------------------- /Textractor.TextLogger/img/extension-order1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/extension-order1.png -------------------------------------------------------------------------------- /Textractor.TextLogger/img/extension-order2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TextLogger/img/extension-order2.png -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.TextLogger", "Textractor.TextLogger\Textractor.TextLogger.vcxproj", "{20FEC392-7367-4FDE-977A-32F1EB1464DF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Debug|x64.ActiveCfg = Debug|x64 17 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Debug|x64.Build.0 = Debug|x64 18 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Debug|x86.ActiveCfg = Debug|Win32 19 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Debug|x86.Build.0 = Debug|Win32 20 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Release|x64.ActiveCfg = Release|x64 21 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Release|x64.Build.0 = Release|x64 22 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Release|x86.ActiveCfg = Release|Win32 23 | {20FEC392-7367-4FDE-977A-32F1EB1464DF}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0FFCEF03-CC6F-413E-9371-3DE749BDBF73} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/ExtExecRequirements.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Extension.h" 4 | #include "ExtensionConfig.h" 5 | #include "Threading/ThreadFilter.h" 6 | 7 | 8 | class ExtExecRequirements { 9 | public: 10 | virtual ~ExtExecRequirements() { } 11 | virtual bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 12 | }; 13 | 14 | 15 | class NoExtExecRequirements : public ExtExecRequirements { 16 | public: 17 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 18 | return true; 19 | } 20 | }; 21 | 22 | 23 | class DefaultExtExecRequirements : public ExtExecRequirements { 24 | public: 25 | DefaultExtExecRequirements(const ThreadFilter& threadFilter) : _threadFilter(threadFilter) { } 26 | 27 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 28 | if (config.disabled) return false; 29 | if (config.activeThreadOnly && !sentInfoWrapper.isActiveThread()) return false; 30 | if (!_threadFilter.isThreadAllowed(sentInfoWrapper, config)) return false; 31 | if (!meetsConsoleAndClipboardRequirements(sentInfoWrapper, config)) return false; 32 | 33 | return true; 34 | } 35 | private: 36 | const ThreadFilter& _threadFilter; 37 | 38 | bool meetsConsoleAndClipboardRequirements( 39 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const 40 | { 41 | static const wstring _consoleThreadName = L"Console"; 42 | static const wstring _clipboardThreadName = L"Clipboard"; 43 | wstring threadName = sentInfoWrapper.getThreadName(); 44 | 45 | switch (config.skipConsoleAndClipboard) { 46 | case ExtensionConfig::ConsoleClipboardMode::SkipAll: 47 | if (sentInfoWrapper.threadIsConsoleOrClipboard()) return false; 48 | break; 49 | case ExtensionConfig::ConsoleClipboardMode::SkipConsole: 50 | if (threadName == _consoleThreadName) return false; 51 | break; 52 | case ExtensionConfig::ConsoleClipboardMode::SkipClipboard: 53 | if (threadName == _clipboardThreadName) return false; 54 | break; 55 | } 56 | 57 | return true; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/Extension.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "_Libraries/winmsg.h" 3 | #include "Extension.h" 4 | #include "ExtensionDepsContainer.h" 5 | 6 | const string _backupModuleName = "TextLogger"; 7 | ExtensionDepsContainer* _deps = nullptr; 8 | 9 | inline void allocateResources(const HMODULE& handle) { 10 | _deps = new DefaultExtensionDepsContainer(handle); 11 | _deps->getConfigRetriever().getConfig(true); // initialize default config if not found in ini 12 | } 13 | 14 | inline void deallocateResources() { 15 | if (_deps != nullptr) delete _deps; 16 | _deps = nullptr; 17 | } 18 | 19 | 20 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 21 | { 22 | switch (ul_reason_for_call) 23 | { 24 | case DLL_PROCESS_ATTACH: 25 | try { 26 | allocateResources(hModule); 27 | } 28 | catch (exception& ex) { 29 | showErrorMessage(ex.what(), _backupModuleName); 30 | deallocateResources(); 31 | throw; 32 | } 33 | break; 34 | case DLL_PROCESS_DETACH: 35 | deallocateResources(); 36 | break; 37 | } 38 | 39 | return TRUE; 40 | } 41 | 42 | /* 43 | Param sentence: sentence received by Textractor (UTF-16). Can be modified, Textractor will receive this modification only if true is returned. 44 | Param sentenceInfo: contains miscellaneous info about the sentence (see README). 45 | Return value: whether the sentence was modified. 46 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 47 | The sentence will be destroyed if it is empty or if you call Skip(). 48 | This function may be run concurrently with itself: please make sure it's thread safe. 49 | It will not be run concurrently with DllMain. 50 | */ 51 | bool ProcessSentence(wstring& sentence, SentenceInfo sentenceInfo) 52 | { 53 | try { 54 | SentenceInfoWrapper sentInfoWrapper(sentenceInfo); 55 | TextLogger& textLogger = _deps->getTextLogger(); 56 | 57 | textLogger.log(sentence, sentInfoWrapper); 58 | } 59 | catch (exception& ex) { 60 | string appName = _deps != nullptr ? _deps->moduleName() : _backupModuleName; 61 | showErrorMessage(ex.what(), appName); 62 | } 63 | 64 | return false; 65 | } -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/Extension.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | struct InfoForExtension 12 | { 13 | const char* name; 14 | int64_t value; 15 | }; 16 | 17 | struct SentenceInfo 18 | { 19 | const InfoForExtension* infoArray; 20 | int64_t operator[](std::string propertyName) 21 | { 22 | for (auto info = infoArray; info->name; ++info) // nullptr name marks end of info array 23 | if (propertyName == info->name) return info->value; 24 | return *(int*)0xcccc = 0; // gives better error message than alternatives 25 | } 26 | }; 27 | 28 | struct SKIP {}; 29 | inline void Skip() { throw SKIP(); } 30 | 31 | 32 | class SentenceInfoWrapper { 33 | public: 34 | SentenceInfoWrapper(SentenceInfo& sentenceInfo) : _sentenceInfo(sentenceInfo) { } 35 | 36 | bool isActiveThread() { 37 | return _sentenceInfo["current select"]; 38 | } 39 | 40 | bool threadIsConsoleOrClipboard() { 41 | return getProcessId() == 0; 42 | } 43 | 44 | wstring getProcessIdW() { 45 | return to_wstring(getProcessId()); 46 | } 47 | 48 | DWORD getProcessIdD() { 49 | return static_cast(getProcessId()); 50 | } 51 | 52 | int64_t getProcessId() { 53 | return _sentenceInfo["process id"]; 54 | } 55 | 56 | wstring getThreadNumberW() { 57 | int64_t threadNum = getThreadNumber(); 58 | return to_wstring(threadNum); 59 | } 60 | 61 | int64_t getThreadNumber() { 62 | return _sentenceInfo["text number"]; 63 | } 64 | 65 | wstring getThreadName() { 66 | int64_t threadNamePtr = _sentenceInfo["text name"]; 67 | return wstring(reinterpret_cast(threadNamePtr)); 68 | } 69 | private: 70 | SentenceInfo _sentenceInfo; 71 | }; 72 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/ExtensionDepsContainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TextLogger.h" 3 | #include "File/Writer/DirCreatorFileWriter.h" 4 | #include "File/Writer/WinApiFileWriter.h" 5 | #include 6 | 7 | 8 | class ExtensionDepsContainer { 9 | public: 10 | virtual ~ExtensionDepsContainer() { } 11 | 12 | virtual string moduleName() = 0; 13 | virtual TextLogger& getTextLogger() = 0; 14 | virtual ConfigRetriever& getConfigRetriever() = 0; 15 | }; 16 | 17 | 18 | class DefaultExtensionDepsContainer : public ExtensionDepsContainer { 19 | public: 20 | DefaultExtensionDepsContainer(const HMODULE& handle) { 21 | _moduleName = getModuleName(handle); 22 | 23 | _fileTracker = make_unique(); 24 | _baseConfigRetriever = make_unique( 25 | _iniFileName, StrHelper::convertToW(_moduleName)); 26 | _mainConfigRetriever = make_unique( 27 | *_baseConfigRetriever, *_fileTracker, _iniFileName); 28 | 29 | _keyGenerator = make_unique(); 30 | _threadTracker = make_unique(); 31 | _threadFilter = make_unique(*_keyGenerator, *_threadTracker); 32 | _procNameRetriever = make_unique(); 33 | _textHandler = make_unique(*_procNameRetriever); 34 | _execRequirements = make_unique(*_threadFilter); 35 | _dirCreator = make_unique(); 36 | 37 | _baseFileWriter = make_unique(); 38 | _mainFileWriter = make_unique(*_baseFileWriter, *_dirCreator); 39 | 40 | _textLogger = make_unique(*_mainConfigRetriever, *_keyGenerator, 41 | *_textHandler, *_threadTracker, *_mainFileWriter, *_execRequirements); 42 | } 43 | 44 | virtual string moduleName() override { 45 | return _moduleName; 46 | } 47 | 48 | virtual TextLogger& getTextLogger() override { 49 | return *_textLogger; 50 | } 51 | 52 | virtual ConfigRetriever& getConfigRetriever() override { 53 | return *_mainConfigRetriever; 54 | } 55 | private: 56 | const string _iniFileName = "Textractor.ini"; 57 | string _moduleName; 58 | 59 | unique_ptr _baseConfigRetriever = nullptr; 60 | unique_ptr _mainConfigRetriever = nullptr; 61 | unique_ptr _fileTracker = nullptr; 62 | unique_ptr _dirCreator = nullptr; 63 | unique_ptr _keyGenerator = nullptr; 64 | unique_ptr _threadTracker = nullptr; 65 | unique_ptr _threadFilter = nullptr; 66 | unique_ptr _procNameRetriever = nullptr; 67 | unique_ptr _textHandler = nullptr; 68 | unique_ptr _execRequirements = nullptr; 69 | unique_ptr _baseFileWriter = nullptr; 70 | unique_ptr _mainFileWriter = nullptr; 71 | unique_ptr _textLogger = nullptr; 72 | }; 73 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | 23 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 24 | { 25 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 26 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 27 | } 28 | } 29 | catch (SKIP) 30 | { 31 | *sentence = L'\0'; 32 | } 33 | return sentence; 34 | } -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/DirectoryCreator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../_Libraries/strhelper.h" 4 | #include "../_Libraries/winmsg.h" 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | class DirectoryCreator { 12 | public: 13 | virtual ~DirectoryCreator() { } 14 | virtual bool createDir(const wstring& dirPath) const = 0; 15 | virtual bool createDir(const string& dirPath) const = 0; 16 | protected: 17 | static constexpr char SEPARATORS[] = { '\\', '/' }; 18 | static constexpr char NO_SEPARATOR = '\0'; 19 | }; 20 | 21 | 22 | class WinApiDirectoryCreator : public DirectoryCreator { 23 | public: 24 | bool createDir(const wstring& dirPath) const override { 25 | return createDir(StrHelper::convertFromW(dirPath)); 26 | } 27 | 28 | bool createDir(const string& dirPath) const override { 29 | char separator = determineSeparator(dirPath); 30 | 31 | string parsedDirPath = containsFileExtension(dirPath) ? 32 | parseDirectoryFromFilePath(dirPath) : dirPath; 33 | 34 | return runMkDirCommand(parsedDirPath); 35 | } 36 | private: 37 | bool containsFileExtension(const string& path, char separator = NO_SEPARATOR) const { 38 | size_t periodIndex = path.rfind(L'.'); 39 | if (periodIndex == string::npos) return false; 40 | 41 | if (separator == NO_SEPARATOR) separator = determineSeparator(path); 42 | if (separator == NO_SEPARATOR) return true; 43 | 44 | size_t separatorIndex = path.rfind(path); 45 | return periodIndex > separatorIndex; 46 | } 47 | 48 | string parseDirectoryFromFilePath(const string& path, char separator = NO_SEPARATOR) const { 49 | if (separator == NO_SEPARATOR) separator = determineSeparator(path); 50 | if (separator == NO_SEPARATOR) return path; 51 | 52 | size_t separatorIndex = path.rfind(separator); 53 | string dirPath = path.substr(0, separatorIndex); 54 | return !dirPath.empty() ? dirPath : path; 55 | } 56 | 57 | char determineSeparator(const string& dirPath) const { 58 | for (char sep : SEPARATORS) { 59 | if (dirPath.find(sep) != string::npos) return sep; 60 | } 61 | 62 | return NO_SEPARATOR; 63 | } 64 | 65 | bool runMkDirCommand(const string& dirPath) const { 66 | string command = "cmd /C mkdir \"" + dirPath + "\" > nul 2>&1"; 67 | return runProcess(command); 68 | } 69 | 70 | bool runProcess(const string& command) const { 71 | STARTUPINFOW si; 72 | PROCESS_INFORMATION pi; 73 | 74 | ZeroMemory(&si, sizeof(si)); 75 | si.cb = sizeof(si); 76 | si.wShowWindow = SW_HIDE; 77 | ZeroMemory(&pi, sizeof(pi)); 78 | wstring commandW = StrHelper::convertToW(command); 79 | 80 | if (!CreateProcessW(NULL, (wchar_t*)(commandW.c_str()), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) 81 | { 82 | showErrorMessage("Failed to run command '" + command 83 | + "'. ErrCode: " + to_string(GetLastError()), "TextLogger"); 84 | 85 | return false; 86 | } 87 | 88 | WaitForSingleObject(pi.hProcess, 3000); 89 | CloseHandle(pi.hProcess); 90 | CloseHandle(pi.hThread); 91 | return true; 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/FileDeleter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | using namespace std; 5 | 6 | 7 | class FileDeleter { 8 | public: 9 | virtual ~FileDeleter() { } 10 | virtual void deleteFile(const string& filePath) = 0; 11 | }; 12 | 13 | 14 | class CRemoveFileDeleter : public FileDeleter { 15 | public: 16 | void deleteFile(const string& filePath) override { 17 | remove(filePath.c_str()); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/FileReader.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | class FileReader { 11 | public: 12 | virtual ~FileReader() { } 13 | virtual bool fileExists(const string& filePath) = 0; 14 | virtual vector readLines(const string& filePath) = 0; 15 | virtual void readLines(const string& filePath, const function& lineAction) = 0; 16 | virtual string readLine(const string& filePath, size_t i) = 0; 17 | virtual string readLine(const string& filePath, const function condition) = 0; 18 | virtual string readAll(const string& filePath) = 0; 19 | }; 20 | 21 | 22 | class NoFileReader : public FileReader { 23 | public: 24 | bool fileExists(const string& filePath) override { return false; } 25 | vector readLines(const string& filePath) override { return vector{}; }; 26 | void readLines(const string& filePath, const function& lineAction) override { } 27 | string readLine(const string& filePath, size_t i) override { return ""; } 28 | string readLine(const string& filePath, const function condition) override { return ""; } 29 | string readAll(const string& filePath) override { return ""; } 30 | }; 31 | 32 | 33 | class FstreamFileReader : public FileReader { 34 | public: 35 | bool fileExists(const string& filePath) override { 36 | ifstream f(filePath, ios_base::in); 37 | return fileExists(f); 38 | } 39 | 40 | vector readLines(const string& filePath) override { 41 | vector lines{}; 42 | readLines(filePath, [&lines](const string& line) { lines.push_back(line); }); 43 | return lines; 44 | } 45 | 46 | void readLines(const string& filePath, const function& lineAction) override { 47 | readLine(filePath, [&lineAction](const string& line) { 48 | lineAction(line); 49 | return false; 50 | }); 51 | } 52 | 53 | string readLine(const string& filePath, size_t i) override { 54 | size_t currI = 0; 55 | 56 | return readLine(filePath, [i, &currI](const string& line) { 57 | return i == currI++; 58 | }); 59 | } 60 | 61 | string readLine(const string& filePath, const function condition) override { 62 | ifstream f(filePath, ios_base::in); 63 | if (!fileExists(f)) return ""; 64 | char* line = new char[MAX_LENGTH]; 65 | 66 | while (f.getline(line, MAX_LENGTH)) { 67 | if (condition(line)) return line; 68 | } 69 | 70 | return ""; 71 | } 72 | 73 | string readAll(const string& filePath) override { 74 | ifstream f(filePath, ios_base::in); 75 | if (!fileExists(f)) return ""; 76 | 77 | stringstream buffer; 78 | buffer << f.rdbuf(); 79 | return buffer.str(); 80 | } 81 | private: 82 | static const int MAX_LENGTH = 524288; 83 | 84 | bool fileExists(const ifstream& f) const { 85 | return f.good(); 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/Writer/DirCreatorFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include "../DirectoryCreator.h" 5 | #include 6 | 7 | class DirCreatorFileWriter : public FileWriter { 8 | public: 9 | DirCreatorFileWriter(FileWriter& mainFileWriter, DirectoryCreator& dirCreator) 10 | : _mainFileWriter(mainFileWriter), _dirCreator(dirCreator) { } 11 | 12 | void writeToFile(const string& filePath, const string& text) override { 13 | createDirIfFileNotSeen(filePath); 14 | _mainFileWriter.writeToFile(filePath, text); 15 | } 16 | 17 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 18 | createDirIfFileNotSeen(filePath); 19 | _mainFileWriter.writeToFile(filePath, lines, startIndex); 20 | } 21 | 22 | void appendToFile(const string& filePath, const string& text) override { 23 | createDirIfFileNotSeen(filePath); 24 | _mainFileWriter.appendToFile(filePath, text); 25 | } 26 | 27 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 28 | createDirIfFileNotSeen(filePath); 29 | _mainFileWriter.appendToFile(filePath, lines, startIndex); 30 | } 31 | private: 32 | FileWriter& _mainFileWriter; 33 | DirectoryCreator& _dirCreator; 34 | unordered_set _seenFiles{}; 35 | 36 | void createDirIfFileNotSeen(const string& filePath) { 37 | if (fileSeen(filePath)) return; 38 | _dirCreator.createDir(filePath); 39 | _seenFiles.insert(filePath); 40 | } 41 | 42 | bool fileSeen(const string& filePath) { 43 | return _seenFiles.find(filePath) != _seenFiles.end(); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/Writer/FileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | class FileWriter { 9 | public: 10 | virtual ~FileWriter() { } 11 | virtual void writeToFile(const string& filePath, const string& text) = 0; 12 | virtual void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 13 | virtual void appendToFile(const string& filePath, const string& text) = 0; 14 | virtual void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 15 | }; 16 | 17 | 18 | class NoFileWriter : public FileWriter { 19 | public: 20 | void writeToFile(const string& filePath, const string& text) override { } 21 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 22 | void appendToFile(const string& filePath, const string& text) override { } 23 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/Writer/FireAndForgetFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | class FireAndForgetFileWriter : public FileWriter { 11 | public: 12 | FireAndForgetFileWriter(FileWriter& mainWriter) : _mainWriter(mainWriter) { } 13 | 14 | ~FireAndForgetFileWriter() { 15 | // ensure all ongoing write activity is done before deallocating 16 | _destrCalled = true; 17 | waitForAllActionsDone(100, 5000); 18 | } 19 | 20 | void writeToFile(const string& filePath, const string& text) override { 21 | thread([this, filePath, text]() { writeToFileBase(filePath, text); }).detach(); 22 | } 23 | 24 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 25 | thread([this, filePath, lines, startIndex]() { 26 | writeToFileBase(filePath, lines, startIndex); }).detach(); 27 | } 28 | 29 | void appendToFile(const string& filePath, const string& text) override { 30 | thread([this, filePath, text]() { appendToFileBase(filePath, text); }).detach(); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | thread([this, filePath, lines, startIndex]() { 35 | appendToFileBase(filePath, lines, startIndex); }).detach(); 36 | } 37 | private: 38 | atomic _activeCount = 0; 39 | atomic_bool _destrCalled = false; 40 | FileWriter& _mainWriter; 41 | 42 | void writeToFileBase(const string& filePath, const string& text) { 43 | trackAction([this, &filePath, &text]() { 44 | _mainWriter.writeToFile(filePath, text); 45 | }); 46 | } 47 | 48 | void writeToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 49 | trackAction([this, &filePath, &lines, startIndex]() { 50 | _mainWriter.writeToFile(filePath, lines, startIndex); 51 | }); 52 | } 53 | 54 | void appendToFileBase(const string& filePath, const string& text) { 55 | trackAction([this, &filePath, &text]() { 56 | _mainWriter.appendToFile(filePath, text); 57 | }); 58 | } 59 | 60 | void appendToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 61 | trackAction([this, &filePath, &lines, startIndex]() { 62 | _mainWriter.appendToFile(filePath, lines, startIndex); 63 | }); 64 | } 65 | 66 | void trackAction(const function& action) { 67 | if (_destrCalled) return; 68 | _activeCount++; 69 | 70 | try { 71 | action(); 72 | _activeCount--; 73 | } 74 | catch (const exception&) { 75 | _activeCount--; 76 | throw; 77 | } 78 | } 79 | 80 | void waitForAllActionsDone(DWORD intervalMs, DWORD maxWaitMs) { 81 | DWORD waitMs = 0; 82 | 83 | while (_activeCount > 0 && waitMs < maxWaitMs) { 84 | Sleep(intervalMs); 85 | waitMs += intervalMs; 86 | } 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/File/Writer/TruncatableFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include "../FileTruncater.h" 5 | 6 | 7 | class TruncatableFileWriter : public FileWriter { 8 | public: 9 | TruncatableFileWriter(FileWriter& mainWriter, FileTruncater& truncater) 10 | : _mainWriter(mainWriter), _truncater(truncater) { } 11 | 12 | void writeToFile(const string& filePath, const string& text) override { 13 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 14 | _mainWriter.writeToFile(filePath, text); 15 | _truncater.truncateFile(filePath); 16 | }); 17 | } 18 | 19 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 20 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 21 | _mainWriter.writeToFile(filePath, lines, startIndex); 22 | _truncater.truncateFile(filePath); 23 | }); 24 | } 25 | 26 | void appendToFile(const string& filePath, const string& text) override { 27 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 28 | _mainWriter.appendToFile(filePath, text); 29 | _truncater.truncateFile(filePath); 30 | }); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 35 | _mainWriter.appendToFile(filePath, lines, startIndex); 36 | _truncater.truncateFile(filePath); 37 | }); 38 | } 39 | private: 40 | DefaultLockerMap _lockerMap; 41 | FileWriter& _mainWriter; 42 | FileTruncater& _truncater; 43 | }; 44 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/ProcessNameRetriever.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class ProcessNameRetriever { 9 | public: 10 | virtual ~ProcessNameRetriever() { } 11 | virtual wstring getProcessName(DWORD pid) const = 0; 12 | }; 13 | 14 | class WinApiProcessNameRetriever : public ProcessNameRetriever { 15 | public: 16 | wstring getProcessName(DWORD pid) const override { 17 | HANDLE hProcess = GetProcessHandle(pid); 18 | 19 | if (isInvalidHandle(hProcess)) { 20 | cerr << "Error opening process. Error code: " << GetLastError() << endl; 21 | return L""; 22 | } 23 | 24 | wstring processNameW = getProcessName(hProcess); 25 | CloseHandle(hProcess); 26 | return processNameW; 27 | } 28 | private: 29 | static constexpr wchar_t PERIOD_CH = L'.'; 30 | 31 | HANDLE GetProcessHandle(DWORD pid) const { 32 | return OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); 33 | } 34 | 35 | bool isInvalidHandle(HANDLE handle) const { 36 | return handle == nullptr || handle == INVALID_HANDLE_VALUE; 37 | } 38 | 39 | wstring getProcessName(HANDLE handle) const { 40 | TCHAR szProcessName[MAX_PATH] = TEXT(""); 41 | 42 | if (!GetModuleBaseName(handle, nullptr, szProcessName, sizeof(szProcessName) / sizeof(TCHAR))) { 43 | cerr << "Error getting process name. Error code: " << GetLastError() << endl; 44 | return L""; 45 | } 46 | 47 | wstring processName = wstring(szProcessName); 48 | return formatProcessName(processName); 49 | } 50 | 51 | wstring formatProcessName(wstring processName) const { 52 | size_t periodIndex = processName.rfind(PERIOD_CH); 53 | if (periodIndex != wstring::npos) { 54 | processName = processName.substr(0, periodIndex); 55 | } 56 | 57 | return processName; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/TextLogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "_Libraries/strhelper.h" 4 | #include "Extension.h" 5 | #include "ExtensionConfig.h" 6 | #include "ExtExecRequirements.h" 7 | #include "LoggerTextHandle.h" 8 | #include "File/Writer/FileWriter.h" 9 | #include "Threading/ThreadKeyGenerator.h" 10 | #include "Threading/ThreadFilter.h" 11 | #include "Threading/ThreadTracker.h" 12 | using namespace std; 13 | 14 | class TextLogger { 15 | public: 16 | virtual ~TextLogger() { } 17 | virtual void log(const wstring& sentence, SentenceInfoWrapper& sentInfoWrapper) = 0; 18 | }; 19 | 20 | class FileTextLogger : public TextLogger { 21 | public: 22 | FileTextLogger(ConfigRetriever& configRetriever, 23 | const ThreadKeyGenerator& keyGenerator, const LoggerTextHandler& textHandler, 24 | ThreadTracker& threadTracker, FileWriter& fileWriter, ExtExecRequirements& execRequirements) 25 | : _configRetriever(configRetriever), _keyGenerator(keyGenerator), 26 | _textHandler(textHandler), _threadTracker(threadTracker), 27 | _fileWriter(fileWriter), _execRequirements(execRequirements) { } 28 | 29 | void log(const wstring& sentence, SentenceInfoWrapper& sentInfoWrapper) override { 30 | ExtensionConfig config = getConfig(); 31 | if (!_execRequirements.meetsRequirements(sentInfoWrapper, config)) return; 32 | 33 | wstring threadKey = createThreadKey(sentInfoWrapper, config); 34 | wstring logFilePath = _textHandler.getLogFilePath(threadKey, sentInfoWrapper, config); 35 | wstring msg = _textHandler.createLogMsg(sentence, threadKey, sentInfoWrapper, config); 36 | 37 | appendToFile(logFilePath, msg); 38 | } 39 | private: 40 | ConfigRetriever& _configRetriever; 41 | const ThreadKeyGenerator& _keyGenerator; 42 | const LoggerTextHandler& _textHandler; 43 | ThreadTracker& _threadTracker; 44 | FileWriter& _fileWriter; 45 | ExtExecRequirements& _execRequirements; 46 | 47 | ExtensionConfig getConfig() { 48 | return _configRetriever.getConfig(); 49 | } 50 | 51 | wstring createThreadKey(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) { 52 | size_t threadIndex = _threadTracker.trackThreadNameIndex(sentInfoWrapper); 53 | wstring threadKey = _keyGenerator.getThreadKey(threadIndex, sentInfoWrapper, config); 54 | return threadKey; 55 | } 56 | 57 | void appendToFile(const wstring& logFilePath, const wstring& msg) { 58 | _fileWriter.appendToFile( 59 | StrHelper::convertFromW(logFilePath), StrHelper::convertFromW(msg)); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/Threading/ThreadFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include "../ExtensionConfig.h" 5 | #include "ThreadKeyGenerator.h" 6 | #include "ThreadTracker.h" 7 | using FilterMode = ExtensionConfig::FilterMode; 8 | 9 | 10 | class ThreadFilter { 11 | public: 12 | virtual ~ThreadFilter() { } 13 | virtual bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 14 | }; 15 | 16 | 17 | class NoThreadFilter : public ThreadFilter { 18 | public: 19 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 20 | const ExtensionConfig& config) const override { 21 | return true; 22 | } 23 | }; 24 | 25 | class AllThreadFilter : public ThreadFilter { 26 | public: 27 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 28 | const ExtensionConfig& config) const override { 29 | return false; 30 | } 31 | }; 32 | 33 | 34 | class DefaultThreadFilter : public ThreadFilter { 35 | public: 36 | DefaultThreadFilter(const ThreadKeyGenerator& keyGenerator, ThreadTracker& threadTracker) 37 | : _keyGenerator(keyGenerator), _threadTracker(threadTracker) { } 38 | 39 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 40 | const ExtensionConfig& config) const override 41 | { 42 | size_t threadIndex = _threadTracker.trackThreadNameIndex(sentInfoWrapper); 43 | wstring threadKey = _keyGenerator.getThreadKey(threadIndex, sentInfoWrapper, config); 44 | wstring threadName = sentInfoWrapper.getThreadName(); 45 | 46 | switch (config.threadKeyFilterMode) { 47 | case FilterMode::Blacklist: 48 | return isInList(threadKey, threadName, config) == false; 49 | case FilterMode::Whitelist: 50 | return isInList(threadKey, threadName, config) == true; 51 | default: 52 | return true; 53 | } 54 | } 55 | private: 56 | const ThreadKeyGenerator& _keyGenerator; 57 | ThreadTracker& _threadTracker; 58 | 59 | bool isInList(const wstring& threadKey, 60 | const wstring& threadName, const ExtensionConfig& config) const 61 | { 62 | if (isInList(config.threadKeyFilterList, threadKey, config.threadKeyFilterListDelim)) return true; 63 | if (isInList(config.threadKeyFilterList, threadName, config.threadKeyFilterListDelim)) return true; 64 | 65 | return false; 66 | } 67 | 68 | bool isInList(const wstring& list, const wstring& subStr, const wstring& delim) const { 69 | if (subStr.length() > list.length()) return false; 70 | wstring searchStr = subStr + delim; 71 | size_t index = list.find(searchStr); 72 | if (index != wstring::npos) return true; 73 | 74 | index = list.rfind(subStr); 75 | if (index == list.length() - subStr.length()) return true; 76 | 77 | return false; 78 | } 79 | }; -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/Threading/ThreadKeyGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include "../ExtensionConfig.h" 5 | #include 6 | 7 | class ThreadKeyGenerator { 8 | public: 9 | virtual ~ThreadKeyGenerator() { } 10 | virtual wstring getThreadKey(size_t threadIndex, 11 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 12 | }; 13 | 14 | 15 | class DefaultThreadKeyGenerator : public ThreadKeyGenerator { 16 | public: 17 | wstring getThreadKey(size_t threadIndex, 18 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override 19 | { 20 | wstring threadKey = sentInfoWrapper.getThreadName(); 21 | if (!config.onlyThreadNameAsKey) threadKey += L"-" + to_wstring(threadIndex); 22 | return threadKey; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/Threading/ThreadTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../_Libraries/Locker.h" 4 | #include "../Extension.h" 5 | #include 6 | using namespace std; 7 | 8 | 9 | class ThreadTracker { 10 | public: 11 | virtual ~ThreadTracker() { } 12 | virtual size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) = 0; 13 | }; 14 | 15 | 16 | class MapThreadTracker : public ThreadTracker { 17 | public: 18 | size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) override { 19 | wstring threadName, threadId = createThreadId(sentInfoWrap, threadName); 20 | return trackThreadNameIndexBase(threadId, threadName); 21 | } 22 | private: 23 | const wstring THREAD_ID_DELIM = L":"; 24 | unordered_map _threadNameMap = { }; 25 | unordered_map _threadIdMap = { }; 26 | mutable DefaultLockerMap _lockerMap; 27 | 28 | size_t trackThreadNameIndexBase(const wstring& threadId, const wstring& threadName) { 29 | size_t index = 0; 30 | 31 | _lockerMap.getOrCreateLocker(threadId).lock([this, &threadId, &threadName, &index]() { 32 | if (!mapHasThreadId(threadId)) 33 | _threadIdMap[threadId] = addOrUpdateThreadNameMap(threadName); 34 | 35 | index = _threadIdMap[threadId]; 36 | }); 37 | 38 | return index; 39 | } 40 | 41 | wstring createThreadId(SentenceInfoWrapper& sentInfoWrap, wstring& threadNameOut) const { 42 | wstring processId = sentInfoWrap.getProcessIdW(); 43 | threadNameOut = sentInfoWrap.getThreadName(); 44 | wstring threadNum = sentInfoWrap.getThreadNumberW(); 45 | wstring delim = THREAD_ID_DELIM; 46 | 47 | wstring threadId = processId + delim + threadNameOut + delim + threadNum; 48 | return threadId; 49 | } 50 | 51 | bool mapHasThreadName(const wstring& threadName) const { 52 | return mapHasKey(_threadNameMap, threadName); 53 | } 54 | 55 | bool mapHasThreadId(const wstring& threadId) const { 56 | return mapHasKey(_threadIdMap, threadId); 57 | } 58 | 59 | bool mapHasKey(const unordered_map& map, const wstring& key) const { 60 | return map.find(key) != map.end(); 61 | } 62 | 63 | size_t addOrUpdateThreadNameMap(const wstring& threadName) { 64 | if (!mapHasThreadName(threadName)) _threadNameMap[threadName] = 1; 65 | else _threadNameMap[threadName]++; 66 | 67 | return _threadNameMap[threadName]; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/_Libraries/FileTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class FileTracker { 10 | public: 11 | virtual ~FileTracker() { } 12 | virtual int64_t getDateLastModifiedEpochs(const string& filePath) = 0; 13 | virtual int64_t getDateLastModifiedEpochs(const char* filePath) = 0; 14 | virtual int64_t getDateLastModifiedEpochs(const wstring& filePath) = 0; 15 | virtual int64_t getDateLastModifiedEpochs(const wchar_t* filePath) = 0; 16 | }; 17 | 18 | 19 | class WinApiFileTracker : public FileTracker { 20 | public: 21 | int64_t getDateLastModifiedEpochs(const string& filePath) override { 22 | return getDateLastModifiedEpochs(StrHelper::convertToW(filePath)); 23 | } 24 | 25 | int64_t getDateLastModifiedEpochs(const char* filePath) override { 26 | return getDateLastModifiedEpochs(string(filePath)); 27 | } 28 | 29 | int64_t getDateLastModifiedEpochs(const wstring& filePath) override { 30 | return getDateLastModifiedEpochs(filePath.c_str()); 31 | } 32 | 33 | int64_t getDateLastModifiedEpochs(const wchar_t* filePath) override { 34 | HANDLE fHandle = getFileHandle(filePath); 35 | if (!isValidHandle(fHandle)) return 0; 36 | 37 | FILETIME lastWrite = getFileLastWriteTime(fHandle); 38 | CloseHandle(fHandle); 39 | 40 | return convertTo64(lastWrite); 41 | } 42 | private: 43 | HANDLE getFileHandle(const wchar_t* filePath) { 44 | return CreateFile(filePath, GENERIC_READ, 45 | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); 46 | } 47 | 48 | bool isValidHandle(const HANDLE& handle) { 49 | return handle != INVALID_HANDLE_VALUE; 50 | } 51 | 52 | FILETIME getFileLastWriteTime(const HANDLE& handle) { 53 | FILETIME lastWrite; 54 | GetFileTime(handle, NULL, NULL, &lastWrite); 55 | return lastWrite; 56 | } 57 | 58 | int64_t convertTo64(FILETIME fTime) { 59 | ULARGE_INTEGER ularge{}; 60 | ularge.LowPart = fTime.dwLowDateTime; 61 | ularge.HighPart = fTime.dwHighDateTime; 62 | return static_cast(ularge.QuadPart); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/_Libraries/datetime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | inline std::string getCurrentDateTime() { 7 | auto currentTime = std::chrono::system_clock::now(); 8 | time_t currentTime_t = std::chrono::system_clock::to_time_t(currentTime); 9 | 10 | struct tm currentTime_tm; 11 | localtime_s(¤tTime_tm, ¤tTime_t); 12 | 13 | char buffer[80]; 14 | strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ¤tTime_tm); 15 | return std::string(buffer); 16 | } 17 | -------------------------------------------------------------------------------- /Textractor.TextLogger/src/Textractor.TextLogger/_Libraries/winmsg.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | inline void showErrorMessage(const string& message, const string& appName) { 9 | string tag = appName + "-Error"; 10 | MessageBoxA(nullptr, message.c_str(), tag.c_str(), MB_ICONERROR | MB_OK); 11 | } 12 | 13 | inline string getModuleName(const HMODULE& handle) { 14 | try { 15 | wchar_t buffer[1024]; 16 | GetModuleFileName(handle, buffer, sizeof(buffer) / sizeof(wchar_t)); 17 | 18 | string module = StrHelper::convertFromW(buffer); 19 | size_t pathDelimIndex = module.rfind('\\'); 20 | if (pathDelimIndex != string::npos) module = module.substr(pathDelimIndex + 1); 21 | 22 | size_t extIndex = module.rfind('.'); 23 | if (extIndex != string::npos) module = module.erase(extIndex); 24 | 25 | return module; 26 | } 27 | catch (exception& ex) { 28 | string errMsg = "Failed to retrieve extension name.\n"; 29 | errMsg += ex.what(); 30 | showErrorMessage(errMsg.c_str(), "VndbNameMapper"); 31 | throw; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/img/config-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TranslationCache/img/config-example.png -------------------------------------------------------------------------------- /Textractor.TranslationCache/img/copy-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TranslationCache/img/copy-extension.png -------------------------------------------------------------------------------- /Textractor.TranslationCache/img/extension-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.TranslationCache/img/extension-order.png -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/Cache/MemoryTextMapCache.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../_Libraries/Locker.h" 4 | #include "TextMapCache.h" 5 | 6 | 7 | class MemoryTextMapCache : public TextMapCache { 8 | public: 9 | MemoryTextMapCache(const TextFormatter& formatter) : _formatter(formatter) { } 10 | MemoryTextMapCache(const TextFormatter& formatter, 11 | const unordered_map& preCache) : _formatter(formatter), _cache(preCache) { } 12 | 13 | bool keyExists(const wstring& key) const override { 14 | wstring formattedKey = _formatter.format(key); 15 | _writeLocker.waitForUnlock(); 16 | return isInCache(formattedKey); 17 | } 18 | 19 | wstring readFromCache(const wstring& key) const override { 20 | wstring formattedKey = _formatter.format(key); 21 | _writeLocker.waitForUnlock(); 22 | return isInCache(formattedKey) ? _cache.at(formattedKey) : L""; 23 | } 24 | 25 | unordered_map readAllFromCache() const override { 26 | _writeLocker.waitForUnlock(); 27 | return _cache; 28 | } 29 | 30 | void writeToCache(const wstring& key, const wstring& value) override { 31 | wstring formattedKey = _formatter.format(key); 32 | wstring formattedValue = _formatter.format(value); 33 | 34 | _writeLocker.lock([this, &formattedKey, formattedValue]() { 35 | writeToCacheBase(formattedKey, formattedValue); 36 | }); 37 | } 38 | 39 | void writeAllToCache(const unordered_map cache, bool reload = false) override { 40 | _writeLocker.lock([this, &cache, reload]() { 41 | if (reload) _cache.clear(); 42 | 43 | for (const auto& textPair : cache) { 44 | formatAndWriteToCache(textPair.first, textPair.second); 45 | } 46 | }); 47 | } 48 | 49 | void removeFromCache(const wstring& key) override { 50 | wstring formattedKey = _formatter.format(key); 51 | 52 | _writeLocker.lock([this, &formattedKey]() { 53 | removeFromCacheBase(formattedKey); 54 | }); 55 | } 56 | 57 | void clearCache() override { 58 | _writeLocker.lock([this]() { 59 | _cache.clear(); 60 | }); 61 | } 62 | private: 63 | const TextFormatter& _formatter; 64 | unordered_map _cache; 65 | mutable BasicLocker _writeLocker; 66 | 67 | bool isInCache(const wstring& key) const { 68 | return _cache.find(key) != _cache.end(); 69 | } 70 | 71 | void formatAndWriteToCache(const wstring& key, const wstring& value) { 72 | writeToCacheBase(_formatter.format(key), _formatter.format(value)); 73 | } 74 | 75 | void writeToCacheBase(const wstring& key, const wstring& value) { 76 | _cache[key] = value; 77 | } 78 | 79 | void removeFromCacheBase(const wstring& key) { 80 | _cache.erase(key); 81 | } 82 | }; -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/CacheFilePathFormatter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "_Libraries/strhelper.h" 4 | 5 | 6 | class CacheFilePathFormatter { 7 | public: 8 | virtual ~CacheFilePathFormatter() { } 9 | virtual string format(wstring cacheFilePath) = 0; 10 | virtual string format(string cacheFilePath) = 0; 11 | }; 12 | 13 | 14 | class DefaultCacheFilePathFormatter : public CacheFilePathFormatter { 15 | public: 16 | DefaultCacheFilePathFormatter(const wstring& defaultFileName) : _defaultFileName(defaultFileName) { } 17 | 18 | string format(wstring cacheFilePath) override { 19 | if (cacheFilePath.find(L'/')) 20 | cacheFilePath = StrHelper::replace(cacheFilePath, L"/", L"\\"); 21 | 22 | if (cacheFilePath.empty() || cacheFilePath.find_last_of(_txtExtW) != cacheFilePath.length() - 1) { 23 | if (!cacheFilePath.empty() && cacheFilePath.back() != L'\\') cacheFilePath += L'\\'; 24 | cacheFilePath += _defaultFileName + _txtExtW; 25 | } 26 | 27 | return StrHelper::convertFromW(cacheFilePath); 28 | } 29 | 30 | string format(string cacheFilePath) override { 31 | return format(StrHelper::convertToW(cacheFilePath)); 32 | } 33 | private: 34 | const wstring _txtExtW = L".txt"; 35 | const string _txtExt = StrHelper::convertFromW(_txtExtW); 36 | const wstring _defaultFileName; 37 | }; 38 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/ConfigAdjustmentEvents.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "_Libraries/Locker.h" 4 | #include "Cache/TextMapCache.h" 5 | #include "ExtensionConfig.h" 6 | 7 | 8 | class ConfigAdjustmentEvents { 9 | public: 10 | virtual ~ConfigAdjustmentEvents() { } 11 | virtual void applyConfigAdjustments(const ExtensionConfig& config) = 0; 12 | }; 13 | 14 | 15 | class NoConfigAdjustmentEvents : public ConfigAdjustmentEvents { 16 | void applyConfigAdjustments(const ExtensionConfig& config) override { } 17 | }; 18 | 19 | 20 | class DefaultReadConfigAdjustmentEvents : public ConfigAdjustmentEvents { 21 | public: 22 | DefaultReadConfigAdjustmentEvents(TextMapCache& srcCache, TextMapCache& destCache) 23 | : _srcCache(srcCache), _destCache(destCache) { } 24 | 25 | void applyConfigAdjustments(const ExtensionConfig& config) override { 26 | if (config.cacheFilePath != _currCacheFilePath) 27 | changeCurrPathAndReloadCache(config.cacheFilePath); 28 | } 29 | private: 30 | BasicLocker _locker; 31 | wstring _currCacheFilePath; 32 | TextMapCache& _srcCache; 33 | TextMapCache& _destCache; 34 | 35 | void changeCurrPathAndReloadCache(const wstring& newCacheFilePath) { 36 | _locker.lock([this, &newCacheFilePath]() { 37 | if (newCacheFilePath == _currCacheFilePath) return; 38 | _currCacheFilePath = newCacheFilePath; 39 | reloadMemCache(); 40 | }); 41 | } 42 | 43 | void reloadMemCache() { 44 | unordered_map srcCacheMap = _srcCache.readAllFromCache(); 45 | _destCache.writeAllToCache(srcCacheMap, true); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/ExtExecRequirements.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "ExtensionConfig.h" 4 | #include "Extension.h" 5 | #include "Threading/ThreadFilter.h" 6 | 7 | 8 | class ExtExecRequirements { 9 | public: 10 | virtual ~ExtExecRequirements() { } 11 | virtual bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 12 | const ExtensionConfig& config, bool readMode) const = 0; 13 | }; 14 | 15 | 16 | class NoExtExecRequirements : public ExtExecRequirements { 17 | public: 18 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 19 | const ExtensionConfig& config, bool readMode) const override 20 | { 21 | return true; 22 | } 23 | }; 24 | 25 | 26 | class DefaultExtExecRequirements : public ExtExecRequirements { 27 | public: 28 | DefaultExtExecRequirements(const ThreadFilter& threadFilter) : _threadFilter(threadFilter) { } 29 | 30 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, 31 | const ExtensionConfig& config, bool readMode) const override 32 | { 33 | if (isDisabled(config)) return false; 34 | if (config.activeThreadOnly && !sentInfoWrapper.isActiveThread()) return false; 35 | if (!_threadFilter.isThreadAllowed(sentInfoWrapper, config)) return false; 36 | if (!meetsConsoleAndClipboardRequirements(sentInfoWrapper, config)) return false; 37 | 38 | return true; 39 | } 40 | private: 41 | const ThreadFilter& _threadFilter; 42 | 43 | bool isDisabled(const ExtensionConfig& config) const { 44 | return config.disabledMode == ExtensionConfig::DisabledMode::DisableAll; 45 | } 46 | 47 | bool meetsConsoleAndClipboardRequirements( 48 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const 49 | { 50 | static const wstring _consoleThreadName = L"Console"; 51 | static const wstring _clipboardThreadName = L"Clipboard"; 52 | wstring threadName = sentInfoWrapper.getThreadName(); 53 | 54 | switch (config.skipConsoleAndClipboard) { 55 | case ExtensionConfig::ConsoleClipboardMode::SkipAll: 56 | if (sentInfoWrapper.threadIsConsoleOrClipboard()) return false; 57 | break; 58 | case ExtensionConfig::ConsoleClipboardMode::SkipConsole: 59 | if (threadName == _consoleThreadName) return false; 60 | break; 61 | case ExtensionConfig::ConsoleClipboardMode::SkipClipboard: 62 | if (threadName == _clipboardThreadName) return false; 63 | break; 64 | } 65 | 66 | return true; 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/Extension.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | struct InfoForExtension 12 | { 13 | const char* name; 14 | int64_t value; 15 | }; 16 | 17 | struct SentenceInfo 18 | { 19 | const InfoForExtension* infoArray; 20 | int64_t operator[](std::string propertyName) 21 | { 22 | for (auto info = infoArray; info->name; ++info) // nullptr name marks end of info array 23 | if (propertyName == info->name) return info->value; 24 | return *(int*)0xcccc = 0; // gives better error message than alternatives 25 | } 26 | }; 27 | 28 | struct SKIP {}; 29 | inline void Skip() { throw SKIP(); } 30 | 31 | 32 | class SentenceInfoWrapper { 33 | public: 34 | SentenceInfoWrapper(SentenceInfo& sentenceInfo) : _sentenceInfo(sentenceInfo) { } 35 | 36 | bool isActiveThread() { 37 | return _sentenceInfo["current select"]; 38 | } 39 | 40 | bool threadIsConsoleOrClipboard() { 41 | return getProcessId() == 0; 42 | } 43 | 44 | wstring getProcessIdW() { 45 | return to_wstring(getProcessId()); 46 | } 47 | 48 | DWORD getProcessIdD() { 49 | return static_cast(getProcessId()); 50 | } 51 | 52 | int64_t getProcessId() { 53 | return _sentenceInfo["process id"]; 54 | } 55 | 56 | wstring getThreadNumberW() { 57 | int64_t threadNum = getThreadNumber(); 58 | return to_wstring(threadNum); 59 | } 60 | 61 | int64_t getThreadNumber() { 62 | return _sentenceInfo["text number"]; 63 | } 64 | 65 | wstring getThreadName() { 66 | int64_t threadNamePtr = _sentenceInfo["text name"]; 67 | return wstring(reinterpret_cast(threadNamePtr)); 68 | } 69 | private: 70 | SentenceInfo _sentenceInfo; 71 | }; 72 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/File/FileDeleter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | using namespace std; 5 | 6 | 7 | class FileDeleter { 8 | public: 9 | virtual ~FileDeleter() { } 10 | virtual void deleteFile(const string& filePath) = 0; 11 | }; 12 | 13 | 14 | class CRemoveFileDeleter : public FileDeleter { 15 | public: 16 | void deleteFile(const string& filePath) override { 17 | remove(filePath.c_str()); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/File/FileReader.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | class FileReader { 11 | public: 12 | virtual ~FileReader() { } 13 | virtual bool fileExists(const string& filePath) = 0; 14 | virtual vector readLines(const string& filePath) = 0; 15 | virtual void readLines(const string& filePath, const function& lineAction) = 0; 16 | virtual string readLine(const string& filePath, size_t i) = 0; 17 | virtual string readLine(const string& filePath, const function condition) = 0; 18 | virtual string readAll(const string& filePath) = 0; 19 | }; 20 | 21 | 22 | class NoFileReader : public FileReader { 23 | public: 24 | bool fileExists(const string& filePath) override { return false; } 25 | vector readLines(const string& filePath) override { return vector{}; }; 26 | void readLines(const string& filePath, const function& lineAction) override { } 27 | string readLine(const string& filePath, size_t i) override { return ""; } 28 | string readLine(const string& filePath, const function condition) override { return ""; } 29 | string readAll(const string& filePath) override { return ""; } 30 | }; 31 | 32 | 33 | class FstreamFileReader : public FileReader { 34 | public: 35 | bool fileExists(const string& filePath) override { 36 | ifstream f(filePath, ios_base::in); 37 | return fileExists(f); 38 | } 39 | 40 | vector readLines(const string& filePath) override { 41 | vector lines{}; 42 | readLines(filePath, [&lines](const string& line) { lines.push_back(line); }); 43 | return lines; 44 | } 45 | 46 | void readLines(const string& filePath, const function& lineAction) override { 47 | readLine(filePath, [&lineAction](const string& line) { 48 | lineAction(line); 49 | return false; 50 | }); 51 | } 52 | 53 | string readLine(const string& filePath, size_t i) override { 54 | size_t currI = 0; 55 | 56 | return readLine(filePath, [i, &currI](const string& line) { 57 | return i == currI++; 58 | }); 59 | } 60 | 61 | string readLine(const string& filePath, const function condition) override { 62 | ifstream f(filePath, ios_base::in); 63 | if (!fileExists(f)) return ""; 64 | char* line = new char[MAX_LENGTH]; 65 | 66 | while (f.getline(line, MAX_LENGTH)) { 67 | if (condition(line)) return line; 68 | } 69 | 70 | return ""; 71 | } 72 | 73 | string readAll(const string& filePath) override { 74 | ifstream f(filePath, ios_base::in); 75 | if (!fileExists(f)) return ""; 76 | 77 | stringstream buffer; 78 | buffer << f.rdbuf(); 79 | return buffer.str(); 80 | } 81 | private: 82 | static const int MAX_LENGTH = 524288; 83 | 84 | bool fileExists(const ifstream& f) const { 85 | return f.good(); 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/File/Writer/FileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | class FileWriter { 9 | public: 10 | virtual ~FileWriter() { } 11 | virtual void writeToFile(const string& filePath, const string& text) = 0; 12 | virtual void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 13 | virtual void appendToFile(const string& filePath, const string& text) = 0; 14 | virtual void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) = 0; 15 | }; 16 | 17 | 18 | class NoFileWriter : public FileWriter { 19 | public: 20 | void writeToFile(const string& filePath, const string& text) override { } 21 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 22 | void appendToFile(const string& filePath, const string& text) override { } 23 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { } 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/File/Writer/FireAndForgetFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | class FireAndForgetFileWriter : public FileWriter { 11 | public: 12 | FireAndForgetFileWriter(FileWriter& mainWriter) : _mainWriter(mainWriter) { } 13 | 14 | ~FireAndForgetFileWriter() { 15 | // ensure all ongoing write activity is done before deallocating 16 | _destrCalled = true; 17 | waitForAllActionsDone(100, 5000); 18 | } 19 | 20 | void writeToFile(const string& filePath, const string& text) override { 21 | thread([this, filePath, text]() { writeToFileBase(filePath, text); }).detach(); 22 | } 23 | 24 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 25 | thread([this, filePath, lines, startIndex]() { 26 | writeToFileBase(filePath, lines, startIndex); }).detach(); 27 | } 28 | 29 | void appendToFile(const string& filePath, const string& text) override { 30 | thread([this, filePath, text]() { appendToFileBase(filePath, text); }).detach(); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | thread([this, filePath, lines, startIndex]() { 35 | appendToFileBase(filePath, lines, startIndex); }).detach(); 36 | } 37 | private: 38 | atomic _activeCount = 0; 39 | atomic_bool _destrCalled = false; 40 | FileWriter& _mainWriter; 41 | 42 | void writeToFileBase(const string& filePath, const string& text) { 43 | trackAction([this, &filePath, &text]() { 44 | _mainWriter.writeToFile(filePath, text); 45 | }); 46 | } 47 | 48 | void writeToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 49 | trackAction([this, &filePath, &lines, startIndex]() { 50 | _mainWriter.writeToFile(filePath, lines, startIndex); 51 | }); 52 | } 53 | 54 | void appendToFileBase(const string& filePath, const string& text) { 55 | trackAction([this, &filePath, &text]() { 56 | _mainWriter.appendToFile(filePath, text); 57 | }); 58 | } 59 | 60 | void appendToFileBase(const string& filePath, const vector& lines, size_t startIndex = 0) { 61 | trackAction([this, &filePath, &lines, startIndex]() { 62 | _mainWriter.appendToFile(filePath, lines, startIndex); 63 | }); 64 | } 65 | 66 | void trackAction(const function& action) { 67 | if (_destrCalled) return; 68 | _activeCount++; 69 | 70 | try { 71 | action(); 72 | _activeCount--; 73 | } 74 | catch (const exception&) { 75 | _activeCount--; 76 | throw; 77 | } 78 | } 79 | 80 | void waitForAllActionsDone(DWORD intervalMs, DWORD maxWaitMs) { 81 | DWORD waitMs = 0; 82 | 83 | while (_activeCount > 0 && waitMs < maxWaitMs) { 84 | Sleep(intervalMs); 85 | waitMs += intervalMs; 86 | } 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/File/Writer/TruncatableFileWriter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "FileWriter.h" 4 | #include "../FileTruncater.h" 5 | 6 | 7 | class TruncatableFileWriter : public FileWriter { 8 | public: 9 | TruncatableFileWriter(FileWriter& mainWriter, FileTruncater& truncater) 10 | : _mainWriter(mainWriter), _truncater(truncater) { } 11 | 12 | void writeToFile(const string& filePath, const string& text) override { 13 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 14 | _mainWriter.writeToFile(filePath, text); 15 | _truncater.truncateFile(filePath); 16 | }); 17 | } 18 | 19 | void writeToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 20 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 21 | _mainWriter.writeToFile(filePath, lines, startIndex); 22 | _truncater.truncateFile(filePath); 23 | }); 24 | } 25 | 26 | void appendToFile(const string& filePath, const string& text) override { 27 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &text]() { 28 | _mainWriter.appendToFile(filePath, text); 29 | _truncater.truncateFile(filePath); 30 | }); 31 | } 32 | 33 | void appendToFile(const string& filePath, const vector& lines, size_t startIndex = 0) override { 34 | _lockerMap.getOrCreateLocker(filePath).lock([this, &filePath, &lines, startIndex]() { 35 | _mainWriter.appendToFile(filePath, lines, startIndex); 36 | _truncater.truncateFile(filePath); 37 | }); 38 | } 39 | private: 40 | DefaultLockerMap _lockerMap; 41 | FileWriter& _mainWriter; 42 | FileTruncater& _truncater; 43 | }; 44 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/SharedMemory/SharedMemoryInstance.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../_Libraries/Locker.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class SharedMemoryInstance { 10 | public: 11 | virtual ~SharedMemoryInstance() { } 12 | virtual void writeData(const wstring& str) = 0; 13 | virtual wstring readData() const = 0; 14 | virtual void close() = 0; 15 | }; 16 | 17 | 18 | class WinApiNamedSharedMemoryInstance : public SharedMemoryInstance { 19 | public: 20 | WinApiNamedSharedMemoryInstance(HANDLE hMapFile, LPVOID mapView) : _hMapFile(hMapFile), _mapView(mapView) { } 21 | 22 | virtual ~WinApiNamedSharedMemoryInstance() { 23 | close_(); 24 | } 25 | 26 | void writeData(const wstring& str) override { 27 | _locker.lock([this, &str]() { 28 | writeData_(str); 29 | }); 30 | } 31 | 32 | wstring readData() const override { 33 | return _locker.lockWS([this]() { 34 | return readData_(); 35 | }); 36 | } 37 | 38 | void close() override { 39 | _locker.lock([this]() { 40 | close_(); 41 | }); 42 | } 43 | private: 44 | mutable BasicLocker _locker; 45 | HANDLE _hMapFile; 46 | LPVOID _mapView; 47 | 48 | void writeData_(const wstring& str) { 49 | lstrcpyW((wchar_t*)_mapView, str.c_str()); 50 | } 51 | 52 | wstring readData_() const { 53 | wchar_t* cwStr = static_cast(_mapView); 54 | return wstring(cwStr); 55 | } 56 | 57 | void close_() { 58 | unmapView(); 59 | closeMapHandle(); 60 | } 61 | 62 | bool isValidHandle(const HANDLE handle) { 63 | return handle != INVALID_HANDLE_VALUE && handle != nullptr; 64 | } 65 | 66 | void closeMapHandle() { 67 | if (!isValidHandle(_hMapFile)) return; 68 | CloseHandle(_hMapFile); 69 | _hMapFile = nullptr; 70 | } 71 | 72 | void unmapView() { 73 | if (_mapView == NULL) return; 74 | UnmapViewOfFile(_mapView); 75 | _mapView = NULL; 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/TextFormatter.h: -------------------------------------------------------------------------------- 1 |  2 | #pragma once 3 | #include "_Libraries/strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class TextFormatter { 9 | public: 10 | virtual ~TextFormatter() { } 11 | virtual wstring format(wstring text) const = 0; 12 | }; 13 | 14 | 15 | class DefaultTextFormatter : public TextFormatter { 16 | public: 17 | wstring format(wstring text) const override { 18 | return trimWS(text); 19 | } 20 | private: 21 | const vector _wsStrs = { L" ", L" ", L"\r", L"\n", L"\t" }; 22 | 23 | wstring trimWS(wstring text) const { 24 | for (const wstring& ws : _wsStrs) { 25 | text = StrHelper::trim(text, ws); 26 | } 27 | 28 | return text; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/TextMapper.h: -------------------------------------------------------------------------------- 1 |  2 | #pragma once 3 | #include "_Libraries/strhelper.h" 4 | #include "TextFormatter.h" 5 | 6 | class TextMapper { 7 | public: 8 | virtual ~TextMapper() { } 9 | virtual wstring merge(const wstring& text1, const wstring& text2) const = 0; 10 | virtual pair split(wstring text) const = 0; 11 | }; 12 | 13 | 14 | class TextractorTextMapper : public TextMapper { 15 | public: 16 | TextractorTextMapper(const TextFormatter& formatter) : _formatter(formatter) { } 17 | 18 | wstring merge(const wstring& text1, const wstring& text2) const override { 19 | return _formatter.format(text1) + ZERO_WIDTH_SPACE + NEW_LINE + _formatter.format(text2); 20 | } 21 | 22 | pair split(wstring text) const override { 23 | vector splitStrs = StrHelper::split(text, ZERO_WIDTH_SPACE); 24 | if (splitStrs.size() < 2) return pair(text, L""); 25 | 26 | wstring str1 = _formatter.format(splitStrs[0]); 27 | wstring str2 = _formatter.format(splitStrs.back()); 28 | return pair(str1, str2); 29 | } 30 | private: 31 | static constexpr wchar_t ZERO_WIDTH_SPACE = L'\x200b'; 32 | static constexpr wchar_t NEW_LINE = L'\n'; 33 | const TextFormatter& _formatter; 34 | }; 35 | 36 | 37 | class DelimTextMapper : public TextMapper { 38 | public: 39 | DelimTextMapper(const TextFormatter& formatter, const wstring& delim) 40 | : _formatter(formatter), _delim(delim) { } 41 | DelimTextMapper(const TextFormatter& formatter) : DelimTextMapper(formatter, _defaultDelim) { } 42 | 43 | wstring merge(const wstring& text1, const wstring& text2) const override { 44 | return _formatter.format(text1) + _delim + _formatter.format(text2); 45 | } 46 | 47 | pair split(wstring text) const override { 48 | pair textPair = splitToPair(text, _delim); 49 | return textPair; 50 | } 51 | private: 52 | const wstring _defaultDelim = L"|~|"; 53 | const TextFormatter& _formatter; 54 | const wstring _delim; 55 | 56 | 57 | pair splitToPair(const wstring& text, const wstring& delim) const { 58 | size_t delimIndex = text.find(delim); 59 | if (delimIndex == wstring::npos) return pair(text, L""); 60 | 61 | wstring str1 = _formatter.format(text.substr(0, delimIndex)); 62 | wstring str2 = _formatter.format(text.substr(delimIndex + delim.length())); 63 | return pair(str1, str2); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/TextTempStore.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Extension.h" 4 | #include "Cache/TextMapCache.h" 5 | 6 | 7 | // This class is meant to only ever store one key per thread. 8 | 9 | class TextTempReadStore { 10 | public: 11 | virtual ~TextTempReadStore() { } 12 | virtual pair fromStore(SentenceInfoWrapper& sentInfoWrapper) const = 0; 13 | }; 14 | 15 | class TextTempWriteStore { 16 | public: 17 | virtual ~TextTempWriteStore() { } 18 | virtual void toStore(SentenceInfoWrapper& sentInfoWrapper, const wstring& key, const wstring& value) = 0; 19 | virtual void clearStore(SentenceInfoWrapper& sentInfoWrapper) = 0; 20 | virtual void clearStore() = 0; 21 | }; 22 | 23 | class TextTempStore : public TextTempReadStore, public TextTempWriteStore { 24 | public: 25 | virtual ~TextTempStore() { } 26 | }; 27 | 28 | 29 | class NoTextTempStore : public TextTempStore { 30 | public: 31 | pair fromStore(SentenceInfoWrapper& sentInfoWrapper) const override { 32 | return pair(); 33 | } 34 | 35 | void toStore(SentenceInfoWrapper& sentInfoWrapper, const wstring& key, const wstring& value) override { } 36 | void clearStore(SentenceInfoWrapper& sentInfoWrapper) override { } 37 | void clearStore() override { } 38 | }; 39 | 40 | 41 | // Stores key-value pair as a merged value to a map cache, under a temp key. 42 | class MapCacheTextTempStore : public TextTempStore { 43 | public: 44 | MapCacheTextTempStore(TextMapCache& cache, const TextMapper& mapper, 45 | const wstring& cacheKeyBase) : _cache(cache), _mapper(mapper), _cacheKeyBase(cacheKeyBase) { } 46 | 47 | pair fromStore(SentenceInfoWrapper& sentInfoWrapper) const override { 48 | wstring cacheKey = getCacheKey(sentInfoWrapper); 49 | wstring fullText = _cache.readFromCache(cacheKey); 50 | return _mapper.split(fullText); 51 | } 52 | 53 | void toStore(SentenceInfoWrapper& sentInfoWrapper, const wstring& key, const wstring& value) override { 54 | wstring cacheKey = getCacheKey(sentInfoWrapper); 55 | wstring fullText = _mapper.merge(key, value); 56 | clearStore(sentInfoWrapper); 57 | _cache.writeToCache(cacheKey, fullText); 58 | } 59 | 60 | void clearStore(SentenceInfoWrapper& sentInfoWrapper) override { 61 | wstring cacheKey = getCacheKey(sentInfoWrapper); 62 | _cache.removeFromCache(cacheKey); 63 | } 64 | 65 | void clearStore() override { 66 | _cache.clearCache(); 67 | } 68 | private: 69 | const wstring _cacheKeyBase; 70 | TextMapCache& _cache; 71 | const TextMapper& _mapper; 72 | 73 | wstring getCacheKey(SentenceInfoWrapper& sentInfoWrapper) const { 74 | return _cacheKeyBase + sentInfoWrapper.getThreadNumberW(); 75 | } 76 | }; 77 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/Threading/ThreadFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include "../ExtensionConfig.h" 5 | #include "ThreadKeyGenerator.h" 6 | #include "ThreadTracker.h" 7 | using FilterMode = ExtensionConfig::FilterMode; 8 | 9 | 10 | class ThreadFilter { 11 | public: 12 | virtual ~ThreadFilter() { } 13 | virtual bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 14 | }; 15 | 16 | 17 | class NoThreadFilter : public ThreadFilter { 18 | public: 19 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 20 | const ExtensionConfig& config) const override { 21 | return true; 22 | } 23 | }; 24 | 25 | class AllThreadFilter : public ThreadFilter { 26 | public: 27 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 28 | const ExtensionConfig& config) const override { 29 | return false; 30 | } 31 | }; 32 | 33 | 34 | class DefaultThreadFilter : public ThreadFilter { 35 | public: 36 | DefaultThreadFilter(const ThreadKeyGenerator& keyGenerator, ThreadTracker& threadTracker) 37 | : _keyGenerator(keyGenerator), _threadTracker(threadTracker) { } 38 | 39 | bool isThreadAllowed(SentenceInfoWrapper& sentInfoWrapper, 40 | const ExtensionConfig& config) const override 41 | { 42 | size_t threadIndex = _threadTracker.trackThreadNameIndex(sentInfoWrapper); 43 | wstring threadKey = _keyGenerator.getThreadKey(threadIndex, sentInfoWrapper); 44 | wstring threadName = sentInfoWrapper.getThreadName(); 45 | 46 | switch (config.threadKeyFilterMode) { 47 | case FilterMode::Blacklist: 48 | return isInList(threadKey, threadName, config) == false; 49 | case FilterMode::Whitelist: 50 | return isInList(threadKey, threadName, config) == true; 51 | default: 52 | return true; 53 | } 54 | } 55 | private: 56 | const ThreadKeyGenerator& _keyGenerator; 57 | ThreadTracker& _threadTracker; 58 | 59 | bool isInList(const wstring& threadKey, 60 | const wstring& threadName, const ExtensionConfig& config) const 61 | { 62 | if (isInList(config.threadKeyFilterList, threadKey, config.threadKeyFilterListDelim)) return true; 63 | if (isInList(config.threadKeyFilterList, threadName, config.threadKeyFilterListDelim)) return true; 64 | 65 | return false; 66 | } 67 | 68 | bool isInList(const wstring& list, const wstring& subStr, const wstring& delim) const { 69 | if (subStr.length() > list.length()) return false; 70 | wstring searchStr = subStr + delim; 71 | size_t index = list.find(searchStr); 72 | if (index != wstring::npos) return true; 73 | 74 | index = list.rfind(subStr); 75 | if (index == list.length() - subStr.length()) return true; 76 | 77 | return false; 78 | } 79 | }; -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/Threading/ThreadKeyGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Extension.h" 4 | #include 5 | 6 | class ThreadKeyGenerator { 7 | public: 8 | virtual ~ThreadKeyGenerator() { } 9 | virtual wstring getThreadKey(size_t threadIndex, SentenceInfoWrapper& sentInfoWrapper) const = 0; 10 | }; 11 | 12 | 13 | class DefaultThreadKeyGenerator : public ThreadKeyGenerator { 14 | public: 15 | wstring getThreadKey(size_t threadIndex, SentenceInfoWrapper& sentInfoWrapper) const override { 16 | wstring threadKey = sentInfoWrapper.getThreadName() + L"-" + to_wstring(threadIndex); 17 | return threadKey; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/Threading/ThreadTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../_Libraries/Locker.h" 4 | #include "../Extension.h" 5 | #include 6 | using namespace std; 7 | 8 | 9 | class ThreadTracker { 10 | public: 11 | virtual ~ThreadTracker() { } 12 | virtual size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) = 0; 13 | }; 14 | 15 | 16 | class MapThreadTracker : public ThreadTracker { 17 | public: 18 | size_t trackThreadNameIndex(SentenceInfoWrapper& sentInfoWrap) override { 19 | wstring threadName, threadId = createThreadId(sentInfoWrap, threadName); 20 | return trackThreadNameIndexBase(threadId, threadName); 21 | } 22 | private: 23 | const wstring THREAD_ID_DELIM = L":"; 24 | unordered_map _threadNameMap = { }; 25 | unordered_map _threadIdMap = { }; 26 | mutable DefaultLockerMap _lockerMap; 27 | 28 | size_t trackThreadNameIndexBase(const wstring& threadId, const wstring& threadName) { 29 | size_t index = 0; 30 | 31 | _lockerMap.getOrCreateLocker(threadId).lock([this, &threadId, &threadName, &index]() { 32 | if (!mapHasThreadId(threadId)) 33 | _threadIdMap[threadId] = addOrUpdateThreadNameMap(threadName); 34 | 35 | index = _threadIdMap[threadId]; 36 | }); 37 | 38 | return index; 39 | } 40 | 41 | wstring createThreadId(SentenceInfoWrapper& sentInfoWrap, wstring& threadNameOut) const { 42 | wstring processId = sentInfoWrap.getProcessIdW(); 43 | threadNameOut = sentInfoWrap.getThreadName(); 44 | wstring threadNum = sentInfoWrap.getThreadNumberW(); 45 | wstring delim = THREAD_ID_DELIM; 46 | 47 | wstring threadId = processId + delim + threadNameOut + delim + threadNum; 48 | return threadId; 49 | } 50 | 51 | bool mapHasThreadName(const wstring& threadName) const { 52 | return mapHasKey(_threadNameMap, threadName); 53 | } 54 | 55 | bool mapHasThreadId(const wstring& threadId) const { 56 | return mapHasKey(_threadIdMap, threadId); 57 | } 58 | 59 | bool mapHasKey(const unordered_map& map, const wstring& key) const { 60 | return map.find(key) != map.end(); 61 | } 62 | 63 | size_t addOrUpdateThreadNameMap(const wstring& threadName) { 64 | if (!mapHasThreadName(threadName)) _threadNameMap[threadName] = 1; 65 | else _threadNameMap[threadName]++; 66 | 67 | return _threadNameMap[threadName]; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/_Libraries/FileTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class FileTracker { 10 | public: 11 | virtual ~FileTracker() { } 12 | virtual int64_t getDateLastModifiedEpochs(const string& filePath) = 0; 13 | virtual int64_t getDateLastModifiedEpochs(const char* filePath) = 0; 14 | virtual int64_t getDateLastModifiedEpochs(const wstring& filePath) = 0; 15 | virtual int64_t getDateLastModifiedEpochs(const wchar_t* filePath) = 0; 16 | }; 17 | 18 | 19 | class WinApiFileTracker : public FileTracker { 20 | public: 21 | int64_t getDateLastModifiedEpochs(const string& filePath) override { 22 | return getDateLastModifiedEpochs(StrHelper::convertToW(filePath)); 23 | } 24 | 25 | int64_t getDateLastModifiedEpochs(const char* filePath) override { 26 | return getDateLastModifiedEpochs(string(filePath)); 27 | } 28 | 29 | int64_t getDateLastModifiedEpochs(const wstring& filePath) override { 30 | return getDateLastModifiedEpochs(filePath.c_str()); 31 | } 32 | 33 | int64_t getDateLastModifiedEpochs(const wchar_t* filePath) override { 34 | HANDLE fHandle = getFileHandle(filePath); 35 | if (!isValidHandle(fHandle)) return 0; 36 | 37 | FILETIME lastWrite = getFileLastWriteTime(fHandle); 38 | CloseHandle(fHandle); 39 | 40 | return convertTo64(lastWrite); 41 | } 42 | private: 43 | HANDLE getFileHandle(const wchar_t* filePath) { 44 | return CreateFile(filePath, GENERIC_READ, 45 | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); 46 | } 47 | 48 | bool isValidHandle(const HANDLE& handle) { 49 | return handle != INVALID_HANDLE_VALUE; 50 | } 51 | 52 | FILETIME getFileLastWriteTime(const HANDLE& handle) { 53 | FILETIME lastWrite; 54 | GetFileTime(handle, NULL, NULL, &lastWrite); 55 | return lastWrite; 56 | } 57 | 58 | int64_t convertTo64(FILETIME fTime) { 59 | ULARGE_INTEGER ularge{}; 60 | ularge.LowPart = fTime.dwLowDateTime; 61 | ularge.HighPart = fTime.dwHighDateTime; 62 | return static_cast(ularge.QuadPart); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Base/_Libraries/winmsg.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | inline void showErrorMessage(const string& message, const string& appName) { 9 | string tag = appName + "-Error"; 10 | MessageBoxA(nullptr, message.c_str(), tag.c_str(), MB_ICONERROR | MB_OK); 11 | } 12 | 13 | inline string getModuleName(const HMODULE& handle) { 14 | try { 15 | wchar_t buffer[1024]; 16 | GetModuleFileName(handle, buffer, sizeof(buffer) / sizeof(wchar_t)); 17 | 18 | string module = StrHelper::convertFromW(buffer); 19 | size_t pathDelimIndex = module.rfind('\\'); 20 | if (pathDelimIndex != string::npos) module = module.substr(pathDelimIndex + 1); 21 | 22 | size_t extIndex = module.rfind('.'); 23 | if (extIndex != string::npos) module = module.erase(extIndex); 24 | 25 | return module; 26 | } 27 | catch (exception& ex) { 28 | string errMsg = "Failed to retrieve extension name.\n"; 29 | errMsg += ex.what(); 30 | showErrorMessage(errMsg.c_str(), "VndbNameMapper"); 31 | throw; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Read/Extension.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../Textractor.TranslationCache.Base/ExtensionDepsContainer.h" 3 | #include "../Textractor.TranslationCache.Base/_Libraries/winmsg.h" 4 | 5 | const string _backupModuleName = "TranslationCache.Read"; 6 | unique_ptr _deps = nullptr; 7 | 8 | 9 | inline void allocateResources(const HMODULE& hModule) { 10 | _deps = make_unique(hModule, true); 11 | _deps->getConfigRetriever().getConfig(true); // define default config if no config found 12 | } 13 | 14 | inline void clearCacheIfUnload() { 15 | try { 16 | ExtensionConfig config = _deps->getConfigRetriever().getConfig(false); 17 | if (config.clearCacheOnUnload) _deps->getCacheManager().clearCache(); 18 | } 19 | catch (const exception&) {} 20 | } 21 | 22 | inline void deallocateResources() { 23 | if (_deps != nullptr) { 24 | clearCacheIfUnload(); 25 | } 26 | 27 | _deps = nullptr; 28 | } 29 | 30 | 31 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 32 | { 33 | switch (ul_reason_for_call) 34 | { 35 | case DLL_PROCESS_ATTACH: 36 | allocateResources(hModule); 37 | break; 38 | case DLL_PROCESS_DETACH: 39 | deallocateResources(); 40 | break; 41 | } 42 | return TRUE; 43 | } 44 | 45 | 46 | /* 47 | Param sentence: sentence received by Textractor (UTF-16). Can be modified, Textractor will receive this modification only if true is returned. 48 | Param sentenceInfo: contains miscellaneous info about the sentence (see README). 49 | Return value: whether the sentence was modified. 50 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 51 | The sentence will be destroyed if it is empty or if you call Skip(). 52 | This function may be run concurrently with itself: please make sure it's thread safe. 53 | It will not be run concurrently with DllMain. 54 | */ 55 | bool ProcessSentence(wstring& sentence, SentenceInfo sentenceInfo) 56 | { 57 | try { 58 | if (_deps->isDisabled()) return false; 59 | ExtensionConfig config = _deps->getConfigRetriever().getConfig(false); 60 | SentenceInfoWrapper sentInfoWrapper(sentenceInfo); 61 | 62 | _deps->getConfigAdjustEvents().applyConfigAdjustments(config); 63 | sentence = _deps->getCacheManager().readCacheAndStoreTemp(sentence, sentInfoWrapper, config); 64 | return true; 65 | } 66 | catch (const exception& ex) { 67 | string appName = _deps != nullptr ? _deps->moduleName() : _backupModuleName; 68 | showErrorMessage(ex.what(), appName); 69 | return false; 70 | } 71 | } -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Read/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "../Textractor.TranslationCache.Base/Extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | 23 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 24 | { 25 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 26 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 27 | } 28 | } 29 | catch (SKIP) 30 | { 31 | *sentence = L'\0'; 32 | } 33 | return sentence; 34 | } -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Read/Textractor.TranslationCache.Read.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Write/Extension.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../Textractor.TranslationCache.Base/ExtensionDepsContainer.h" 3 | #include "../Textractor.TranslationCache.Base/_Libraries/winmsg.h" 4 | 5 | const string _backupModuleName = "TranslationCache.Write"; 6 | unique_ptr _deps = nullptr; 7 | 8 | 9 | inline void allocateResources(const HMODULE& hModule) { 10 | _deps = make_unique(hModule, false); 11 | _deps->getConfigRetriever().getConfig(true); // define default config if no config found 12 | } 13 | 14 | inline void clearCacheIfUnload() { 15 | try { 16 | ExtensionConfig config = _deps->getConfigRetriever().getConfig(false); 17 | if (config.clearCacheOnUnload) _deps->getCacheManager().clearCache(); 18 | } 19 | catch (const exception&) {} 20 | } 21 | 22 | inline void deallocateResources() { 23 | if (_deps != nullptr) clearCacheIfUnload(); 24 | _deps = nullptr; 25 | } 26 | 27 | 28 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 29 | { 30 | switch (ul_reason_for_call) 31 | { 32 | case DLL_PROCESS_ATTACH: 33 | allocateResources(hModule); 34 | break; 35 | case DLL_PROCESS_DETACH: 36 | deallocateResources(); 37 | break; 38 | } 39 | return TRUE; 40 | } 41 | 42 | 43 | /* 44 | Param sentence: sentence received by Textractor (UTF-16). Can be modified, Textractor will receive this modification only if true is returned. 45 | Param sentenceInfo: contains miscellaneous info about the sentence (see README). 46 | Return value: whether the sentence was modified. 47 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 48 | The sentence will be destroyed if it is empty or if you call Skip(). 49 | This function may be run concurrently with itself: please make sure it's thread safe. 50 | It will not be run concurrently with DllMain. 51 | */ 52 | bool ProcessSentence(wstring& sentence, SentenceInfo sentenceInfo) 53 | { 54 | try { 55 | if (_deps->isDisabled()) return false; 56 | ExtensionConfig config = _deps->getConfigRetriever().getConfig(false); 57 | SentenceInfoWrapper sentInfoWrapper(sentenceInfo); 58 | 59 | _deps->getConfigAdjustEvents().applyConfigAdjustments(config); 60 | sentence = _deps->getCacheManager().writeCacheOrLoadTemp(sentence, sentInfoWrapper, config); 61 | return true; 62 | } 63 | catch (const exception& ex) { 64 | string appName = _deps != nullptr ? _deps->moduleName() : _backupModuleName; 65 | showErrorMessage(ex.what(), appName); 66 | return false; 67 | } 68 | } -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Write/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "../Textractor.TranslationCache.Base/Extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | 23 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 24 | { 25 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 26 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 27 | } 28 | } 29 | catch (SKIP) 30 | { 31 | *sentence = L'\0'; 32 | } 33 | return sentence; 34 | } -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.Write/Textractor.TranslationCache.Write.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | -------------------------------------------------------------------------------- /Textractor.TranslationCache/src/Textractor.TranslationCache.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33205.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.TranslationCache.Read", "Textractor.TranslationCache.Read\Textractor.TranslationCache.Read.vcxproj", "{481B8E0D-8D90-49E3-B92C-35EC9BD5386B}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.TranslationCache.Write", "Textractor.TranslationCache.Write\Textractor.TranslationCache.Write.vcxproj", "{A6C0F91E-34AC-4684-8F63-4B92E8292787}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.TranslationCache.Base", "Textractor.TranslationCache.Base\Textractor.TranslationCache.Base.vcxproj", "{AF21C536-73F3-46AA-A2DA-270ADADB9C66}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Debug|x64.ActiveCfg = Debug|x64 21 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Debug|x64.Build.0 = Debug|x64 22 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Debug|x86.ActiveCfg = Debug|Win32 23 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Debug|x86.Build.0 = Debug|Win32 24 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Release|x64.ActiveCfg = Release|x64 25 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Release|x64.Build.0 = Release|x64 26 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Release|x86.ActiveCfg = Release|Win32 27 | {481B8E0D-8D90-49E3-B92C-35EC9BD5386B}.Release|x86.Build.0 = Release|Win32 28 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Debug|x64.ActiveCfg = Debug|x64 29 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Debug|x64.Build.0 = Debug|x64 30 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Debug|x86.ActiveCfg = Debug|Win32 31 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Debug|x86.Build.0 = Debug|Win32 32 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Release|x64.ActiveCfg = Release|x64 33 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Release|x64.Build.0 = Release|x64 34 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Release|x86.ActiveCfg = Release|Win32 35 | {A6C0F91E-34AC-4684-8F63-4B92E8292787}.Release|x86.Build.0 = Release|Win32 36 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Debug|x64.ActiveCfg = Debug|x64 37 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Debug|x64.Build.0 = Debug|x64 38 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Debug|x86.ActiveCfg = Debug|Win32 39 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Debug|x86.Build.0 = Debug|Win32 40 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Release|x64.ActiveCfg = Release|x64 41 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Release|x64.Build.0 = Release|x64 42 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Release|x86.ActiveCfg = Release|Win32 43 | {AF21C536-73F3-46AA-A2DA-270ADADB9C66}.Release|x86.Build.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {D4AEB2E9-FE57-47F9-AA7B-A5EA289C2355} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/appname-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/appname-example.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/config-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/config-example.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/copy-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/copy-extension.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/curl-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/curl-check.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/example1.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/extension-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/extension-order.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/img/vnid-tab-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voidpenguin-28/Textractor-ExtraExtensions/0ca4d1443983151c5ba23eb57496df87a230fc27/Textractor.VndbCharNameMapper/img/vnid-tab-example.png -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Textractor.VndbCharNameMapper", "Textractor.VndbCharNameMapper\Textractor.VndbCharNameMapper.vcxproj", "{361DF18C-0BFE-4E13-AAD5-89BFB4D54952}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Debug|x64.ActiveCfg = Debug|x64 17 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Debug|x64.Build.0 = Debug|x64 18 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Debug|x86.ActiveCfg = Debug|Win32 19 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Debug|x86.Build.0 = Debug|Win32 20 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Release|x64.ActiveCfg = Release|x64 21 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Release|x64.Build.0 = Release|x64 22 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Release|x86.ActiveCfg = Release|Win32 23 | {361DF18C-0BFE-4E13-AAD5-89BFB4D54952}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {93F82DCE-16ED-4614-8718-EF5552191776} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/CharMappingConverter.h: -------------------------------------------------------------------------------- 1 |  2 | #pragma once 3 | #include "Common.h" 4 | #include 5 | #include 6 | 7 | 8 | class CharMappingConverter { 9 | public: 10 | virtual ~CharMappingConverter() { } 11 | virtual CharMappings convert(const vector& jpNames, 12 | const vector& enNames, const vector& genders = {}) const = 0; 13 | }; 14 | 15 | 16 | class DefaultCharMappingConverter : public CharMappingConverter { 17 | public: 18 | CharMappings convert(const vector& jpNames, 19 | const vector& enNames, const vector& genders) const override 20 | { 21 | wstring_map fullNameMap = { }; 22 | wstring_map singleNameMap = { }; 23 | gender_map genderMap = { }; 24 | 25 | if (jpNames.size() != enNames.size()) 26 | throw runtime_error("Number of parsed JP & EN names do not match; JP: " + to_string(jpNames.size()) + ", EN: " + to_string(enNames.size())); 27 | 28 | for (size_t i = 0; i < jpNames.size(); i++) { 29 | if (jpNames[i].empty()) continue; 30 | 31 | addIfNotExist(fullNameMap, jpNames[i], enNames[i]); 32 | addIfNotExist(fullNameMap, removeDelimsFromStr(jpNames[i]), enNames[i]); 33 | 34 | vector jpNameParts = splitStrByDelims(jpNames[i]); 35 | vector enNameParts = splitStrByDelims(enNames[i]); 36 | 37 | addIfNotExist(genderMap, enNameParts[enNameParts.size() - 1], genders[i]); 38 | if (jpNameParts.size() != enNameParts.size() || jpNameParts.size() <= 1) continue; 39 | 40 | for (size_t j = 0; j < jpNameParts.size(); j++) { 41 | if (jpNameParts[j].empty()) continue; 42 | addIfNotExist(singleNameMap, jpNameParts[j], enNameParts[j]); 43 | } 44 | } 45 | 46 | return CharMappings(fullNameMap, singleNameMap, genderMap); 47 | } 48 | private: 49 | const unordered_set _nameDelims = { L' ', L'・' }; 50 | 51 | template 52 | void addIfNotExist(templ_map& map, const wstring& key, const T& value) const { 53 | if (map.count(key)) return; 54 | map[key] = value; 55 | } 56 | 57 | wstring removeDelimsFromStr(const wstring& input) const { 58 | wstring output = L""; 59 | 60 | for (auto& ch : input) { 61 | if (!isNameDelim(ch)) output += ch; 62 | } 63 | 64 | return output; 65 | } 66 | 67 | vector splitStrByDelims(const wstring& input) const { 68 | vector splitStrs = { }; 69 | wstring output = L""; 70 | 71 | for (auto& ch : input) { 72 | if (!isNameDelim(ch)) { 73 | output += ch; 74 | } 75 | else { 76 | splitStrs.push_back(output); 77 | output = L""; 78 | } 79 | } 80 | 81 | splitStrs.push_back(output); 82 | return splitStrs; 83 | } 84 | 85 | bool isNameDelim(wchar_t ch) const { 86 | return _nameDelims.find(ch) != _nameDelims.end(); 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | enum class Gender { Unknown = 0, Male, Female }; 8 | 9 | template using templ_map = unordered_map; 10 | typedef templ_map wstring_map; 11 | typedef templ_map gender_map; 12 | 13 | 14 | struct CharMappings { 15 | wstring_map fullNameMap; 16 | wstring_map singleNameMap; 17 | gender_map genderMap; 18 | 19 | CharMappings(wstring_map fullNameMap_ = {}, wstring_map singleNameMap_ = {}, gender_map genderMap_ = {}) 20 | : fullNameMap(fullNameMap_), singleNameMap(singleNameMap_), genderMap(genderMap_) { } 21 | }; 22 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/ExtExecRequirements.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "ExtensionConfig.h" 4 | #include "Extension.h" 5 | 6 | 7 | class ExtExecRequirements { 8 | public: 9 | virtual ~ExtExecRequirements() { } 10 | virtual bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const = 0; 11 | }; 12 | 13 | 14 | class NoExtExecRequirements : public ExtExecRequirements { 15 | public: 16 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 17 | return true; 18 | } 19 | }; 20 | 21 | 22 | class DefaultExtExecRequirements : public ExtExecRequirements { 23 | public: 24 | bool meetsRequirements(SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const override { 25 | if (config.disabled) return false; 26 | if (config.activeThreadOnly && !sentInfoWrapper.isActiveThread()) return false; 27 | if (!meetsConsoleAndClipboardRequirements(sentInfoWrapper, config)) return false; 28 | 29 | return true; 30 | } 31 | private: 32 | bool meetsConsoleAndClipboardRequirements( 33 | SentenceInfoWrapper& sentInfoWrapper, const ExtensionConfig& config) const 34 | { 35 | static const wstring _consoleThreadName = L"Console"; 36 | static const wstring _clipboardThreadName = L"Clipboard"; 37 | wstring threadName = sentInfoWrapper.getThreadName(); 38 | 39 | switch (config.skipConsoleAndClipboard) { 40 | case ExtensionConfig::ConsoleClipboardMode::SkipAll: 41 | if (sentInfoWrapper.threadIsConsoleOrClipboard()) return false; 42 | break; 43 | case ExtensionConfig::ConsoleClipboardMode::SkipConsole: 44 | if (threadName == _consoleThreadName) return false; 45 | break; 46 | case ExtensionConfig::ConsoleClipboardMode::SkipClipboard: 47 | if (threadName == _clipboardThreadName) return false; 48 | break; 49 | } 50 | 51 | return true; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Extension.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "Libraries/winmsg.h" 3 | #include "Extension.h" 4 | #include "ExtensionDepsContainer.h" 5 | #include 6 | using namespace std; 7 | 8 | const string _backupModuleName = "VndbCharNameMapper"; 9 | unique_ptr _deps = nullptr; 10 | 11 | 12 | inline void allocateResources(const HMODULE& hModule) { 13 | _deps = make_unique(hModule); 14 | _deps->getConfigRetriever().getConfig(true); // define default config if no config found 15 | } 16 | 17 | inline void deallocateResources() { 18 | _deps = nullptr; 19 | } 20 | 21 | 22 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 23 | { 24 | switch (ul_reason_for_call) 25 | { 26 | case DLL_PROCESS_ATTACH: 27 | allocateResources(hModule); 28 | break; 29 | case DLL_PROCESS_DETACH: 30 | deallocateResources(); 31 | break; 32 | } 33 | 34 | return TRUE; 35 | } 36 | 37 | /* 38 | Param sentence: sentence received by Textractor (UTF-16). Can be modified, Textractor will receive this modification only if true is returned. 39 | Param sentenceInfo: contains miscellaneous info about the sentence (see README). 40 | Return value: whether the sentence was modified. 41 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 42 | The sentence will be destroyed if it is empty or if you call Skip(). 43 | This function may be run concurrently with itself: please make sure it's thread safe. 44 | It will not be run concurrently with DllMain. 45 | */ 46 | bool ProcessSentence(wstring& sentence, SentenceInfo sentenceInfo) 47 | { 48 | try { 49 | SentenceInfoWrapper sentInfoWrapper(sentenceInfo); 50 | NameMappingManager& mappingManager = _deps->getNameMappingManager(); 51 | 52 | sentence = mappingManager.applyAllNameMappings(sentence, sentInfoWrapper); 53 | return true; 54 | } 55 | catch (exception& ex) { 56 | string moduleName = _deps != nullptr ? _deps->moduleName() : _backupModuleName; 57 | showErrorMessage(ex.what(), moduleName); 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Extension.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | 11 | struct InfoForExtension 12 | { 13 | const char* name; 14 | int64_t value; 15 | }; 16 | 17 | struct SentenceInfo 18 | { 19 | const InfoForExtension* infoArray; 20 | int64_t operator[](std::string propertyName) 21 | { 22 | for (auto info = infoArray; info->name; ++info) // nullptr name marks end of info array 23 | if (propertyName == info->name) return info->value; 24 | return *(int*)0xcccc = 0; // gives better error message than alternatives 25 | } 26 | }; 27 | 28 | struct SKIP {}; 29 | inline void Skip() { throw SKIP(); } 30 | 31 | 32 | class SentenceInfoWrapper { 33 | public: 34 | SentenceInfoWrapper(SentenceInfo& sentenceInfo) : _sentenceInfo(sentenceInfo) { } 35 | 36 | bool isActiveThread() { 37 | return _sentenceInfo["current select"]; 38 | } 39 | 40 | bool threadIsConsoleOrClipboard() { 41 | return getProcessId() == 0; 42 | } 43 | 44 | wstring getProcessIdW() { 45 | return to_wstring(getProcessId()); 46 | } 47 | 48 | DWORD getProcessIdD() { 49 | return static_cast(getProcessId()); 50 | } 51 | 52 | int64_t getProcessId() { 53 | return _sentenceInfo["process id"]; 54 | } 55 | 56 | wstring getThreadNumberW() { 57 | int64_t threadNum = getThreadNumber(); 58 | return to_wstring(threadNum); 59 | } 60 | 61 | int64_t getThreadNumber() { 62 | return _sentenceInfo["text number"]; 63 | } 64 | 65 | wstring getThreadName() { 66 | int64_t threadNamePtr = _sentenceInfo["text name"]; 67 | return wstring(reinterpret_cast(threadNamePtr)); 68 | } 69 | private: 70 | SentenceInfo _sentenceInfo; 71 | }; 72 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/ExtensionImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | 3 | bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo); 4 | 5 | /* 6 | You shouldn't mess with this or even look at it unless you're certain you know what you're doing. 7 | Param sentence: pointer to sentence received by Textractor (UTF-16). 8 | This can be modified. Textractor uses the modified sentence for future processing and display. If empty (starts with null terminator), Textractor will destroy it. 9 | Textractor will display the sentence after all extensions have had a chance to process and/or modify it. 10 | The buffer is allocated using HeapAlloc(). If you want to make it larger, please use HeapReAlloc(). 11 | Param sentenceInfo: pointer to array containing misc info about the sentence. End of array is marked with name being nullptr. 12 | Return value: the buffer used for the sentence. Remember to return a new pointer if HeapReAlloc() gave you one. 13 | This function may be run concurrently with itself: please make sure it's thread safe. 14 | It will not be run concurrently with DllMain. 15 | */ 16 | extern "C" __declspec(dllexport) wchar_t* OnNewSentence(wchar_t* sentence, const InfoForExtension * sentenceInfo) 17 | { 18 | try 19 | { 20 | std::wstring sentenceCopy(sentence); 21 | size_t oldSize = sentenceCopy.size(); 22 | if (ProcessSentence(sentenceCopy, SentenceInfo{ sentenceInfo })) 23 | { 24 | if (sentenceCopy.size() > oldSize) sentence = (wchar_t*)HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sentence, (sentenceCopy.size() + 1) * sizeof(wchar_t)); 25 | wcscpy_s(sentence, sentenceCopy.size() + 1, sentenceCopy.c_str()); 26 | } 27 | } 28 | catch (SKIP) 29 | { 30 | *sentence = L'\0'; 31 | } 32 | return sentence; 33 | } -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/GenderStrMapper.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Common.h" 4 | 5 | class GenderStrMapper { 6 | public: 7 | virtual ~GenderStrMapper() { } 8 | virtual wstring map(Gender gender) const = 0; 9 | virtual Gender map(wstring gender) const = 0; 10 | }; 11 | 12 | 13 | class DefaultGenderStrMapper : public GenderStrMapper { 14 | public: 15 | wstring map(Gender gender) const { 16 | switch (gender) { 17 | case Gender::Male: 18 | return L"M"; 19 | case Gender::Female: 20 | return L"F"; 21 | default: 22 | return L"U"; 23 | } 24 | } 25 | 26 | Gender map(wstring gender) const { 27 | if (gender == L"M") 28 | return Gender::Male; 29 | else if (gender == L"F") 30 | return Gender::Female; 31 | else 32 | return Gender::Unknown; 33 | } 34 | }; 35 | 36 | 37 | class VndbHtmlGenderStrMapper : public GenderStrMapper { 38 | public: 39 | wstring map(Gender gender) const { 40 | switch (gender) { 41 | case Gender::Male: 42 | return L"Male"; 43 | case Gender::Female: 44 | return L"Female"; 45 | default: 46 | return L""; 47 | } 48 | } 49 | 50 | Gender map(wstring gender) const { 51 | if (gender == L"Male") 52 | return Gender::Male; 53 | else if (gender == L"Female") 54 | return Gender::Female; 55 | else 56 | return Gender::Unknown; 57 | } 58 | }; -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/HtmlParsers/HtmlParser.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "../Common.h" 4 | 5 | class HtmlParser { 6 | public: 7 | virtual ~HtmlParser() { } 8 | virtual string extractSpoilCharsPath(const string& html) const = 0; 9 | virtual CharMappings getNameMappings(const string& html) const = 0; 10 | virtual CharMappings getNameMappings(const wstring& html) const = 0; 11 | virtual vector parseAllJpNames(const wstring& html) const = 0; 12 | virtual vector parseAllEnNames(const wstring& html) const = 0; 13 | }; 14 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/HttpClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Libraries/curlproc.h" 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | class HttpClient { 10 | public: 11 | ~HttpClient() { } 12 | virtual string httpGet(const string& url, const vector& headers = vector()) const = 0; 13 | virtual string httpPost(const string& url, const string& body, const vector& headers = vector()) const = 0; 14 | }; 15 | 16 | 17 | class CurlProcHttpClient : public HttpClient { 18 | public: 19 | CurlProcHttpClient(const function customCurlPathGetter) 20 | : _customCurlPathGetter(customCurlPathGetter) { } 21 | CurlProcHttpClient(const string& customCurlPath) 22 | : CurlProcHttpClient([customCurlPath]() { return customCurlPath; }) { } 23 | 24 | string httpGet(const string& url, const vector& headers = vector()) const override { 25 | string customCurlPath = _customCurlPathGetter(); 26 | return curlproc::httpGet(url, headers, curlproc::DEFAULT_USER_AGENT, customCurlPath); 27 | } 28 | 29 | string httpPost(const string& url, const string& body, const vector& headers = vector()) const override { 30 | string customCurlPath = _customCurlPathGetter(); 31 | return curlproc::httpPost(url, body, headers, curlproc::DEFAULT_USER_AGENT, customCurlPath); 32 | } 33 | private: 34 | const function _customCurlPathGetter; 35 | }; 36 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Libraries/FileTracker.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | class FileTracker { 10 | public: 11 | virtual ~FileTracker() { } 12 | virtual int64_t getDateLastModifiedEpochs(const string& filePath) = 0; 13 | virtual int64_t getDateLastModifiedEpochs(const char* filePath) = 0; 14 | virtual int64_t getDateLastModifiedEpochs(const wstring& filePath) = 0; 15 | virtual int64_t getDateLastModifiedEpochs(const wchar_t* filePath) = 0; 16 | }; 17 | 18 | 19 | class WinApiFileTracker : public FileTracker { 20 | public: 21 | int64_t getDateLastModifiedEpochs(const string& filePath) override { 22 | return getDateLastModifiedEpochs(StrHelper::convertToW(filePath)); 23 | } 24 | 25 | int64_t getDateLastModifiedEpochs(const char* filePath) override { 26 | return getDateLastModifiedEpochs(string(filePath)); 27 | } 28 | 29 | int64_t getDateLastModifiedEpochs(const wstring& filePath) override { 30 | return getDateLastModifiedEpochs(filePath.c_str()); 31 | } 32 | 33 | int64_t getDateLastModifiedEpochs(const wchar_t* filePath) override { 34 | HANDLE fHandle = getFileHandle(filePath); 35 | if (!isValidHandle(fHandle)) return 0; 36 | 37 | FILETIME lastWrite = getFileLastWriteTime(fHandle); 38 | CloseHandle(fHandle); 39 | 40 | return convertTo64(lastWrite); 41 | } 42 | private: 43 | HANDLE getFileHandle(const wchar_t* filePath) { 44 | return CreateFile(filePath, GENERIC_READ, 45 | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); 46 | } 47 | 48 | bool isValidHandle(const HANDLE& handle) { 49 | return handle != INVALID_HANDLE_VALUE; 50 | } 51 | 52 | FILETIME getFileLastWriteTime(const HANDLE& handle) { 53 | FILETIME lastWrite; 54 | GetFileTime(handle, NULL, NULL, &lastWrite); 55 | return lastWrite; 56 | } 57 | 58 | int64_t convertTo64(FILETIME fTime) { 59 | ULARGE_INTEGER ularge{}; 60 | ularge.LowPart = fTime.dwLowDateTime; 61 | ularge.HighPart = fTime.dwHighDateTime; 62 | return static_cast(ularge.QuadPart); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Libraries/curlproc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace curlproc { 8 | const string DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"; 9 | 10 | string httpGet(const string& url, const vector& headers = vector(), const string& userAgent = DEFAULT_USER_AGENT, const string& customCurlPath = ""); 11 | string httpPost(const string& url, const string& body, const vector& headers = vector(), const string& userAgent = DEFAULT_USER_AGENT, const string& customCurlPath = ""); 12 | } 13 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Libraries/winmsg.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "strhelper.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | inline void showErrorMessage(const string& message, const string& appName) { 9 | string tag = appName + "-Error"; 10 | MessageBoxA(nullptr, message.c_str(), tag.c_str(), MB_ICONERROR | MB_OK); 11 | } 12 | 13 | inline string getModuleName(const HMODULE& handle) { 14 | try { 15 | wchar_t buffer[1024]; 16 | GetModuleFileName(handle, buffer, sizeof(buffer) / sizeof(wchar_t)); 17 | 18 | string module = StrHelper::convertFromW(buffer); 19 | size_t pathDelimIndex = module.rfind('\\'); 20 | if (pathDelimIndex != string::npos) module = module.substr(pathDelimIndex + 1); 21 | 22 | size_t extIndex = module.rfind('.'); 23 | if (extIndex != string::npos) module = module.erase(extIndex); 24 | 25 | return module; 26 | } 27 | catch (exception& ex) { 28 | string errMsg = "Failed to retrieve extension name.\n"; 29 | errMsg += ex.what(); 30 | showErrorMessage(errMsg.c_str(), "VndbNameMapper"); 31 | throw; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/NameMapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Libraries/strhelper.h" 4 | #include "HtmlParsers/HtmlParser.h" 5 | #include "ExtensionConfig.h" 6 | #include "GenderStrMapper.h" 7 | #include 8 | using namespace std; 9 | 10 | class NameMapper { 11 | public: 12 | virtual ~NameMapper() { } 13 | virtual wstring applyNameMappings(MappingMode mappingMode, const CharMappings& charMap, wstring str) const = 0; 14 | }; 15 | 16 | 17 | class DefaultNameMapper : public NameMapper { 18 | public: 19 | DefaultNameMapper(const GenderStrMapper& genderStrMapper) : _genderStrMapper(genderStrMapper) { } 20 | 21 | wstring applyNameMappings(MappingMode mappingMode, const CharMappings& charMap, wstring str) const override { 22 | if (mappingMode == MappingMode::None) return str; 23 | 24 | str = replaceNames(mappingMode, charMap.fullNameMap, charMap.genderMap, str); 25 | str = replaceNames(mappingMode, charMap.singleNameMap, charMap.genderMap, str); 26 | return str; 27 | } 28 | private: 29 | const GenderStrMapper& _genderStrMapper; 30 | 31 | wstring replaceNames(MappingMode mappingMode, const wstring_map& nameMap, 32 | const gender_map& genderMap, wstring str) const 33 | { 34 | if (mappingMode == MappingMode::None) return str; 35 | wstring mappedName; 36 | 37 | for (const auto& name : nameMap) { 38 | if (str.find(name.first) == string::npos) continue; 39 | 40 | mappedName = name.second; 41 | if (mappingMode == MappingMode::NameAndGender) 42 | mappedName = appendGenderToName(mappedName, genderMap); 43 | 44 | str = StrHelper::replace(str, name.first, mappedName); 45 | } 46 | 47 | return str; 48 | } 49 | 50 | wstring appendGenderToName(wstring name, const gender_map& genderMap) const { 51 | Gender gender = parseGender(name, genderMap); 52 | if (gender == Gender::Unknown) return name; 53 | 54 | wstring genderStr = _genderStrMapper.map(gender); 55 | return name + L" (" + genderStr + L")"; 56 | } 57 | 58 | Gender parseGender(const wstring& name, const gender_map& genderMap) const { 59 | wstring newName = StrHelper::split(name, L' ', true).back(); 60 | Gender gender = genderMap.find(newName) != genderMap.end() ? genderMap.at(newName) : Gender::Unknown; 61 | return gender; 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/NameMappingManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Extension.h" 4 | #include "ExtensionConfig.h" 5 | #include "ExtExecRequirements.h" 6 | #include "NameMapper.h" 7 | #include "NameRetriever.h" 8 | #include "VnIdsParser.h" 9 | 10 | 11 | class NameMappingManager { 12 | public: 13 | virtual ~NameMappingManager() { } 14 | virtual wstring applyAllNameMappings(const wstring& sentence, SentenceInfoWrapper& sentInfoWrapper) = 0; 15 | }; 16 | 17 | 18 | class DefaultNameMappingManager : public NameMappingManager { 19 | public: 20 | DefaultNameMappingManager(ConfigRetriever& configRetriever, 21 | const NameMapper& nameMapper, NameRetriever& nameRetriever, 22 | const VnIdsParser& vnIdsParser, const ExtExecRequirements& execRequirements) 23 | : _configRetriever(configRetriever), _nameMapper(nameMapper), 24 | _nameRetriever(nameRetriever), _vnIdsParser(vnIdsParser), 25 | _execRequirements(execRequirements) { } 26 | 27 | wstring applyAllNameMappings(const wstring& sentence, SentenceInfoWrapper& sentInfoWrapper) override { 28 | ExtensionConfig config = _configRetriever.getConfig(false); 29 | if (!_execRequirements.meetsRequirements(sentInfoWrapper, config)) return sentence; 30 | 31 | vector vnIdList = _vnIdsParser.parse(config, sentInfoWrapper); 32 | wstring newSentence = applyAllNameMappings(vnIdList, sentence, config); 33 | return newSentence; 34 | } 35 | private: 36 | ConfigRetriever& _configRetriever; 37 | const NameMapper& _nameMapper; 38 | NameRetriever& _nameRetriever; 39 | const VnIdsParser& _vnIdsParser; 40 | const ExtExecRequirements& _execRequirements; 41 | 42 | wstring applyAllNameMappings(const vector vnIdList, 43 | wstring sentence, const ExtensionConfig& config) const 44 | { 45 | for (const auto& vnId : vnIdList) { 46 | sentence = applyNameMappings(vnId, sentence, config); 47 | } 48 | 49 | return sentence; 50 | } 51 | 52 | wstring applyNameMappings(const string& vnId, const wstring sentence, const ExtensionConfig& config) const { 53 | CharMappings map = getNameMappings(vnId, config.minNameCharSize); 54 | return _nameMapper.applyNameMappings(config.mappingMode, map, sentence); 55 | } 56 | 57 | CharMappings getNameMappings(const string& vnId, int minNameCharSize) const { 58 | CharMappings map = _nameRetriever.getNameMappings(vnId); 59 | map = filterMap(map, minNameCharSize); 60 | return map; 61 | } 62 | 63 | CharMappings filterMap(const CharMappings& map, int minNameCharSize) const { 64 | CharMappings filteredMap( 65 | filterMap(map.fullNameMap, minNameCharSize), 66 | filterMap(map.singleNameMap, minNameCharSize), 67 | map.genderMap 68 | ); 69 | 70 | return filteredMap; 71 | } 72 | 73 | wstring_map filterMap(const wstring_map& map, int minNameCharSize) const { 74 | wstring_map filteredMap{}; 75 | 76 | for (const auto& name : map) { 77 | if (name.first.length() < minNameCharSize) continue; 78 | filteredMap[name.first] = name.second; 79 | } 80 | 81 | return filteredMap; 82 | } 83 | }; 84 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/ProcessNameRetriever.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | class ProcessNameRetriever { 10 | public: 11 | virtual ~ProcessNameRetriever() { } 12 | virtual wstring getProcessName(DWORD pid) const = 0; 13 | }; 14 | 15 | class WinApiProcessNameRetriever : public ProcessNameRetriever { 16 | public: 17 | wstring getProcessName(DWORD pid) const override { 18 | HANDLE hProcess = GetProcessHandle(pid); 19 | 20 | if (isInvalidHandle(hProcess)) { 21 | cerr << "Error opening process. Error code: " << GetLastError() << endl; 22 | return L""; 23 | } 24 | 25 | wstring processNameW = getProcessName(hProcess); 26 | CloseHandle(hProcess); 27 | return processNameW; 28 | } 29 | private: 30 | static constexpr wchar_t PERIOD_CH = L'.'; 31 | 32 | HANDLE GetProcessHandle(DWORD pid) const { 33 | return OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); 34 | } 35 | 36 | bool isInvalidHandle(HANDLE handle) const { 37 | return handle == nullptr || handle == INVALID_HANDLE_VALUE; 38 | } 39 | 40 | wstring getProcessName(HANDLE handle) const { 41 | TCHAR szProcessName[MAX_PATH] = TEXT(""); 42 | 43 | if (!GetModuleBaseName(handle, nullptr, szProcessName, sizeof(szProcessName) / sizeof(TCHAR))) { 44 | cerr << "Error getting process name. Error code: " << GetLastError() << endl; 45 | return L""; 46 | } 47 | 48 | wstring processName = wstring(szProcessName); 49 | return formatProcessName(processName); 50 | } 51 | 52 | wstring formatProcessName(wstring processName) const { 53 | size_t periodIndex = processName.rfind(PERIOD_CH); 54 | 55 | if (periodIndex != wstring::npos) { 56 | processName = processName.substr(0, periodIndex); 57 | } 58 | 59 | return processName; 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/Textractor.VndbCharNameMapper.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {27688e67-07dc-48c1-acac-05cfbd5244db} 37 | 38 | 39 | -------------------------------------------------------------------------------- /Textractor.VndbCharNameMapper/src/Textractor.VndbCharNameMapper/VnIdsParser.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "Libraries/strhelper.h" 4 | #include "Extension.h" 5 | #include "ExtensionConfig.h" 6 | #include "ProcessNameRetriever.h" 7 | #include 8 | 9 | 10 | class VnIdsParser { 11 | public: 12 | ~VnIdsParser() { } 13 | virtual vector parse(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) const = 0; 14 | }; 15 | 16 | 17 | class DefaultVnIdsParser : public VnIdsParser { 18 | public: 19 | DefaultVnIdsParser(const ProcessNameRetriever& procNameRetriever) : _procNameRetriever(procNameRetriever) { } 20 | 21 | vector parse(const ExtensionConfig& config, SentenceInfoWrapper& sentInfoWrapper) const override { 22 | if (config.vnIds.empty()) return vector(); 23 | if (!contains(config.vnIds, _keyValDelim)) return splitVnIds(config); 24 | 25 | vector vnIds = StrHelper::split(config.vnIds, config.vnIdDelim, true); 26 | wstring appName = _procNameRetriever.getProcessName(sentInfoWrapper.getProcessIdD()); 27 | return filterVnIds(vnIds, appName); 28 | } 29 | private: 30 | static constexpr wchar_t _keyValDelim = L'='; 31 | const ProcessNameRetriever& _procNameRetriever; 32 | 33 | bool contains(const wstring& str, const wchar_t ch) const { 34 | return str.find(ch) != wstring::npos; 35 | } 36 | 37 | bool startsWith(const wstring& str, const wstring& subStr) const { 38 | return str.find(subStr) == 0; 39 | } 40 | 41 | vector splitVnIds(const ExtensionConfig& config) const { 42 | return StrHelper::split(StrHelper::convertFromW(config.vnIds), 43 | StrHelper::convertFromW(config.vnIdDelim), true); 44 | } 45 | 46 | vector splitVnIdsW(const ExtensionConfig& config) const { 47 | return StrHelper::split(config.vnIds, config.vnIdDelim, true); 48 | } 49 | 50 | vector filterVnIds(const vector& vnIds, wstring appName) const { 51 | vector nonMappedVnIds{}; 52 | appName += _keyValDelim; 53 | 54 | 55 | for (const wstring& vnId : vnIds) { 56 | if (!contains(vnId, _keyValDelim)) { 57 | nonMappedVnIds.push_back(StrHelper::convertFromW(vnId)); 58 | } 59 | else if (startsWith(vnId, appName)) { 60 | pair appVnIdPair = splitToPair(vnId, _keyValDelim); 61 | return vector { StrHelper::convertFromW(appVnIdPair.second) }; 62 | } 63 | } 64 | 65 | return nonMappedVnIds; 66 | } 67 | 68 | pair splitToPair(const wstring& str, const wchar_t delim) const { 69 | vector splits = StrHelper::split(str, delim, true); 70 | 71 | return splits.size() >= 2 ? 72 | pair(splits[0], splits[1]) : 73 | pair(str, L""); 74 | } 75 | }; 76 | --------------------------------------------------------------------------------