├── .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