mireado

starting commit

1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#pragma once
19 +
20 +template <class T, unsigned int default_size>
21 +class PointerTable
22 +{
23 +public:
24 + PointerTable()
25 + {
26 + assert((default_size & (default_size - 1)) == 0);
27 + size = default_size;
28 + table = new T*[size];
29 + used = 0;
30 + next = 0;
31 + memset(table, 0, size * sizeof(T*));
32 + }
33 + ~PointerTable()
34 + {
35 + delete table;
36 + }
37 + T* Set(unsigned int number, T* ptr)
38 + {
39 + if (number >= size - 2)
40 + {
41 + unsigned int new_size = size;
42 + while (number >= new_size - 2) new_size <<= 1;
43 + Resize(new_size);
44 + }
45 + T* original = table[number + 1];
46 + table[number + 1] = ptr;
47 + if (ptr == 0) //Clear pointer.
48 + {
49 + if (number < next) next = number;
50 + if (number == used - 1) //Last used position is cleared.
51 + {
52 + table[0] = (T*)1;
53 + for (used--; table[used] == 0; used--);
54 + }
55 + }
56 + else //Set pointer.
57 + {
58 + __assume(number < size - 2); //Otherwise a resize operation is invoked.
59 + if (number == next)
60 + {
61 + next++; //Next position is occupied.
62 + for (next++; table[next]; next++); //There is always a zero in the end.
63 + next--; //next is zero based but the table start at one(zero is used as sentry).
64 + }
65 + if (number >= used) used = number + 1;
66 + }
67 + return original;
68 + }
69 + T* Get(unsigned int number)
70 + {
71 + number++;
72 + if (number <= used) return table[number];
73 + else return 0;
74 + }
75 + T* operator [](unsigned int number)
76 + {
77 + number++;
78 + if (number <= used) return table[number];
79 + else return 0;
80 + }
81 + void Append(T* ptr)
82 + {
83 + Set(next,ptr);
84 + }
85 + void Resize(unsigned int new_size)
86 + {
87 + assert(new_size > size);
88 + assert((new_size & (new_size - 1)) == 0);
89 + assert(new_size < 0x10000);
90 +
91 + T** temp = new T*[new_size];
92 + memcpy(temp, table, size * sizeof(T*));
93 + memset(temp + size, 0, (new_size - size) * sizeof(T*));
94 + delete table;
95 + size = new_size;
96 + table = temp;
97 + }
98 + void DeleteAll() //Release all pointers on demand.
99 + {
100 + T* p;
101 + next = 0;
102 + while (used)
103 + {
104 + p = table[used];
105 + if (p) delete p;
106 + table[used] = 0;
107 + used--;
108 + }
109 + }
110 + void Reset() //Reset without release pointers.
111 + {
112 + memset(table, 0, sizeof(T*) * (used + 1));
113 + next = 0;
114 + used = 0;
115 +
116 + }
117 + unsigned int size,next,used;
118 + T** table;
119 +};
1 +#include "ProcessWindow.h"
2 +#include "resource.h"
3 +#include "ith/host/srv.h"
4 +#include "ith/host/hookman.h"
5 +#include "ProfileManager.h"
6 +#include "Profile.h"
7 +
8 +extern HookManager* man; // main.cpp
9 +extern ProfileManager* pfman; // ProfileManager.cpp
10 +
11 +ProcessWindow::ProcessWindow(HWND hDialog) : hDlg(hDialog)
12 +{
13 + hbRefresh = GetDlgItem(hDlg, IDC_BUTTON1);
14 + hbAttach = GetDlgItem(hDlg, IDC_BUTTON2);
15 + hbDetach = GetDlgItem(hDlg, IDC_BUTTON3);
16 + hbAddProfile = GetDlgItem(hDlg, IDC_BUTTON5);
17 + hbRemoveProfile = GetDlgItem(hDlg, IDC_BUTTON6);
18 + EnableWindow(hbAddProfile, FALSE);
19 + EnableWindow(hbRemoveProfile, FALSE);
20 + hlProcess = GetDlgItem(hDlg, IDC_LIST1);
21 + heOutput = GetDlgItem(hDlg, IDC_EDIT1);
22 + ListView_SetExtendedListViewStyleEx(hlProcess, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
23 + InitProcessDlg();
24 + RefreshProcess();
25 +}
26 +
27 +void ProcessWindow::InitProcessDlg()
28 +{
29 + LVCOLUMN lvc = {};
30 + lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
31 + lvc.fmt = LVCFMT_RIGHT; // left-aligned column
32 + lvc.cx = 40;
33 + lvc.pszText = L"PID";
34 + ListView_InsertColumn(hlProcess, 0, &lvc);
35 + lvc.cx = 100;
36 + lvc.fmt = LVCFMT_LEFT; // left-aligned column
37 + lvc.pszText = L"Name";
38 + ListView_InsertColumn(hlProcess, 1, &lvc);
39 +}
40 +
41 +void ProcessWindow::RefreshProcess()
42 +{
43 + ListView_DeleteAllItems(hlProcess);
44 + LVITEM item = {};
45 + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
46 + DWORD idProcess[1024], cbNeeded;
47 + WCHAR path[MAX_PATH];
48 +
49 + if (EnumProcesses(idProcess, sizeof(idProcess), &cbNeeded))
50 + {
51 + DWORD len = cbNeeded / sizeof(DWORD);
52 + for (DWORD i = 0; i < len; ++i)
53 + {
54 + DWORD pid = idProcess[i];
55 + UniqueHandle hProcess(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
56 + if (hProcess)
57 + {
58 + if (GetProcessImageFileName(hProcess.get(), path, MAX_PATH))
59 + {
60 + WCHAR buffer[256];
61 + std::swprintf(buffer, L"%d", pid);
62 + PWCHAR name = wcsrchr(path, L'\\') + 1;
63 + item.pszText = buffer;
64 + item.lParam = pid;
65 + ListView_InsertItem(hlProcess, &item);
66 + ListView_SetItemText(hlProcess, item.iItem, 1, name);
67 + }
68 + }
69 + }
70 + }
71 +}
72 +
73 +void ProcessWindow::AttachProcess()
74 +{
75 + DWORD pid = GetSelectedPID();
76 + if (IHF_InjectByPID(pid) != -1)
77 + RefreshThreadWithPID(pid, true);
78 +}
79 +
80 +void ProcessWindow::DetachProcess()
81 +{
82 + DWORD pid = GetSelectedPID();
83 + if (IHF_ActiveDetachProcess(pid) == 0)
84 + RefreshThreadWithPID(pid, false);
85 +}
86 +
87 +void ProcessWindow::AddCurrentToProfile()
88 +{
89 + DWORD pid = GetSelectedPID();
90 + auto path = GetProcessPath(pid);
91 + if (!path.empty())
92 + {
93 + Profile* pf = pfman->AddProfile(path, pid);
94 + pfman->FindProfileAndUpdateHookAddresses(pid, path);
95 + RefreshThread(ListView_GetSelectionMark(hlProcess));
96 + }
97 +}
98 +
99 +void ProcessWindow::RemoveCurrentFromProfile()
100 +{
101 + DWORD pid = GetSelectedPID();
102 + auto path = GetProcessPath(pid);
103 + if (!path.empty())
104 + {
105 + pfman->DeleteProfile(path);
106 + RefreshThread(ListView_GetSelectionMark(hlProcess));
107 + }
108 +}
109 +
110 +void ProcessWindow::RefreshThread(int index)
111 +{
112 + LVITEM item = {};
113 + item.mask = LVIF_PARAM;
114 + item.iItem = index;
115 + ListView_GetItem(hlProcess, &item);
116 + DWORD pid = item.lParam;
117 + bool isAttached = man->GetProcessRecord(pid) != NULL;
118 + RefreshThreadWithPID(pid, isAttached);
119 +}
120 +
121 +void ProcessWindow::RefreshThreadWithPID(DWORD pid, bool isAttached)
122 +{
123 + EnableWindow(hbDetach, isAttached);
124 + EnableWindow(hbAttach, !isAttached);
125 + auto path = GetProcessPath(pid);
126 + bool hasProfile = !path.empty() && pfman->HasProfile(path);
127 + EnableWindow(hbAddProfile, isAttached && !hasProfile);
128 + EnableWindow(hbRemoveProfile, hasProfile);
129 + if (pid == GetCurrentProcessId())
130 + EnableWindow(hbAttach, FALSE);
131 +}
132 +
133 +DWORD ProcessWindow::GetSelectedPID()
134 +{
135 + LVITEM item={};
136 + item.mask = LVIF_PARAM;
137 + item.iItem = ListView_GetSelectionMark(hlProcess);
138 + ListView_GetItem(hlProcess, &item);
139 + return item.lParam;
140 +}
1 +#pragma once
2 +#include "ITH.h"
3 +
4 +class ProcessWindow
5 +{
6 +public:
7 + ProcessWindow(HWND hDialog);
8 + void InitProcessDlg();
9 + void RefreshProcess();
10 + void AttachProcess();
11 + void DetachProcess();
12 + void AddCurrentToProfile();
13 + void RemoveCurrentFromProfile();
14 + void RefreshThread(int index);
15 +private:
16 + void RefreshThreadWithPID(DWORD pid, bool isAttached);
17 + DWORD GetSelectedPID();
18 + HWND hDlg;
19 + HWND hlProcess;
20 + HWND hbRefresh,hbAttach,hbDetach,hbAddProfile,hbRemoveProfile;
21 + HWND heOutput;
22 +};
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +
19 +#include "ITH.h"
20 +#include "ith/host/srv.h"
21 +#include "ith/host/hookman.h"
22 +#include "ith/common/types.h"
23 +#include "ith/common/const.h"
24 +#include "Profile.h"
25 +#include "utility.h"
26 +
27 +Profile::Profile(const std::wstring& title) :
28 +select_index(-1),
29 +title(title)
30 +{}
31 +
32 +std::vector<thread_ptr>::const_iterator Profile::FindThreadProfile(const ThreadParameter& tp) const
33 +{
34 + auto thread_profile = std::find_if(threads.begin(), threads.end(),
35 + [&tp](const thread_ptr& thread_profile) -> bool
36 + {
37 + if (thread_profile->HookAddress() != tp.hook)
38 + return false;
39 + DWORD t1 = thread_profile->Return();
40 + DWORD t2 = tp.retn;
41 + if (thread_profile->Flags() & THREAD_MASK_RETN)
42 + {
43 + t1 &= 0xFFFF;
44 + t2 &= 0xFFFF;
45 + }
46 + if (t1 != t2)
47 + return false;
48 + t1 = thread_profile->Split();
49 + t2 = tp.spl;
50 + if (thread_profile->Flags() & THREAD_MASK_SPLIT)
51 + {
52 + t1 &= 0xFFFF;
53 + t2 &= 0xFFFF;
54 + }
55 + return t1 == t2;
56 + });
57 + return thread_profile;
58 +}
59 +
60 +const std::vector<hook_ptr>& Profile::Hooks() const
61 +{
62 + return hooks;
63 +}
64 +
65 +const std::vector<thread_ptr>& Profile::Threads() const
66 +{
67 + return threads;
68 +}
69 +
70 +const std::vector<link_ptr>& Profile::Links() const
71 +{
72 + return links;
73 +}
74 +
75 +bool Profile::XmlReadProfile(pugi::xml_node profile)
76 +{
77 + auto hooks_node = profile.child(L"Hooks");
78 + auto threads_node = profile.child(L"Threads");
79 + auto links_node = profile.child(L"Links");
80 + if (hooks_node && !XmlReadProfileHook(hooks_node))
81 + return false;
82 + if (threads_node && !XmlReadProfileThread(threads_node))
83 + return false;
84 + if (links_node && !XmlReadProfileLink(links_node))
85 + return false;
86 + auto select_node = profile.child(L"Select");
87 + if (select_node)
88 + {
89 + auto thread_index = select_node.attribute(L"ThreadIndex");
90 + if (!thread_index)
91 + return false;
92 + DWORD tmp_select = std::stoul(thread_index.value(), NULL, 16);
93 + select_index = tmp_select & 0xFFFF;
94 + }
95 + return true;
96 +}
97 +
98 +bool Profile::XmlReadProfileHook(pugi::xml_node hooks_node)
99 +{
100 + for (auto hook = hooks_node.begin(); hook != hooks_node.end(); ++hook)
101 + {
102 + std::wstring name = hook->name();
103 + if (name.empty() || name.compare(L"Hook") != 0)
104 + return false;
105 + auto type = hook->attribute(L"Type");
106 + if (!type || type.empty())
107 + return false;
108 + auto code = hook->attribute(L"Code");
109 + if (!code)
110 + return false;
111 + std::wstring code_value = code.value();
112 + HookParam hp = {};
113 + switch (type.value()[0])
114 + {
115 + case L'H':
116 + if (code_value[0] != L'/')
117 + return false;
118 + if (code_value[1] != L'H' && code_value[1] != L'h')
119 + return false;
120 + if (Parse(code_value.substr(2), hp))
121 + {
122 + auto name = hook->attribute(L"Name");
123 + if (!name || name.empty())
124 + AddHook(hp, L"");
125 + else
126 + AddHook(hp, name.value());
127 + }
128 + break;
129 + default:
130 + return false;
131 + }
132 + }
133 + return true;
134 +}
135 +
136 +bool Profile::XmlReadProfileThread(pugi::xml_node threads_node)
137 +{
138 + std::wstring hook_name_buffer;
139 + for (auto thread = threads_node.begin(); thread != threads_node.end(); ++thread)
140 + {
141 + std::wstring name = thread->name();
142 + if (name.empty() || name.compare(L"Thread") != 0)
143 + return false;
144 + auto hook_name = thread->attribute(L"HookName");
145 + if (!hook_name)
146 + return false;
147 + auto context = thread->attribute(L"Context");
148 + if (!context)
149 + return false;
150 + auto sub_context = thread->attribute(L"SubContext");
151 + if (!sub_context)
152 + return false;
153 + auto mask = thread->attribute(L"Mask");
154 + if (!mask)
155 + return false;
156 + DWORD mask_tmp = std::stoul(mask.value(), NULL, 16);
157 + auto comment = thread->attribute(L"Comment");
158 + auto retn = std::stoul(context.value(), NULL, 16);
159 + WORD hm_index = 0;
160 + auto hook_addr = 0;
161 + auto split = std::stoul(sub_context.value(), NULL, 16);
162 + WORD flags = mask_tmp & 0xFFFF;
163 + auto tp = new ThreadProfile(hook_name.value(), retn, split, hook_addr, hm_index, flags,
164 + comment.value());
165 + AddThread(thread_ptr(tp));
166 + }
167 + return true;
168 +}
169 +
170 +bool Profile::XmlReadProfileLink(pugi::xml_node links_node)
171 +{
172 + for (auto link = links_node.begin(); link != links_node.end(); ++link)
173 + {
174 + std::wstring name = link->name();
175 + if (name.empty() || name.compare(L"Link") != 0)
176 + return false;
177 + auto from = link->attribute(L"From");
178 + if (!from)
179 + return false;
180 + DWORD link_from = std::stoul(from.value(), NULL, 16);
181 + auto to = link->attribute(L"To");
182 + if (!to)
183 + return false;
184 + DWORD link_to = std::stoul(to.value(), NULL, 16);
185 + auto lp = new LinkProfile(link_from & 0xFFFF, link_to & 0xFFFF);
186 + AddLink(link_ptr(lp));
187 + }
188 + return true;
189 +}
190 +
191 +bool Profile::XmlWriteProfile(pugi::xml_node profile_node)
192 +{
193 + if (!hooks.empty())
194 + {
195 + auto node = profile_node.append_child(L"Hooks");
196 + XmlWriteProfileHook(node);
197 + }
198 + if (!threads.empty())
199 + {
200 + auto node = profile_node.append_child(L"Threads");
201 + XmlWriteProfileThread(node);
202 + }
203 + if (!links.empty())
204 + {
205 + auto node = profile_node.append_child(L"Links");
206 + XmlWriteProfileLink(node);
207 + }
208 + if (select_index != 0xFFFF)
209 + {
210 + auto node = profile_node.append_child(L"Select");
211 + node.append_attribute(L"ThreadIndex") = select_index;
212 + }
213 + return true;
214 +}
215 +
216 +bool Profile::XmlWriteProfileHook(pugi::xml_node hooks_node)
217 +{
218 + for (auto hook = hooks.begin(); hook != hooks.end(); ++hook)
219 + {
220 + auto hook_node = hooks_node.append_child(L"Hook");
221 + hook_node.append_attribute(L"Type") = L"H";
222 + hook_node.append_attribute(L"Code") = GetCode((*hook)->HP()).c_str();
223 + if (!(*hook)->Name().empty())
224 + hook_node.append_attribute(L"Name") = (*hook)->Name().c_str();
225 + }
226 + return true;
227 +}
228 +
229 +bool Profile::XmlWriteProfileThread(pugi::xml_node threads_node)
230 +{
231 + for (auto thread = threads.begin(); thread != threads.end(); ++thread)
232 + {
233 + const std::wstring& name = (*thread)->HookName();
234 + if (name.empty())
235 + return false;
236 + auto node = threads_node.append_child(L"Thread");
237 + node.append_attribute(L"HookName") = name.c_str();
238 + node.append_attribute(L"Mask") = ToHexString((*thread)->Flags() & 3).c_str();
239 + node.append_attribute(L"SubContext") = ToHexString((*thread)->Split()).c_str();
240 + node.append_attribute(L"Context") = ToHexString((*thread)->Return()).c_str();
241 + if (!(*thread)->Comment().empty())
242 + node.append_attribute(L"Comment") = (*thread)->Comment().c_str();
243 + }
244 + return true;
245 +}
246 +
247 +bool Profile::XmlWriteProfileLink(pugi::xml_node links_node)
248 +{
249 + for (auto link = links.begin(); link != links.end(); ++link)
250 + {
251 + auto node = links_node.append_child(L"Link");
252 + node.append_attribute(L"From") = ToHexString((*link)->FromIndex()).c_str();
253 + node.append_attribute(L"To") = ToHexString((*link)->ToIndex()).c_str();
254 + }
255 + return true;
256 +}
257 +
258 +void Profile::Clear()
259 +{
260 + title = L"";
261 + select_index = -1;
262 + hooks.clear();
263 + threads.clear();
264 + links.clear();
265 +}
266 +
267 +int Profile::AddHook(const HookParam& hp, const std::wstring& name)
268 +{
269 + //if (hook_count == 4) return;
270 + auto it = std::find_if(hooks.begin(), hooks.end(), [&hp](hook_ptr& hook)
271 + {
272 + return hook->HP().addr == hp.addr &&
273 + hook->HP().module == hp.module &&
274 + hook->HP().function == hp.function;
275 + });
276 + if (it != hooks.end())
277 + return it - hooks.begin();
278 + hooks.emplace_back(new HookProfile(hp, name));
279 + return hooks.size() - 1;
280 +}
281 +
282 +// add the thread profile and return its index
283 +int Profile::AddThread(thread_ptr tp)
284 +{
285 + auto it = std::find_if(threads.begin(), threads.end(), [&tp](thread_ptr& thread)
286 + {
287 + return thread->HookName().compare(tp->HookName()) == 0 &&
288 + thread->Return() == tp->Return() &&
289 + thread->Split() == tp->Split();
290 + });
291 + if (it != threads.end())
292 + return it - threads.begin();
293 + threads.push_back(std::move(tp));
294 + return threads.size() - 1;
295 +}
296 +
297 +int Profile::AddLink(link_ptr lp)
298 +{
299 + auto it = std::find_if(links.begin(), links.end(), [&lp] (link_ptr& link)
300 + {
301 + return link->FromIndex() == lp->FromIndex() &&
302 + link->ToIndex() == lp->ToIndex();
303 + });
304 + if (it != links.end())
305 + return it - links.begin();
306 + links.push_back(std::move(lp));
307 + return links.size() - 1;
308 +}
309 +
310 +void Profile::RemoveHook(DWORD index)
311 +{
312 + if (index >= 0 && index < hooks.size())
313 + hooks.erase(hooks.begin() + index);
314 +}
315 +
316 +void Profile::RemoveThread(DWORD index)
317 +{
318 + if (index >= 0 && index < threads.size())
319 + {
320 + links.erase(std::remove_if(links.begin(), links.end(), [index](link_ptr& link)
321 + {
322 + return link->FromIndex() == index + 1 || link->ToIndex() == index + 1;
323 + }), links.end());
324 + if (select_index == index)
325 + select_index = -1;
326 + threads.erase(threads.begin() + index);
327 + if (index < select_index)
328 + select_index--;
329 + }
330 +}
331 +
332 +void Profile::RemoveLink(DWORD index)
333 +{
334 + if (index >= 0 && index < links.size())
335 + links.erase(links.begin() + index);
336 +}
337 +
338 +const std::wstring& Profile::Title() const
339 +{
340 + return title;
341 +}
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#pragma once
19 +#include "ITH.h"
20 +#include "ith/common/types.h" // HookParam
21 +
22 +struct ThreadParameter;
23 +
24 +#define THREAD_MASK_RETN 1
25 +#define THREAD_MASK_SPLIT 2
26 +
27 +class HookProfile
28 +{
29 + HookParam hp;
30 + std::wstring name;
31 +public:
32 + HookProfile(const HookParam& hp, const std::wstring& name):
33 + hp(hp),
34 + name(name)
35 + {}
36 + const HookParam& HP() const { return hp; };
37 + const std::wstring& Name() const { return name; };
38 +};
39 +
40 +class ThreadProfile
41 +{
42 + std::wstring hook_name;
43 + DWORD retn;
44 + DWORD split;
45 + DWORD hook_addr;
46 + WORD hm_index, flags;
47 + std::wstring comment;
48 +public:
49 + ThreadProfile(const std::wstring& hook_name,
50 + DWORD retn,
51 + DWORD split,
52 + DWORD hook_addr,
53 + WORD hm_index,
54 + WORD flags,
55 + const std::wstring& comment) :
56 + hook_name(hook_name),
57 + retn(retn),
58 + split(split),
59 + hook_addr(hook_addr),
60 + hm_index(hm_index),
61 + flags(flags),
62 + comment(comment)
63 + {
64 + }
65 + const std::wstring& HookName() const { return hook_name; }
66 + const std::wstring& Comment() const { return comment; }
67 + DWORD Return() const { return retn; }
68 + DWORD Split() const { return split; }
69 + DWORD& HookAddress() { return hook_addr; }
70 + WORD& HookManagerIndex() { return hm_index; }
71 + WORD Flags() const { return flags; }
72 +};
73 +
74 +class LinkProfile
75 +{
76 + WORD from_index, to_index;
77 +public:
78 + LinkProfile(WORD from_index, WORD to_index):
79 + from_index(from_index),
80 + to_index(to_index)
81 + {}
82 + WORD FromIndex() const { return from_index; }
83 + WORD ToIndex() const { return to_index; }
84 +};
85 +
86 +typedef std::unique_ptr<HookProfile> hook_ptr;
87 +typedef std::unique_ptr<ThreadProfile> thread_ptr;
88 +typedef std::unique_ptr<LinkProfile> link_ptr;
89 +
90 +class Profile
91 +{
92 +public:
93 + Profile(const std::wstring& title);
94 + bool XmlReadProfile(pugi::xml_node profile_node);
95 + bool XmlWriteProfile(pugi::xml_node profile_node);
96 + int AddHook(const HookParam& hp, const std::wstring& name);
97 + int AddThread(thread_ptr tp);
98 + int AddLink(link_ptr lp);
99 + void Clear();
100 + const std::vector<hook_ptr>& Hooks() const;
101 + const std::vector<thread_ptr>& Threads() const;
102 + const std::vector<link_ptr>& Links() const;
103 + const std::wstring& Title() const;
104 + std::vector<thread_ptr>::const_iterator FindThreadProfile(const ThreadParameter& tp) const;
105 + WORD& SelectedIndex() { return select_index; }
106 +
107 +private:
108 + void RemoveLink(DWORD index);
109 + void RemoveHook(DWORD index);
110 + void RemoveThread(DWORD index);
111 +
112 + bool XmlReadProfileHook(pugi::xml_node hooks_node);
113 + bool XmlReadProfileThread(pugi::xml_node threads_node);
114 + bool XmlReadProfileLink(pugi::xml_node links_node);
115 + bool XmlWriteProfileHook(pugi::xml_node hooks_node);
116 + bool XmlWriteProfileThread(pugi::xml_node threads_node);
117 + bool XmlWriteProfileLink(pugi::xml_node links_node);
118 +
119 + std::wstring title;
120 + std::vector<hook_ptr> hooks;
121 + std::vector<thread_ptr> threads;
122 + std::vector<link_ptr> links;
123 +
124 + WORD select_index;
125 +};
1 +#include "ProfileManager.h"
2 +#include "Profile.h"
3 +#include "ith/host/srv.h"
4 +#include "ith/host/hookman.h"
5 +#include "ith/common/types.h"
6 +#include "ith/common/const.h"
7 +
8 +extern HookManager* man; // main.cpp
9 +extern LONG auto_inject, auto_insert, inject_delay; // main.cpp
10 +extern LONG insert_delay, process_time; // main.cpp
11 +bool MonitorFlag;
12 +ProfileManager* pfman;
13 +
14 +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter);
15 +void AddHooksToProfile(Profile& pf, const ProcessRecord& pr);
16 +void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid);
17 +DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread);
18 +void MakeHookRelative(const ProcessRecord& pr, HookParam& hp);
19 +std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address);
20 +void GetHookNameToAddressMap(const ProcessRecord& pr, std::map<std::wstring, DWORD>& hookNameToAddress);
21 +
22 +ProfileManager::ProfileManager():
23 +hMonitorThread(IthCreateThread(MonitorThread, 0))
24 +{
25 + LoadProfile();
26 +}
27 +ProfileManager::~ProfileManager()
28 +{
29 + SaveProfile();
30 + WaitForSingleObject(hMonitorThread.get(), 0);
31 +}
32 +
33 +Profile* ProfileManager::GetProfile(DWORD pid)
34 +{
35 + std::wstring path = GetProcessPath(pid);
36 + if (!path.empty())
37 + {
38 + auto node = profile_tree.find(path);
39 + if (node != profile_tree.end())
40 + return node->second.get();
41 + }
42 + return NULL;
43 +}
44 +
45 +bool ProfileManager::AddProfile(pugi::xml_node game)
46 +{
47 + auto file = game.child(L"File");
48 + auto profile = game.child(L"Profile");
49 + if (!file || !profile)
50 + return false;
51 + auto path = file.attribute(L"Path");
52 + if (!path)
53 + return false;
54 + auto profile_title = game.attribute(L"Title");
55 + auto title = profile_title ? profile_title.value() : L"";
56 + auto pf = new Profile(title);
57 + if (!pf->XmlReadProfile(profile))
58 + return false;
59 + AddProfile(path.value(), profile_ptr(pf));
60 + return true;
61 +}
62 +
63 +Profile* ProfileManager::AddProfile(const std::wstring& path, DWORD pid)
64 +{
65 + CSLock lock(cs);
66 + auto& pf = profile_tree[path];
67 + if (!pf)
68 + {
69 + std::wstring title = GetProcessTitle(pid);
70 + pf.reset(new Profile(title));
71 + }
72 + return pf.get();
73 +}
74 +
75 +Profile* ProfileManager::AddProfile(const std::wstring& path, profile_ptr new_profile)
76 +{
77 + CSLock lock(cs);
78 + auto& pf = profile_tree[path];
79 + if (!pf)
80 + pf.swap(new_profile);
81 + return pf.get();
82 +}
83 +
84 +void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node root)
85 +{
86 + auto game = root.append_child(L"Game");
87 + auto file_node = game.append_child(L"File");
88 + file_node.append_attribute(L"Path") = path.c_str();
89 + auto profile_node = game.append_child(L"Profile");
90 + pf.XmlWriteProfile(profile_node);
91 + if (!pf.Title().empty())
92 + {
93 + if (!game.attribute(L"Title"))
94 + game.append_attribute(L"Title");
95 + game.attribute(L"Title") = pf.Title().c_str();
96 + }
97 +}
98 +
99 +void ProfileManager::LoadProfile()
100 +{
101 + pugi::xml_document doc;
102 + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
103 + if (hFile.get() == INVALID_HANDLE_VALUE)
104 + return;
105 + DWORD size = GetFileSize(hFile.get(), NULL);
106 + std::unique_ptr<char[]> buffer(new char[size]);
107 + ReadFile(hFile.get(), buffer.get(), size, &size, NULL);
108 + auto result = doc.load_buffer(buffer.get(), size);
109 + if (!result)
110 + return;
111 + auto root = doc.root().child(L"ITH_Profile");
112 + if (!root)
113 + return;
114 + for (auto game = root.begin(); game != root.end(); ++game)
115 + AddProfile(*game);
116 +}
117 +
118 +void ProfileManager::SaveProfile()
119 +{
120 + pugi::xml_document doc;
121 + auto root = doc.append_child(L"ITH_Profile");
122 + for (auto it = profile_tree.begin(); it != profile_tree.end(); ++it) {
123 + auto& path = it->first;
124 + auto& profile = it->second;
125 + WriteProfileXml(path, *profile, root);
126 + }
127 + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_WRITE, 0, CREATE_ALWAYS));
128 + if (hFile.get() != INVALID_HANDLE_VALUE)
129 + {
130 + FileWriter fw(hFile.get());
131 + doc.save(fw);
132 + }
133 +}
134 +
135 +void ProfileManager::DeleteProfile(const std::wstring& path)
136 +{
137 + CSLock lock(cs);
138 + profile_tree.erase(profile_tree.find(path));
139 +}
140 +
141 +void ProfileManager::FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path)
142 +{
143 + if (path.empty())
144 + return;
145 + auto it = profile_tree.find(path);
146 + if (it == profile_tree.end())
147 + return;
148 + auto& pf = it->second;
149 + const ProcessRecord* pr = man->GetProcessRecord(pid);
150 + if (pr == NULL)
151 + return;
152 + // hook name -> hook address
153 + std::map<std::wstring, DWORD> hookNameToAddress;
154 + GetHookNameToAddressMap(*pr, hookNameToAddress);
155 + for (auto thread_profile = pf->Threads().begin(); thread_profile != pf->Threads().end();
156 + ++thread_profile)
157 + {
158 + auto it = hookNameToAddress.find((*thread_profile)->HookName());
159 + if (it != hookNameToAddress.end())
160 + (*thread_profile)->HookAddress() = it->second;
161 + }
162 +}
163 +
164 +void GetHookNameToAddressMap(const ProcessRecord& pr,
165 + std::map<std::wstring, DWORD>& hookNameToAddress)
166 +{
167 + WaitForSingleObject(pr.hookman_mutex, 0);
168 + auto hooks = (const Hook*)pr.hookman_map;
169 + for (DWORD i = 0; i < MAX_HOOK; ++i)
170 + {
171 + if (hooks[i].Address() == 0)
172 + continue;
173 + auto& hook = hooks[i];
174 + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
175 + if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL))
176 + hookNameToAddress[name.get()] = hook.Address();
177 + }
178 + ReleaseMutex(pr.hookman_mutex);
179 +}
180 +
181 +bool ProfileManager::HasProfile(const std::wstring& path)
182 +{
183 + return profile_tree.find(path) != profile_tree.end();
184 +}
185 +
186 +DWORD ProfileManager::ProfileCount()
187 +{
188 + return profile_tree.size();
189 +}
190 +
191 +DWORD WINAPI InjectThread(LPVOID lpThreadParameter)
192 +{
193 + DWORD pid = (DWORD)lpThreadParameter;
194 + Sleep(inject_delay);
195 + if (man == NULL)
196 + return 0;
197 + DWORD status = IHF_InjectByPID(pid);
198 + if (!auto_insert)
199 + return status;
200 + if (status == -1)
201 + return status;
202 + Sleep(insert_delay);
203 + const Profile* pf = pfman->GetProfile(pid);
204 + if (pf)
205 + {
206 + SendParam sp;
207 + sp.type = 0;
208 + for (auto hp = pf->Hooks().begin(); hp != pf->Hooks().end(); ++hp)
209 + IHF_InsertHook(pid, const_cast<HookParam*>(&(*hp)->HP()), (*hp)->Name().c_str());
210 + }
211 + return status;
212 +}
213 +
214 +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter)
215 +{
216 + while (MonitorFlag)
217 + {
218 + DWORD aProcesses[1024], cbNeeded, cProcesses;
219 + if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
220 + break;
221 + cProcesses = cbNeeded / sizeof(DWORD);
222 + for (size_t i = 0; i < cProcesses; ++i)
223 + {
224 + Sleep(process_time);
225 + if (!auto_inject || man == NULL || man->GetProcessRecord(aProcesses[i]))
226 + continue;
227 + std::wstring process_path = GetProcessPath(aProcesses[i]);
228 + if (!process_path.empty() && pfman->HasProfile(process_path))
229 + {
230 + UniqueHandle hThread(IthCreateThread(InjectThread, aProcesses[i]));
231 + WaitForSingleObject(hThread.get(), 0);
232 + }
233 + }
234 + }
235 + return 0;
236 +}
237 +
238 +DWORD SaveProcessProfile(DWORD pid)
239 +{
240 + const ProcessRecord* pr = man->GetProcessRecord(pid);
241 + if (pr == NULL)
242 + return 0;
243 + std::wstring path = GetProcessPath(pid);
244 + if (path.empty())
245 + return 0;
246 + Profile* pf = pfman->GetProfile(pid);
247 + if (pf != NULL)
248 + pf->Clear();
249 + else
250 + pf = pfman->AddProfile(path, pid);
251 + AddHooksToProfile(*pf, *pr);
252 + AddThreadsToProfile(*pf, *pr, pid);
253 + return 0;
254 +}
255 +
256 +void AddHooksToProfile(Profile& pf, const ProcessRecord& pr)
257 +{
258 + WaitForSingleObject(pr.hookman_mutex, 0);
259 + auto hooks = (const Hook*)pr.hookman_map;
260 + for (DWORD i = 0; i < MAX_HOOK; ++i)
261 + {
262 + if (hooks[i].Address() == 0)
263 + continue;
264 + auto& hook = hooks[i];
265 + DWORD type = hook.Type();
266 + if ((type & HOOK_ADDITIONAL) && (type & HOOK_ENGINE) == 0)
267 + {
268 + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
269 + if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL))
270 + {
271 + if (hook.hp.module)
272 + {
273 + HookParam hp = hook.hp;
274 + MakeHookRelative(pr, hp);
275 + pf.AddHook(hp, name.get());
276 + }
277 + else
278 + pf.AddHook(hook.hp, name.get());
279 + }
280 + }
281 + }
282 + ReleaseMutex(pr.hookman_mutex);
283 +}
284 +
285 +void MakeHookRelative(const ProcessRecord& pr, HookParam& hp)
286 +{
287 + MEMORY_BASIC_INFORMATION info;
288 + VirtualQueryEx(pr.process_handle, (LPCVOID)hp.addr, &info, sizeof(info));
289 + hp.addr -= (DWORD)info.AllocationBase;
290 + hp.function = 0;
291 +}
292 +
293 +void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid)
294 +{
295 + man->LockHookman();
296 + ThreadTable* table = man->Table();
297 + for (int i = 0; i < table->Used(); ++i)
298 + {
299 + TextThread* tt = table->FindThread(i);
300 + if (tt == NULL || tt->GetThreadParameter()->pid != pid)
301 + continue;
302 + //if (tt->Status() & CURRENT_SELECT || tt->Link() || tt->GetComment())
303 + if (tt->Status() & CURRENT_SELECT || tt->Link())
304 + AddThreadToProfile(pf, pr, *tt);
305 + }
306 + man->UnlockHookman();
307 +}
308 +
309 +DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread)
310 +{
311 + const ThreadParameter* tp = thread.GetThreadParameter();
312 + std::wstring hook_name = GetHookNameByAddress(pr, tp->hook);
313 + if (hook_name.empty())
314 + return -1;
315 + auto thread_profile = new ThreadProfile(hook_name, tp->retn, tp->spl, 0, 0,
316 + THREAD_MASK_RETN | THREAD_MASK_SPLIT, L"");
317 + DWORD threads_size = pf.Threads().size();
318 + int thread_profile_index = pf.AddThread(thread_ptr(thread_profile));
319 + if (thread_profile_index == threads_size) // new thread
320 + {
321 + WORD iw = thread_profile_index & 0xFFFF;
322 + if (thread.Status() & CURRENT_SELECT)
323 + pf.SelectedIndex() = iw;
324 + if (thread.Link())
325 + {
326 + WORD to_index = AddThreadToProfile(pf, pr, *(thread.Link())) & 0xFFFF;
327 + if (iw >= 0)
328 + pf.AddLink(link_ptr(new LinkProfile(iw, to_index)));
329 + }
330 + }
331 + return thread_profile_index; // in case more than one thread links to the same thread.
332 +}
333 +
334 +std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address)
335 +{
336 + std::wstring hook_name;
337 + WaitForSingleObject(pr.hookman_mutex, 0);
338 + auto hooks = (const Hook*)pr.hookman_map;
339 + for (int i = 0; i < MAX_HOOK; ++i)
340 + {
341 + auto& hook = hooks[i];
342 + if (hook.Address() == hook_address)
343 + {
344 + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]);
345 + if (ReadProcessMemory(pr.process_handle, hooks[i].Name(), name.get(), hook.NameLength() * 2, NULL))
346 + hook_name = name.get();
347 + break;
348 + }
349 + }
350 + ReleaseMutex(pr.hookman_mutex);
351 + return hook_name;
352 +}
1 +#pragma once
2 +#include "ITH.h"
3 +#include "utility.h" // UniqueHandle, CriticalSection
4 +
5 +class Profile;
6 +
7 +class ProfileManager
8 +{
9 +public:
10 + ProfileManager();
11 + ~ProfileManager();
12 + Profile* AddProfile(const std::wstring& path, DWORD pid);
13 + void DeleteProfile(const std::wstring& path);
14 + void LoadProfile();
15 + void SaveProfile();
16 + void FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path);
17 + bool HasProfile(const std::wstring& path);
18 + Profile* GetProfile(DWORD pid);
19 + DWORD ProfileCount();
20 +private:
21 + typedef std::unique_ptr<Profile> profile_ptr;
22 + typedef std::map<std::wstring, profile_ptr> profile_map;
23 +
24 + ProfileManager(const ProfileManager&);
25 + ProfileManager operator=(const ProfileManager&);
26 +
27 + bool AddProfile(pugi::xml_node game);
28 + Profile* AddProfile(const std::wstring& path, profile_ptr new_profile);
29 + void WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node doc);
30 + // locate profile with executable path
31 + profile_map profile_tree;
32 + CriticalSection cs;
33 + UniqueHandle hMonitorThread;
34 +};
1 +#include "TextBuffer.h"
2 +
3 +DWORD WINAPI FlushThread(LPVOID lParam); // window.cpp
4 +
5 +TextBuffer::TextBuffer(HWND edit) : hThread(IthCreateThread(FlushThread, (DWORD)this)),
6 + hEdit(edit),
7 + running(true)
8 +{
9 +}
10 +
11 +TextBuffer::~TextBuffer()
12 +{
13 + running = false;
14 + WaitForSingleObject(hThread.get(), 0);
15 +}
16 +
17 +void TextBuffer::AddText(LPCWSTR str, int len, bool line)
18 +{
19 + CSLock lock(cs);
20 + if (len > 0)
21 + this->str.append(str, len);
22 + line_break = line;
23 +}
24 +
25 +void TextBuffer::Flush()
26 +{
27 + CSLock lock(cs);
28 + if (line_break || str.empty())
29 + return;
30 + DWORD t = Edit_GetTextLength(hEdit);
31 + Edit_SetSel(hEdit, t, -1);
32 + Edit_ReplaceSel(hEdit, str.c_str());
33 + str.clear();
34 +}
35 +
36 +void TextBuffer::ClearBuffer()
37 +{
38 + CSLock lock(cs);
39 + str.clear();
40 + line_break = false;
41 +}
1 +#pragma once
2 +#include "ITH.h"
3 +#include "utility.h" // UniqueHandle, CriticalSection
4 +
5 +class TextBuffer
6 +{
7 +public:
8 + TextBuffer(HWND edit);
9 + ~TextBuffer();
10 + void Flush();
11 + void AddText(LPCWSTR str, int len, bool line);
12 + void ClearBuffer();
13 + bool Running() { return running; }
14 +private:
15 + CriticalSection cs;
16 + bool line_break, running;
17 + UniqueHandle hThread;
18 + HWND hEdit;
19 + std::wstring str;
20 +};
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +const wchar_t* Warning=L"Warning!";
18 +//command.cpp
19 +const wchar_t* ErrorSyntax=L"Syntax error";
20 +const wchar_t* Usage = L"Syntax:\r\n\
21 +\r\n\
22 +:H[ELP] - print help\r\n\
23 +:Lfrom-to - link from thread 'from' to thread 'to'\r\n\
24 +:Ufrom - unlink link from thread 'from'\r\n\
25 +\r\n\
26 +'from' and 'to' and hexadecimal thread numbers. The thread number is the first number in the combo box.\r\n\
27 +\r\n\
28 +Loader options:\r\n\
29 +/P[{process_id|Nprocess_name}] - attach to process\r\n\
30 +\r\n\
31 +Hook options:\r\n\
32 +/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\
33 +\r\n\
34 +All numbers in /H (except ordinal) are hexadecimal without any prefixes";
35 +
36 +const wchar_t* ExtendedUsage = L"/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]\r\n\
37 +\r\n\
38 +Set additional custom hook\r\n\
39 +\r\n\
40 +Hook types :\r\n\
41 +A - DBCS char\r\n\
42 +B - DBCS char(big-endian)\r\n\
43 +W - UCS2 char\r\n\
44 +S - MBCS string\r\n\
45 +Q - UTF-16 string\r\n\
46 +\r\n\
47 +Parameters:\r\n\
48 +X - use hardware breakpoints\r\n\
49 +N - don't use contexts\r\n\
50 +data_offset - stack offset to char / string pointer\r\n\
51 +drdo - add a level of indirection to data_offset\r\n\
52 +sub_offset - stack offset to subcontext\r\n\
53 +drso - add a level of indirection to sub_offset\r\n\
54 +addr - address of the hook\r\n\
55 +module - name of the module to use as base for 'addr'\r\n\
56 +name - name of the 'module' export to use as base for 'addr'\r\n\
57 +ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\
58 +\r\n\
59 +Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\
60 +- 4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI\r\n\
61 +\r\n\
62 +\"Add a level of indirection\" means in C/C++ style: (*(ESP+data_offset)+drdo) instead of (ESP+data_offset)\r\n\
63 +\r\n\
64 +All numbers except ordinal are hexadecimal without any prefixes";
65 +
66 +//inject.cpp
67 +const wchar_t* ErrorRemoteThread=L"Can't create remote thread.";
68 +const wchar_t* ErrorOpenProcess=L"Can't open process.";
69 +const wchar_t* ErrorNoProcess=L"Process not found";
70 +const wchar_t* SelfAttach=L"Please do not attach to ITH.exe";
71 +const wchar_t* AlreadyAttach=L"Process already attached.";
72 +const wchar_t* FormatInject=L"Inject process %d. Module base %.8X";
73 +//main.cpp
74 +const wchar_t* NotAdmin=L"Can't enable SeDebugPrevilege. ITH might malfunction.\r\n\
75 +Please run ITH as administrator or turn off UAC.";
76 +//pipe.cpp
77 +const wchar_t* ErrorCreatePipe=L"Can't create text pipe or too many instance.";
78 +const wchar_t* FormatDetach=L"Process %d detached.";
79 +const wchar_t* ErrorCmdQueueFull=L"Command queue full.";
80 +const wchar_t* ErrorNoAttach=L"No process attached.";
81 +
82 +//profile.cpp
83 +const wchar_t* ErrorMonitor=L"Can't monitor process.";
84 +//utility.cpp
85 +const wchar_t* InitMessage=L"Copyright (C) 2010-2012 kaosu <qiupf2000@gmail.com>\r\n\
86 +Copyright (C) 2015 zorkzero <zorkzero@hotmail.com>\r\n\
87 +Source code <https://code.google.com/p/interactive-text-hooker/>\r\n\
88 +General discussion <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>";
89 +const wchar_t* BackgroundMsg=L"Type \":h\" or \":help\" for help.";
90 +const wchar_t* ErrorLinkExist=L"Link exist.";
91 +const wchar_t* ErrorCylicLink=L"Link failed. No cyclic link allowed.";
92 +const wchar_t* FormatLink=L"Link from thread%.4x to thread%.4x.";
93 +const wchar_t* ErrorLink=L"Link failed. Source or/and destination thread not found.";
94 +const wchar_t* ErrorDeleteCombo=L"Error delete from combo.";
95 +
96 +//window.cpp
97 +const wchar_t* ClassName=L"ITH";
98 +const wchar_t* ClassNameAdmin=L"ITH (Administrator)";
99 +const wchar_t* ErrorNotSplit=L"Need to enable split first!";
100 +const wchar_t* ErrorNotModule=L"Need to enable module first!";
101 +//Main window buttons
102 +const wchar_t* ButtonTitleProcess=L"Process";
103 +const wchar_t* ButtonTitleThread=L"Thread";
104 +const wchar_t* ButtonTitleHook=L"Hook";
105 +const wchar_t* ButtonTitleProfile=L"Profile";
106 +const wchar_t* ButtonTitleOption=L"Option";
107 +const wchar_t* ButtonTitleClear=L"Clear";
108 +const wchar_t* ButtonTitleSave=L"Save";
109 +const wchar_t* ButtonTitleTop=L"Top";
110 +//Hook window
111 +const wchar_t* SpecialHook=L"Special hook, no AGTH equivalent.";
112 +//Process window
113 +const wchar_t* TabTitlePID=L"PID";
114 +const wchar_t* TabTitleMemory=L"Memory";
115 +const wchar_t* TabTitleName=L"Name";
116 +const wchar_t* TabTitleTID=L"TID";
117 +const wchar_t* TabTitleStart=L"Start";
118 +const wchar_t* TabTitleModule=L"Module";
119 +const wchar_t* TabTitleState=L"State";
120 +const wchar_t* SuccessAttach=L"Attach ITH to process successfully.";
121 +const wchar_t* FailAttach=L"Failed to attach ITH to process.";
122 +const wchar_t* SuccessDetach=L"ITH detach from process.";
123 +const wchar_t* FailDetach=L"Detach failed.";
124 +//Profile window
125 +const wchar_t* ProfileExist=L"Profile already exists.";
126 +const wchar_t* SuccessAddProfile=L"Profile added.";
127 +const wchar_t* FailAddProfile=L"Fail to add profile";
128 +const wchar_t* TabTitleNumber=L"No.";
129 +const wchar_t* NoFile=L"Can't find file.";
130 +const wchar_t* PathDismatch=L"Process name dismatch, continue?";
131 +const wchar_t* SuccessImportProfile=L"Import profile success";
132 +//const wchar_t* SuccessAddProfile=L"Profile added.";
...\ No newline at end of file ...\ No newline at end of file
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +#pragma once
18 +
19 +extern const wchar_t* Warning;
20 +//command.cpp
21 +extern const wchar_t* ErrorSyntax;
22 +extern const wchar_t* Usage;
23 +extern const wchar_t* ExtendedUsage;
24 +//inject.cpp
25 +extern const wchar_t* ErrorRemoteThread;
26 +extern const wchar_t* ErrorOpenProcess;
27 +extern const wchar_t* ErrorNoProcess;
28 +extern const wchar_t* SelfAttach;
29 +extern const wchar_t* AlreadyAttach;
30 +extern const wchar_t* FormatInject;
31 +//main.cpp
32 +extern const wchar_t* NotAdmin;
33 +//pipe.cpp
34 +extern const wchar_t* ErrorCreatePipe;
35 +extern const wchar_t* FormatDetach;
36 +extern const wchar_t* ErrorCmdQueueFull;
37 +extern const wchar_t* ErrorNoAttach;
38 +
39 +//profile.cpp
40 +extern const wchar_t* ErrorMonitor;
41 +
42 +//utility.cpp
43 +extern const wchar_t* InitMessage;
44 +extern const wchar_t* BackgroundMsg;
45 +extern const wchar_t* ErrorLinkExist;
46 +extern const wchar_t* ErrorCylicLink;
47 +extern const wchar_t* FormatLink;
48 +extern const wchar_t* ErrorLink;
49 +extern const wchar_t* ErrorDeleteCombo;
50 +
51 +//window.cpp
52 +extern const wchar_t* ClassName;
53 +extern const wchar_t* ClassNameAdmin;
54 +extern const wchar_t* ErrorNotSplit;
55 +extern const wchar_t* ErrorNotModule;
56 +//Main window buttons
57 +extern const wchar_t* ButtonTitleProcess;
58 +extern const wchar_t* ButtonTitleThread;
59 +extern const wchar_t* ButtonTitleHook;
60 +extern const wchar_t* ButtonTitleProfile;
61 +extern const wchar_t* ButtonTitleOption;
62 +extern const wchar_t* ButtonTitleClear;
63 +extern const wchar_t* ButtonTitleSave;
64 +extern const wchar_t* ButtonTitleTop;
65 +//Hook window
66 +extern const wchar_t* SpecialHook;
67 +//Process window
68 +extern const wchar_t* TabTitlePID;
69 +extern const wchar_t* TabTitleMemory;
70 +extern const wchar_t* TabTitleName;
71 +extern const wchar_t* TabTitleTID;
72 +extern const wchar_t* TabTitleStart;
73 +extern const wchar_t* TabTitleModule;
74 +extern const wchar_t* TabTitleState;
75 +extern const wchar_t* SuccessAttach;
76 +extern const wchar_t* FailAttach;
77 +extern const wchar_t* SuccessDetach;
78 +extern const wchar_t* FailDetach;
79 +//Profile window
80 +extern const wchar_t* ProfileExist;
81 +extern const wchar_t* SuccessAddProfile;
82 +extern const wchar_t* FailAddProfile;
83 +extern const wchar_t* TabTitleNumber;
84 +extern const wchar_t* NoFile;
85 +extern const wchar_t* PathDismatch;
86 +extern const wchar_t* SuccessImportProfile;
...\ No newline at end of file ...\ No newline at end of file
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#include "ITH.h"
19 +#include "ith/host/srv.h"
20 +#include "ith/host/hookman.h"
21 +#include "ith/host/SettingManager.h"
22 +#include "CustomFilter.h"
23 +#include "profile.h"
24 +#include "ProfileManager.h"
25 +
26 +HINSTANCE hIns;
27 +ATOM MyRegisterClass(HINSTANCE hInstance);
28 +BOOL InitInstance(HINSTANCE hInstance, DWORD nCmdShow, RECT *rc);
29 +RECT window;
30 +extern HWND hMainWnd; // windows.cpp
31 +extern bool MonitorFlag; // ProfileManager.cpp
32 +extern ProfileManager* pfman; // ProfileManager.cpp
33 +
34 +extern "C" {
35 + BOOL IthInitSystemService();
36 + void IthCloseSystemService();
37 +}
38 +
39 +CustomFilter* uni_filter;
40 +CustomFilter* mb_filter;
41 +HookManager* man;
42 +SettingManager* setman;
43 +LONG split_time, cyclic_remove, global_filter;
44 +LONG process_time, inject_delay, insert_delay,
45 + auto_inject, auto_insert, clipboard_flag;
46 +
47 +std::map<std::wstring, long> setting;
48 +
49 +void RecordMBChar(WORD mb, PVOID f)
50 +{
51 + auto filter = (pugi::xml_node*)f;
52 + DWORD m = mb;
53 + WCHAR buffer[16];
54 + std::swprintf(buffer, L"m%04X", m);
55 + filter->append_attribute(buffer) = L"0";
56 +}
57 +
58 +void RecordUniChar(WORD uni, PVOID f)
59 +{
60 + auto filter = (pugi::xml_node*)f;
61 + DWORD m = uni;
62 + WCHAR buffer[16];
63 + std::swprintf(buffer, L"u%04X", m);
64 + filter->append_attribute(buffer) = L"0";
65 + std::wstring text = filter->text().get();
66 + text += (wchar_t)m;
67 + filter->text().set(text.c_str());
68 +}
69 +
70 +void SaveSettings()
71 +{
72 + GetWindowRect(hMainWnd, &window);
73 + setting[L"window_left"] = window.left;
74 + setting[L"window_right"] = window.right;
75 + setting[L"window_top"] = window.top;
76 + setting[L"window_bottom"] = window.bottom;
77 + setting[L"split_time"] = split_time;
78 + setting[L"process_time"] = process_time;
79 + setting[L"inject_delay"] = inject_delay;
80 + setting[L"insert_delay"] = insert_delay;
81 + setting[L"auto_inject"] = auto_inject;
82 + setting[L"auto_insert"] = auto_insert;
83 + setting[L"auto_copy"] = clipboard_flag;
84 + setting[L"auto_suppress"] = cyclic_remove;
85 + setting[L"global_filter"] = global_filter;
86 +
87 + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
88 + if (hFile.get() != INVALID_HANDLE_VALUE)
89 + {
90 + FileWriter fw(hFile.get());
91 + pugi::xml_document doc;
92 + auto root = doc.root().append_child(L"ITH_Setting");
93 + for (auto it = setting.begin(); it != setting.end(); ++it)
94 + root.append_attribute(it->first.c_str()).set_value(it->second);
95 + auto filter = root.append_child(L"SingleCharFilter");
96 + filter.append_child(pugi::xml_node_type::node_pcdata);
97 + mb_filter->Traverse(RecordMBChar, &filter);
98 + uni_filter->Traverse(RecordUniChar, &filter);
99 + doc.save(fw);
100 + }
101 +}
102 +
103 +void DefaultSettings()
104 +{
105 + setting[L"split_time"] = 200;
106 + setting[L"process_time"] = 50;
107 + setting[L"inject_delay"] = 3000;
108 + setting[L"insert_delay"] = 500;
109 + setting[L"auto_inject"] = 1;
110 + setting[L"auto_insert"] = 1;
111 + setting[L"auto_copy"] = 0;
112 + setting[L"auto_suppress"] = 0;
113 + setting[L"global_filter"] = 0;
114 + setting[L"window_left"] = 100;
115 + setting[L"window_right"] = 800;
116 + setting[L"window_top"] = 100;
117 + setting[L"window_bottom"] = 600;
118 +}
119 +
120 +void InitializeSettings()
121 +{
122 + split_time = setting[L"split_time"];
123 + process_time = setting[L"process_time"];
124 + inject_delay = setting[L"inject_delay"];
125 + insert_delay = setting[L"insert_delay"];
126 + auto_inject = setting[L"auto_inject"];
127 + auto_insert = setting[L"auto_insert"];
128 + clipboard_flag = setting[L"auto_copy"];
129 + cyclic_remove = setting[L"auto_suppress"];
130 + global_filter = setting[L"global_filter"];
131 + window.left = setting[L"window_left"];
132 + window.right = setting[L"window_right"];
133 + window.top = setting[L"window_top"];
134 + window.bottom = setting[L"window_bottom"];
135 +
136 + if (auto_inject > 1)
137 + auto_inject = 1;
138 + if (auto_insert > 1)
139 + auto_insert = 1;
140 + if (clipboard_flag > 1)
141 + clipboard_flag = 1;
142 + if (cyclic_remove > 1)
143 + cyclic_remove = 1;
144 +
145 + if (window.right < window.left || window.right - window.left < 600)
146 + window.right = window.left + 600;
147 + if (window.bottom < window.top || window.bottom - window.top < 200)
148 + window.bottom = window.top + 200;
149 +}
150 +
151 +void LoadSettings()
152 +{
153 + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
154 + if (hFile.get() != INVALID_HANDLE_VALUE)
155 + {
156 + DWORD size = GetFileSize(hFile.get(), NULL);
157 + std::unique_ptr<char[]> buffer(new char[size]);
158 + ReadFile(hFile.get(), buffer.get(), size, &size, NULL);
159 + pugi::xml_document doc;
160 + auto result = doc.load_buffer_inplace(buffer.get(), size);
161 + if (!result)
162 + return;
163 + auto root = doc.root().child(L"ITH_Setting");
164 + for (auto attr = root.attributes_begin(); attr != root.attributes_end(); ++attr)
165 + {
166 + auto it = setting.find(attr->name());
167 + if (it != setting.end())
168 + it->second = std::stoul(attr->value());
169 + }
170 + auto filter = root.child(L"SingleCharFilter");
171 + if (filter)
172 + {
173 + for (auto attr = filter.attributes_begin(); attr != filter.attributes_end(); ++attr)
174 + {
175 + if (attr->name()[0] == L'm')
176 + {
177 + DWORD c = std::stoul(attr->name() + 1, NULL, 16);
178 + mb_filter->Insert(c & 0xFFFF);
179 + }
180 + else if (attr->name()[0] == L'u')
181 + {
182 + DWORD c = std::stoul(attr->name() + 1, NULL, 16);
183 + uni_filter->Insert(c & 0xFFFF);
184 + }
185 + }
186 + std::wstring filter_value = filter.text().get();
187 + for (auto it = filter_value.begin(); it != filter_value.end(); ++it)
188 + {
189 + WCHAR filter_unichar[2] = { *it, L'\0' };
190 + char filter_mbchar[4];
191 + WC_MB(filter_unichar, filter_mbchar, 4);
192 + mb_filter->Insert(*(WORD*)filter_mbchar);
193 + uni_filter->Insert(*it);
194 + }
195 + }
196 + }
197 +}
198 +
199 +extern LPCWSTR ClassName, ClassNameAdmin;
200 +static WCHAR mutex[] = L"ITH_RUNNING";
201 +DWORD FindITH()
202 +{
203 + HWND hwnd = FindWindow(ClassName, ClassName);
204 + if (hwnd == NULL)
205 + hwnd = FindWindow(ClassName, ClassNameAdmin);
206 + if (hwnd)
207 + {
208 + ShowWindow(hwnd, SW_SHOWNORMAL);
209 + SetForegroundWindow(hwnd);
210 + return 0;
211 + }
212 + return 1;
213 +}
214 +LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo)
215 +{
216 + wchar_t path_name[512]; // fully qualified path name
217 + WCHAR code[16];
218 + EXCEPTION_RECORD* rec = ExceptionInfo->ExceptionRecord;
219 + std::swprintf(code, L"%08X", rec->ExceptionCode);
220 + MEMORY_BASIC_INFORMATION info;
221 + if (VirtualQuery(rec->ExceptionAddress, &info, sizeof(info)))
222 + {
223 + if (GetModuleFileName((HMODULE)info.AllocationBase, path_name, 512))
224 + {
225 + LPWSTR name = wcsrchr(path_name, L'\\');
226 + if (name)
227 + {
228 + DWORD addr = (DWORD)rec->ExceptionAddress;
229 + std::swprintf(name, L"%s:%08X", name + 1, addr - (DWORD)info.AllocationBase);
230 + MessageBox(NULL, name, code, MB_OK);
231 + TerminateProcess(GetCurrentProcess(), 0);
232 + }
233 + }
234 + }
235 + std::swprintf(path_name, L"%08X", rec->ExceptionAddress);
236 + MessageBox(NULL, path_name, code, MB_OK);
237 + TerminateProcess(GetCurrentProcess(), 0);
238 + return 0;
239 +}
240 +
241 +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
242 +{
243 + if (!IthInitSystemService())
244 + TerminateProcess(GetCurrentProcess(), 0);
245 + CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING");
246 + if (IHF_Init())
247 + {
248 + SetUnhandledExceptionFilter(UnhandledExcept);
249 + IHF_GetHookManager(&man);
250 + IHF_GetSettingManager(&setman);
251 + setman->SetValue(SETTING_SPLIT_TIME, 200);
252 + MonitorFlag = true;
253 + pfman = new ProfileManager();
254 + mb_filter = new CustomFilter();
255 + uni_filter = new CustomFilter();
256 + DefaultSettings();
257 + LoadSettings();
258 + InitializeSettings();
259 + setman->SetValue(SETTING_SPLIT_TIME, split_time);
260 + setman->SetValue(SETTING_CLIPFLAG, clipboard_flag);
261 + hIns = hInstance;
262 + MyRegisterClass(hIns);
263 + InitInstance(hIns, IHF_IsAdmin(), &window);
264 + MSG msg;
265 + while (GetMessage(&msg, NULL, 0, 0))
266 + {
267 + TranslateMessage(&msg);
268 + DispatchMessage(&msg);
269 + }
270 + //delete mb_filter;
271 + //delete uni_filter;
272 + delete pfman;
273 + MonitorFlag = false;
274 + man = NULL;
275 + }
276 + else
277 + {
278 + FindITH();
279 + }
280 + IHF_Cleanup();
281 + IthCloseSystemService();
282 + TerminateProcess(GetCurrentProcess(), 0);
283 +}
This diff could not be displayed because it is too large.
1 +/**
2 + * pugixml parser - version 1.5
3 + * --------------------------------------------------------
4 + * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5 + * Report bugs and download new versions at http://pugixml.org/
6 + *
7 + * This library is distributed under the MIT License. See notice at the end
8 + * of this file.
9 + *
10 + * This work is based on the pugxml parser, which is:
11 + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12 + */
13 +
14 +#ifndef PUGIXML_VERSION
15 +// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
16 +# define PUGIXML_VERSION 150
17 +#endif
18 +
19 +// Include user configuration file (this can define various configuration macros)
20 +#include "pugiconfig.hpp"
21 +
22 +#ifndef HEADER_PUGIXML_HPP
23 +#define HEADER_PUGIXML_HPP
24 +
25 +// Include stddef.h for size_t and ptrdiff_t
26 +#include <stddef.h>
27 +
28 +// Include exception header for XPath
29 +#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)
30 +# include <exception>
31 +#endif
32 +
33 +// Include STL headers
34 +#ifndef PUGIXML_NO_STL
35 +# include <iterator>
36 +# include <iosfwd>
37 +# include <string>
38 +#endif
39 +
40 +// Macro for deprecated features
41 +#ifndef PUGIXML_DEPRECATED
42 +# if defined(__GNUC__)
43 +# define PUGIXML_DEPRECATED __attribute__((deprecated))
44 +# elif defined(_MSC_VER) && _MSC_VER >= 1300
45 +# define PUGIXML_DEPRECATED __declspec(deprecated)
46 +# else
47 +# define PUGIXML_DEPRECATED
48 +# endif
49 +#endif
50 +
51 +// If no API is defined, assume default
52 +#ifndef PUGIXML_API
53 +# define PUGIXML_API
54 +#endif
55 +
56 +// If no API for classes is defined, assume default
57 +#ifndef PUGIXML_CLASS
58 +# define PUGIXML_CLASS PUGIXML_API
59 +#endif
60 +
61 +// If no API for functions is defined, assume default
62 +#ifndef PUGIXML_FUNCTION
63 +# define PUGIXML_FUNCTION PUGIXML_API
64 +#endif
65 +
66 +// If the platform is known to have long long support, enable long long functions
67 +#ifndef PUGIXML_HAS_LONG_LONG
68 +# if defined(__cplusplus) && __cplusplus >= 201103
69 +# define PUGIXML_HAS_LONG_LONG
70 +# elif defined(_MSC_VER) && _MSC_VER >= 1400
71 +# define PUGIXML_HAS_LONG_LONG
72 +# endif
73 +#endif
74 +
75 +// Character interface macros
76 +#ifdef PUGIXML_WCHAR_MODE
77 +# define PUGIXML_TEXT(t) L ## t
78 +# define PUGIXML_CHAR wchar_t
79 +#else
80 +# define PUGIXML_TEXT(t) t
81 +# define PUGIXML_CHAR char
82 +#endif
83 +
84 +namespace pugi
85 +{
86 + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE
87 + typedef PUGIXML_CHAR char_t;
88 +
89 +#ifndef PUGIXML_NO_STL
90 + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE
91 + typedef std::basic_string<PUGIXML_CHAR, std::char_traits<PUGIXML_CHAR>, std::allocator<PUGIXML_CHAR> > string_t;
92 +#endif
93 +}
94 +
95 +// The PugiXML namespace
96 +namespace pugi
97 +{
98 + // Tree node types
99 + enum xml_node_type
100 + {
101 + node_null, // Empty (null) node handle
102 + node_document, // A document tree's absolute root
103 + node_element, // Element tag, i.e. '<node/>'
104 + node_pcdata, // Plain character data, i.e. 'text'
105 + node_cdata, // Character data, i.e. '<![CDATA[text]]>'
106 + node_comment, // Comment tag, i.e. '<!-- text -->'
107 + node_pi, // Processing instruction, i.e. '<?name?>'
108 + node_declaration, // Document declaration, i.e. '<?xml version="1.0"?>'
109 + node_doctype // Document type declaration, i.e. '<!DOCTYPE doc>'
110 + };
111 +
112 + // Parsing options
113 +
114 + // Minimal parsing mode (equivalent to turning all other flags off).
115 + // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.
116 + const unsigned int parse_minimal = 0x0000;
117 +
118 + // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default.
119 + const unsigned int parse_pi = 0x0001;
120 +
121 + // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default.
122 + const unsigned int parse_comments = 0x0002;
123 +
124 + // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default.
125 + const unsigned int parse_cdata = 0x0004;
126 +
127 + // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree.
128 + // This flag is off by default; turning it on usually results in slower parsing and more memory consumption.
129 + const unsigned int parse_ws_pcdata = 0x0008;
130 +
131 + // This flag determines if character and entity references are expanded during parsing. This flag is on by default.
132 + const unsigned int parse_escapes = 0x0010;
133 +
134 + // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.
135 + const unsigned int parse_eol = 0x0020;
136 +
137 + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.
138 + const unsigned int parse_wconv_attribute = 0x0040;
139 +
140 + // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.
141 + const unsigned int parse_wnorm_attribute = 0x0080;
142 +
143 + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.
144 + const unsigned int parse_declaration = 0x0100;
145 +
146 + // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.
147 + const unsigned int parse_doctype = 0x0200;
148 +
149 + // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only
150 + // of whitespace is added to the DOM tree.
151 + // This flag is off by default; turning it on may result in slower parsing and more memory consumption.
152 + const unsigned int parse_ws_pcdata_single = 0x0400;
153 +
154 + // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default.
155 + const unsigned int parse_trim_pcdata = 0x0800;
156 +
157 + // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document
158 + // is a valid document. This flag is off by default.
159 + const unsigned int parse_fragment = 0x1000;
160 +
161 + // The default parsing mode.
162 + // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
163 + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
164 + const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;
165 +
166 + // The full parsing mode.
167 + // Nodes of all types are added to the DOM tree, character/reference entities are expanded,
168 + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
169 + const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;
170 +
171 + // These flags determine the encoding of input data for XML document
172 + enum xml_encoding
173 + {
174 + encoding_auto, // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found
175 + encoding_utf8, // UTF8 encoding
176 + encoding_utf16_le, // Little-endian UTF16
177 + encoding_utf16_be, // Big-endian UTF16
178 + encoding_utf16, // UTF16 with native endianness
179 + encoding_utf32_le, // Little-endian UTF32
180 + encoding_utf32_be, // Big-endian UTF32
181 + encoding_utf32, // UTF32 with native endianness
182 + encoding_wchar, // The same encoding wchar_t has (either UTF16 or UTF32)
183 + encoding_latin1
184 + };
185 +
186 + // Formatting flags
187 +
188 + // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default.
189 + const unsigned int format_indent = 0x01;
190 +
191 + // Write encoding-specific BOM to the output stream. This flag is off by default.
192 + const unsigned int format_write_bom = 0x02;
193 +
194 + // Use raw output mode (no indentation and no line breaks are written). This flag is off by default.
195 + const unsigned int format_raw = 0x04;
196 +
197 + // Omit default XML declaration even if there is no declaration in the document. This flag is off by default.
198 + const unsigned int format_no_declaration = 0x08;
199 +
200 + // Don't escape attribute values and PCDATA contents. This flag is off by default.
201 + const unsigned int format_no_escapes = 0x10;
202 +
203 + // Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default.
204 + const unsigned int format_save_file_text = 0x20;
205 +
206 + // The default set of formatting flags.
207 + // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
208 + const unsigned int format_default = format_indent;
209 +
210 + // Forward declarations
211 + struct xml_attribute_struct;
212 + struct xml_node_struct;
213 +
214 + class xml_node_iterator;
215 + class xml_attribute_iterator;
216 + class xml_named_node_iterator;
217 +
218 + class xml_tree_walker;
219 +
220 + struct xml_parse_result;
221 +
222 + class xml_node;
223 +
224 + class xml_text;
225 +
226 + #ifndef PUGIXML_NO_XPATH
227 + class xpath_node;
228 + class xpath_node_set;
229 + class xpath_query;
230 + class xpath_variable_set;
231 + #endif
232 +
233 + // Range-based for loop support
234 + template <typename It> class xml_object_range
235 + {
236 + public:
237 + typedef It const_iterator;
238 + typedef It iterator;
239 +
240 + xml_object_range(It b, It e): _begin(b), _end(e)
241 + {
242 + }
243 +
244 + It begin() const { return _begin; }
245 + It end() const { return _end; }
246 +
247 + private:
248 + It _begin, _end;
249 + };
250 +
251 + // Writer interface for node printing (see xml_node::print)
252 + class PUGIXML_CLASS xml_writer
253 + {
254 + public:
255 + virtual ~xml_writer() {}
256 +
257 + // Write memory chunk into stream/file/whatever
258 + virtual void write(const void* data, size_t size) = 0;
259 + };
260 +
261 + // xml_writer implementation for FILE*
262 + class PUGIXML_CLASS xml_writer_file: public xml_writer
263 + {
264 + public:
265 + // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
266 + xml_writer_file(void* file);
267 +
268 + virtual void write(const void* data, size_t size);
269 +
270 + private:
271 + void* file;
272 + };
273 +
274 + #ifndef PUGIXML_NO_STL
275 + // xml_writer implementation for streams
276 + class PUGIXML_CLASS xml_writer_stream: public xml_writer
277 + {
278 + public:
279 + // Construct writer from an output stream object
280 + xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream);
281 + xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream);
282 +
283 + virtual void write(const void* data, size_t size);
284 +
285 + private:
286 + std::basic_ostream<char, std::char_traits<char> >* narrow_stream;
287 + std::basic_ostream<wchar_t, std::char_traits<wchar_t> >* wide_stream;
288 + };
289 + #endif
290 +
291 + // A light-weight handle for manipulating attributes in DOM tree
292 + class PUGIXML_CLASS xml_attribute
293 + {
294 + friend class xml_attribute_iterator;
295 + friend class xml_node;
296 +
297 + private:
298 + xml_attribute_struct* _attr;
299 +
300 + typedef void (*unspecified_bool_type)(xml_attribute***);
301 +
302 + public:
303 + // Default constructor. Constructs an empty attribute.
304 + xml_attribute();
305 +
306 + // Constructs attribute from internal pointer
307 + explicit xml_attribute(xml_attribute_struct* attr);
308 +
309 + // Safe bool conversion operator
310 + operator unspecified_bool_type() const;
311 +
312 + // Borland C++ workaround
313 + bool operator!() const;
314 +
315 + // Comparison operators (compares wrapped attribute pointers)
316 + bool operator==(const xml_attribute& r) const;
317 + bool operator!=(const xml_attribute& r) const;
318 + bool operator<(const xml_attribute& r) const;
319 + bool operator>(const xml_attribute& r) const;
320 + bool operator<=(const xml_attribute& r) const;
321 + bool operator>=(const xml_attribute& r) const;
322 +
323 + // Check if attribute is empty
324 + bool empty() const;
325 +
326 + // Get attribute name/value, or "" if attribute is empty
327 + const char_t* name() const;
328 + const char_t* value() const;
329 +
330 + // Get attribute value, or the default value if attribute is empty
331 + const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
332 +
333 + // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty
334 + int as_int(int def = 0) const;
335 + unsigned int as_uint(unsigned int def = 0) const;
336 + double as_double(double def = 0) const;
337 + float as_float(float def = 0) const;
338 +
339 + #ifdef PUGIXML_HAS_LONG_LONG
340 + long long as_llong(long long def = 0) const;
341 + unsigned long long as_ullong(unsigned long long def = 0) const;
342 + #endif
343 +
344 + // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty
345 + bool as_bool(bool def = false) const;
346 +
347 + // Set attribute name/value (returns false if attribute is empty or there is not enough memory)
348 + bool set_name(const char_t* rhs);
349 + bool set_value(const char_t* rhs);
350 +
351 + // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
352 + bool set_value(int rhs);
353 + bool set_value(unsigned int rhs);
354 + bool set_value(double rhs);
355 + bool set_value(bool rhs);
356 +
357 + #ifdef PUGIXML_HAS_LONG_LONG
358 + bool set_value(long long rhs);
359 + bool set_value(unsigned long long rhs);
360 + #endif
361 +
362 + // Set attribute value (equivalent to set_value without error checking)
363 + xml_attribute& operator=(const char_t* rhs);
364 + xml_attribute& operator=(int rhs);
365 + xml_attribute& operator=(unsigned int rhs);
366 + xml_attribute& operator=(double rhs);
367 + xml_attribute& operator=(bool rhs);
368 +
369 + #ifdef PUGIXML_HAS_LONG_LONG
370 + xml_attribute& operator=(long long rhs);
371 + xml_attribute& operator=(unsigned long long rhs);
372 + #endif
373 +
374 + // Get next/previous attribute in the attribute list of the parent node
375 + xml_attribute next_attribute() const;
376 + xml_attribute previous_attribute() const;
377 +
378 + // Get hash value (unique for handles to the same object)
379 + size_t hash_value() const;
380 +
381 + // Get internal pointer
382 + xml_attribute_struct* internal_object() const;
383 + };
384 +
385 +#ifdef __BORLANDC__
386 + // Borland C++ workaround
387 + bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs);
388 + bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs);
389 +#endif
390 +
391 + // A light-weight handle for manipulating nodes in DOM tree
392 + class PUGIXML_CLASS xml_node
393 + {
394 + friend class xml_attribute_iterator;
395 + friend class xml_node_iterator;
396 + friend class xml_named_node_iterator;
397 +
398 + protected:
399 + xml_node_struct* _root;
400 +
401 + typedef void (*unspecified_bool_type)(xml_node***);
402 +
403 + public:
404 + // Default constructor. Constructs an empty node.
405 + xml_node();
406 +
407 + // Constructs node from internal pointer
408 + explicit xml_node(xml_node_struct* p);
409 +
410 + // Safe bool conversion operator
411 + operator unspecified_bool_type() const;
412 +
413 + // Borland C++ workaround
414 + bool operator!() const;
415 +
416 + // Comparison operators (compares wrapped node pointers)
417 + bool operator==(const xml_node& r) const;
418 + bool operator!=(const xml_node& r) const;
419 + bool operator<(const xml_node& r) const;
420 + bool operator>(const xml_node& r) const;
421 + bool operator<=(const xml_node& r) const;
422 + bool operator>=(const xml_node& r) const;
423 +
424 + // Check if node is empty.
425 + bool empty() const;
426 +
427 + // Get node type
428 + xml_node_type type() const;
429 +
430 + // Get node name, or "" if node is empty or it has no name
431 + const char_t* name() const;
432 +
433 + // Get node value, or "" if node is empty or it has no value
434 + // Note: For <node>text</node> node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes.
435 + const char_t* value() const;
436 +
437 + // Get attribute list
438 + xml_attribute first_attribute() const;
439 + xml_attribute last_attribute() const;
440 +
441 + // Get children list
442 + xml_node first_child() const;
443 + xml_node last_child() const;
444 +
445 + // Get next/previous sibling in the children list of the parent node
446 + xml_node next_sibling() const;
447 + xml_node previous_sibling() const;
448 +
449 + // Get parent node
450 + xml_node parent() const;
451 +
452 + // Get root of DOM tree this node belongs to
453 + xml_node root() const;
454 +
455 + // Get text object for the current node
456 + xml_text text() const;
457 +
458 + // Get child, attribute or next/previous sibling with the specified name
459 + xml_node child(const char_t* name) const;
460 + xml_attribute attribute(const char_t* name) const;
461 + xml_node next_sibling(const char_t* name) const;
462 + xml_node previous_sibling(const char_t* name) const;
463 +
464 + // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA
465 + const char_t* child_value() const;
466 +
467 + // Get child value of child with specified name. Equivalent to child(name).child_value().
468 + const char_t* child_value(const char_t* name) const;
469 +
470 + // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
471 + bool set_name(const char_t* rhs);
472 + bool set_value(const char_t* rhs);
473 +
474 + // Add attribute with specified name. Returns added attribute, or empty attribute on errors.
475 + xml_attribute append_attribute(const char_t* name);
476 + xml_attribute prepend_attribute(const char_t* name);
477 + xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
478 + xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
479 +
480 + // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.
481 + xml_attribute append_copy(const xml_attribute& proto);
482 + xml_attribute prepend_copy(const xml_attribute& proto);
483 + xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
484 + xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);
485 +
486 + // Add child node with specified type. Returns added node, or empty node on errors.
487 + xml_node append_child(xml_node_type type = node_element);
488 + xml_node prepend_child(xml_node_type type = node_element);
489 + xml_node insert_child_after(xml_node_type type, const xml_node& node);
490 + xml_node insert_child_before(xml_node_type type, const xml_node& node);
491 +
492 + // Add child element with specified name. Returns added node, or empty node on errors.
493 + xml_node append_child(const char_t* name);
494 + xml_node prepend_child(const char_t* name);
495 + xml_node insert_child_after(const char_t* name, const xml_node& node);
496 + xml_node insert_child_before(const char_t* name, const xml_node& node);
497 +
498 + // Add a copy of the specified node as a child. Returns added node, or empty node on errors.
499 + xml_node append_copy(const xml_node& proto);
500 + xml_node prepend_copy(const xml_node& proto);
501 + xml_node insert_copy_after(const xml_node& proto, const xml_node& node);
502 + xml_node insert_copy_before(const xml_node& proto, const xml_node& node);
503 +
504 + // Move the specified node to become a child of this node. Returns moved node, or empty node on errors.
505 + xml_node append_move(const xml_node& moved);
506 + xml_node prepend_move(const xml_node& moved);
507 + xml_node insert_move_after(const xml_node& moved, const xml_node& node);
508 + xml_node insert_move_before(const xml_node& moved, const xml_node& node);
509 +
510 + // Remove specified attribute
511 + bool remove_attribute(const xml_attribute& a);
512 + bool remove_attribute(const char_t* name);
513 +
514 + // Remove specified child
515 + bool remove_child(const xml_node& n);
516 + bool remove_child(const char_t* name);
517 +
518 + // Parses buffer as an XML document fragment and appends all nodes as children of the current node.
519 + // Copies/converts the buffer, so it may be deleted or changed after the function returns.
520 + // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory.
521 + xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
522 +
523 + // Find attribute using predicate. Returns first attribute for which predicate returned true.
524 + template <typename Predicate> xml_attribute find_attribute(Predicate pred) const
525 + {
526 + if (!_root) return xml_attribute();
527 +
528 + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())
529 + if (pred(attrib))
530 + return attrib;
531 +
532 + return xml_attribute();
533 + }
534 +
535 + // Find child node using predicate. Returns first child for which predicate returned true.
536 + template <typename Predicate> xml_node find_child(Predicate pred) const
537 + {
538 + if (!_root) return xml_node();
539 +
540 + for (xml_node node = first_child(); node; node = node.next_sibling())
541 + if (pred(node))
542 + return node;
543 +
544 + return xml_node();
545 + }
546 +
547 + // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true.
548 + template <typename Predicate> xml_node find_node(Predicate pred) const
549 + {
550 + if (!_root) return xml_node();
551 +
552 + xml_node cur = first_child();
553 +
554 + while (cur._root && cur._root != _root)
555 + {
556 + if (pred(cur)) return cur;
557 +
558 + if (cur.first_child()) cur = cur.first_child();
559 + else if (cur.next_sibling()) cur = cur.next_sibling();
560 + else
561 + {
562 + while (!cur.next_sibling() && cur._root != _root) cur = cur.parent();
563 +
564 + if (cur._root != _root) cur = cur.next_sibling();
565 + }
566 + }
567 +
568 + return xml_node();
569 + }
570 +
571 + // Find child node by attribute name/value
572 + xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
573 + xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
574 +
575 + #ifndef PUGIXML_NO_STL
576 + // Get the absolute node path from root as a text string.
577 + string_t path(char_t delimiter = '/') const;
578 + #endif
579 +
580 + // Search for a node by path consisting of node names and . or .. elements.
581 + xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const;
582 +
583 + // Recursively traverse subtree with xml_tree_walker
584 + bool traverse(xml_tree_walker& walker);
585 +
586 + #ifndef PUGIXML_NO_XPATH
587 + // Select single node by evaluating XPath query. Returns first node from the resulting node set.
588 + xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const;
589 + xpath_node select_node(const xpath_query& query) const;
590 +
591 + // Select node set by evaluating XPath query
592 + xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
593 + xpath_node_set select_nodes(const xpath_query& query) const;
594 +
595 + // (deprecated: use select_node instead) Select single node by evaluating XPath query.
596 + xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
597 + xpath_node select_single_node(const xpath_query& query) const;
598 +
599 + #endif
600 +
601 + // Print subtree using a writer object
602 + void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
603 +
604 + #ifndef PUGIXML_NO_STL
605 + // Print subtree to stream
606 + void print(std::basic_ostream<char, std::char_traits<char> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
607 + void print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const;
608 + #endif
609 +
610 + // Child nodes iterators
611 + typedef xml_node_iterator iterator;
612 +
613 + iterator begin() const;
614 + iterator end() const;
615 +
616 + // Attribute iterators
617 + typedef xml_attribute_iterator attribute_iterator;
618 +
619 + attribute_iterator attributes_begin() const;
620 + attribute_iterator attributes_end() const;
621 +
622 + // Range-based for support
623 + xml_object_range<xml_node_iterator> children() const;
624 + xml_object_range<xml_named_node_iterator> children(const char_t* name) const;
625 + xml_object_range<xml_attribute_iterator> attributes() const;
626 +
627 + // Get node offset in parsed file/string (in char_t units) for debugging purposes
628 + ptrdiff_t offset_debug() const;
629 +
630 + // Get hash value (unique for handles to the same object)
631 + size_t hash_value() const;
632 +
633 + // Get internal pointer
634 + xml_node_struct* internal_object() const;
635 + };
636 +
637 +#ifdef __BORLANDC__
638 + // Borland C++ workaround
639 + bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs);
640 + bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs);
641 +#endif
642 +
643 + // A helper for working with text inside PCDATA nodes
644 + class PUGIXML_CLASS xml_text
645 + {
646 + friend class xml_node;
647 +
648 + xml_node_struct* _root;
649 +
650 + typedef void (*unspecified_bool_type)(xml_text***);
651 +
652 + explicit xml_text(xml_node_struct* root);
653 +
654 + xml_node_struct* _data_new();
655 + xml_node_struct* _data() const;
656 +
657 + public:
658 + // Default constructor. Constructs an empty object.
659 + xml_text();
660 +
661 + // Safe bool conversion operator
662 + operator unspecified_bool_type() const;
663 +
664 + // Borland C++ workaround
665 + bool operator!() const;
666 +
667 + // Check if text object is empty
668 + bool empty() const;
669 +
670 + // Get text, or "" if object is empty
671 + const char_t* get() const;
672 +
673 + // Get text, or the default value if object is empty
674 + const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
675 +
676 + // Get text as a number, or the default value if conversion did not succeed or object is empty
677 + int as_int(int def = 0) const;
678 + unsigned int as_uint(unsigned int def = 0) const;
679 + double as_double(double def = 0) const;
680 + float as_float(float def = 0) const;
681 +
682 + #ifdef PUGIXML_HAS_LONG_LONG
683 + long long as_llong(long long def = 0) const;
684 + unsigned long long as_ullong(unsigned long long def = 0) const;
685 + #endif
686 +
687 + // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty
688 + bool as_bool(bool def = false) const;
689 +
690 + // Set text (returns false if object is empty or there is not enough memory)
691 + bool set(const char_t* rhs);
692 +
693 + // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
694 + bool set(int rhs);
695 + bool set(unsigned int rhs);
696 + bool set(double rhs);
697 + bool set(bool rhs);
698 +
699 + #ifdef PUGIXML_HAS_LONG_LONG
700 + bool set(long long rhs);
701 + bool set(unsigned long long rhs);
702 + #endif
703 +
704 + // Set text (equivalent to set without error checking)
705 + xml_text& operator=(const char_t* rhs);
706 + xml_text& operator=(int rhs);
707 + xml_text& operator=(unsigned int rhs);
708 + xml_text& operator=(double rhs);
709 + xml_text& operator=(bool rhs);
710 +
711 + #ifdef PUGIXML_HAS_LONG_LONG
712 + xml_text& operator=(long long rhs);
713 + xml_text& operator=(unsigned long long rhs);
714 + #endif
715 +
716 + // Get the data node (node_pcdata or node_cdata) for this object
717 + xml_node data() const;
718 + };
719 +
720 +#ifdef __BORLANDC__
721 + // Borland C++ workaround
722 + bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs);
723 + bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs);
724 +#endif
725 +
726 + // Child node iterator (a bidirectional iterator over a collection of xml_node)
727 + class PUGIXML_CLASS xml_node_iterator
728 + {
729 + friend class xml_node;
730 +
731 + private:
732 + mutable xml_node _wrap;
733 + xml_node _parent;
734 +
735 + xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent);
736 +
737 + public:
738 + // Iterator traits
739 + typedef ptrdiff_t difference_type;
740 + typedef xml_node value_type;
741 + typedef xml_node* pointer;
742 + typedef xml_node& reference;
743 +
744 + #ifndef PUGIXML_NO_STL
745 + typedef std::bidirectional_iterator_tag iterator_category;
746 + #endif
747 +
748 + // Default constructor
749 + xml_node_iterator();
750 +
751 + // Construct an iterator which points to the specified node
752 + xml_node_iterator(const xml_node& node);
753 +
754 + // Iterator operators
755 + bool operator==(const xml_node_iterator& rhs) const;
756 + bool operator!=(const xml_node_iterator& rhs) const;
757 +
758 + xml_node& operator*() const;
759 + xml_node* operator->() const;
760 +
761 + const xml_node_iterator& operator++();
762 + xml_node_iterator operator++(int);
763 +
764 + const xml_node_iterator& operator--();
765 + xml_node_iterator operator--(int);
766 + };
767 +
768 + // Attribute iterator (a bidirectional iterator over a collection of xml_attribute)
769 + class PUGIXML_CLASS xml_attribute_iterator
770 + {
771 + friend class xml_node;
772 +
773 + private:
774 + mutable xml_attribute _wrap;
775 + xml_node _parent;
776 +
777 + xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent);
778 +
779 + public:
780 + // Iterator traits
781 + typedef ptrdiff_t difference_type;
782 + typedef xml_attribute value_type;
783 + typedef xml_attribute* pointer;
784 + typedef xml_attribute& reference;
785 +
786 + #ifndef PUGIXML_NO_STL
787 + typedef std::bidirectional_iterator_tag iterator_category;
788 + #endif
789 +
790 + // Default constructor
791 + xml_attribute_iterator();
792 +
793 + // Construct an iterator which points to the specified attribute
794 + xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent);
795 +
796 + // Iterator operators
797 + bool operator==(const xml_attribute_iterator& rhs) const;
798 + bool operator!=(const xml_attribute_iterator& rhs) const;
799 +
800 + xml_attribute& operator*() const;
801 + xml_attribute* operator->() const;
802 +
803 + const xml_attribute_iterator& operator++();
804 + xml_attribute_iterator operator++(int);
805 +
806 + const xml_attribute_iterator& operator--();
807 + xml_attribute_iterator operator--(int);
808 + };
809 +
810 + // Named node range helper
811 + class PUGIXML_CLASS xml_named_node_iterator
812 + {
813 + friend class xml_node;
814 +
815 + public:
816 + // Iterator traits
817 + typedef ptrdiff_t difference_type;
818 + typedef xml_node value_type;
819 + typedef xml_node* pointer;
820 + typedef xml_node& reference;
821 +
822 + #ifndef PUGIXML_NO_STL
823 + typedef std::bidirectional_iterator_tag iterator_category;
824 + #endif
825 +
826 + // Default constructor
827 + xml_named_node_iterator();
828 +
829 + // Construct an iterator which points to the specified node
830 + xml_named_node_iterator(const xml_node& node, const char_t* name);
831 +
832 + // Iterator operators
833 + bool operator==(const xml_named_node_iterator& rhs) const;
834 + bool operator!=(const xml_named_node_iterator& rhs) const;
835 +
836 + xml_node& operator*() const;
837 + xml_node* operator->() const;
838 +
839 + const xml_named_node_iterator& operator++();
840 + xml_named_node_iterator operator++(int);
841 +
842 + const xml_named_node_iterator& operator--();
843 + xml_named_node_iterator operator--(int);
844 +
845 + private:
846 + mutable xml_node _wrap;
847 + xml_node _parent;
848 + const char_t* _name;
849 +
850 + xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name);
851 + };
852 +
853 + // Abstract tree walker class (see xml_node::traverse)
854 + class PUGIXML_CLASS xml_tree_walker
855 + {
856 + friend class xml_node;
857 +
858 + private:
859 + int _depth;
860 +
861 + protected:
862 + // Get current traversal depth
863 + int depth() const;
864 +
865 + public:
866 + xml_tree_walker();
867 + virtual ~xml_tree_walker();
868 +
869 + // Callback that is called when traversal begins
870 + virtual bool begin(xml_node& node);
871 +
872 + // Callback that is called for each node traversed
873 + virtual bool for_each(xml_node& node) = 0;
874 +
875 + // Callback that is called when traversal ends
876 + virtual bool end(xml_node& node);
877 + };
878 +
879 + // Parsing status, returned as part of xml_parse_result object
880 + enum xml_parse_status
881 + {
882 + status_ok = 0, // No error
883 +
884 + status_file_not_found, // File was not found during load_file()
885 + status_io_error, // Error reading from file/stream
886 + status_out_of_memory, // Could not allocate memory
887 + status_internal_error, // Internal error occurred
888 +
889 + status_unrecognized_tag, // Parser could not determine tag type
890 +
891 + status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction
892 + status_bad_comment, // Parsing error occurred while parsing comment
893 + status_bad_cdata, // Parsing error occurred while parsing CDATA section
894 + status_bad_doctype, // Parsing error occurred while parsing document type declaration
895 + status_bad_pcdata, // Parsing error occurred while parsing PCDATA section
896 + status_bad_start_element, // Parsing error occurred while parsing start element tag
897 + status_bad_attribute, // Parsing error occurred while parsing element attribute
898 + status_bad_end_element, // Parsing error occurred while parsing end element tag
899 + status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
900 +
901 + status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer)
902 +
903 + status_no_document_element // Parsing resulted in a document without element nodes
904 + };
905 +
906 + // Parsing result
907 + struct PUGIXML_CLASS xml_parse_result
908 + {
909 + // Parsing status (see xml_parse_status)
910 + xml_parse_status status;
911 +
912 + // Last parsed offset (in char_t units from start of input data)
913 + ptrdiff_t offset;
914 +
915 + // Source document encoding
916 + xml_encoding encoding;
917 +
918 + // Default constructor, initializes object to failed state
919 + xml_parse_result();
920 +
921 + // Cast to bool operator
922 + operator bool() const;
923 +
924 + // Get error description
925 + const char* description() const;
926 + };
927 +
928 + // Document class (DOM tree root)
929 + class PUGIXML_CLASS xml_document: public xml_node
930 + {
931 + private:
932 + char_t* _buffer;
933 +
934 + char _memory[192];
935 +
936 + // Non-copyable semantics
937 + xml_document(const xml_document&);
938 + const xml_document& operator=(const xml_document&);
939 +
940 + void create();
941 + void destroy();
942 +
943 + public:
944 + // Default constructor, makes empty document
945 + xml_document();
946 +
947 + // Destructor, invalidates all node/attribute handles to this document
948 + ~xml_document();
949 +
950 + // Removes all nodes, leaving the empty document
951 + void reset();
952 +
953 + // Removes all nodes, then copies the entire contents of the specified document
954 + void reset(const xml_document& proto);
955 +
956 + #ifndef PUGIXML_NO_STL
957 + // Load document from stream.
958 + xml_parse_result load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
959 + xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default);
960 + #endif
961 +
962 + // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.
963 + xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
964 +
965 + // Load document from zero-terminated string. No encoding conversions are applied.
966 + xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);
967 +
968 + // Load document from file
969 + xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
970 + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
971 +
972 + // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns.
973 + xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
974 +
975 + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
976 + // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.
977 + xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
978 +
979 + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
980 + // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).
981 + xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
982 +
983 + // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details).
984 + void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
985 +
986 + #ifndef PUGIXML_NO_STL
987 + // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details).
988 + void save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
989 + void save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const;
990 + #endif
991 +
992 + // Save XML to file
993 + bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
994 + bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
995 +
996 + // Get document element
997 + xml_node document_element() const;
998 + };
999 +
1000 +#ifndef PUGIXML_NO_XPATH
1001 + // XPath query return type
1002 + enum xpath_value_type
1003 + {
1004 + xpath_type_none, // Unknown type (query failed to compile)
1005 + xpath_type_node_set, // Node set (xpath_node_set)
1006 + xpath_type_number, // Number
1007 + xpath_type_string, // String
1008 + xpath_type_boolean // Boolean
1009 + };
1010 +
1011 + // XPath parsing result
1012 + struct PUGIXML_CLASS xpath_parse_result
1013 + {
1014 + // Error message (0 if no error)
1015 + const char* error;
1016 +
1017 + // Last parsed offset (in char_t units from string start)
1018 + ptrdiff_t offset;
1019 +
1020 + // Default constructor, initializes object to failed state
1021 + xpath_parse_result();
1022 +
1023 + // Cast to bool operator
1024 + operator bool() const;
1025 +
1026 + // Get error description
1027 + const char* description() const;
1028 + };
1029 +
1030 + // A single XPath variable
1031 + class PUGIXML_CLASS xpath_variable
1032 + {
1033 + friend class xpath_variable_set;
1034 +
1035 + protected:
1036 + xpath_value_type _type;
1037 + xpath_variable* _next;
1038 +
1039 + xpath_variable();
1040 +
1041 + // Non-copyable semantics
1042 + xpath_variable(const xpath_variable&);
1043 + xpath_variable& operator=(const xpath_variable&);
1044 +
1045 + public:
1046 + // Get variable name
1047 + const char_t* name() const;
1048 +
1049 + // Get variable type
1050 + xpath_value_type type() const;
1051 +
1052 + // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error
1053 + bool get_boolean() const;
1054 + double get_number() const;
1055 + const char_t* get_string() const;
1056 + const xpath_node_set& get_node_set() const;
1057 +
1058 + // Set variable value; no type conversion is performed, false is returned on type mismatch error
1059 + bool set(bool value);
1060 + bool set(double value);
1061 + bool set(const char_t* value);
1062 + bool set(const xpath_node_set& value);
1063 + };
1064 +
1065 + // A set of XPath variables
1066 + class PUGIXML_CLASS xpath_variable_set
1067 + {
1068 + private:
1069 + xpath_variable* _data[64];
1070 +
1071 + // Non-copyable semantics
1072 + xpath_variable_set(const xpath_variable_set&);
1073 + xpath_variable_set& operator=(const xpath_variable_set&);
1074 +
1075 + xpath_variable* find(const char_t* name) const;
1076 +
1077 + public:
1078 + // Default constructor/destructor
1079 + xpath_variable_set();
1080 + ~xpath_variable_set();
1081 +
1082 + // Add a new variable or get the existing one, if the types match
1083 + xpath_variable* add(const char_t* name, xpath_value_type type);
1084 +
1085 + // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch
1086 + bool set(const char_t* name, bool value);
1087 + bool set(const char_t* name, double value);
1088 + bool set(const char_t* name, const char_t* value);
1089 + bool set(const char_t* name, const xpath_node_set& value);
1090 +
1091 + // Get existing variable by name
1092 + xpath_variable* get(const char_t* name);
1093 + const xpath_variable* get(const char_t* name) const;
1094 + };
1095 +
1096 + // A compiled XPath query object
1097 + class PUGIXML_CLASS xpath_query
1098 + {
1099 + private:
1100 + void* _impl;
1101 + xpath_parse_result _result;
1102 +
1103 + typedef void (*unspecified_bool_type)(xpath_query***);
1104 +
1105 + // Non-copyable semantics
1106 + xpath_query(const xpath_query&);
1107 + xpath_query& operator=(const xpath_query&);
1108 +
1109 + public:
1110 + // Construct a compiled object from XPath expression.
1111 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.
1112 + explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0);
1113 +
1114 + // Destructor
1115 + ~xpath_query();
1116 +
1117 + // Get query expression return type
1118 + xpath_value_type return_type() const;
1119 +
1120 + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary.
1121 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1122 + bool evaluate_boolean(const xpath_node& n) const;
1123 +
1124 + // Evaluate expression as double value in the specified context; performs type conversion if necessary.
1125 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1126 + double evaluate_number(const xpath_node& n) const;
1127 +
1128 + #ifndef PUGIXML_NO_STL
1129 + // Evaluate expression as string value in the specified context; performs type conversion if necessary.
1130 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1131 + string_t evaluate_string(const xpath_node& n) const;
1132 + #endif
1133 +
1134 + // Evaluate expression as string value in the specified context; performs type conversion if necessary.
1135 + // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).
1136 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1137 + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead.
1138 + size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
1139 +
1140 + // Evaluate expression as node set in the specified context.
1141 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
1142 + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
1143 + xpath_node_set evaluate_node_set(const xpath_node& n) const;
1144 +
1145 + // Evaluate expression as node set in the specified context.
1146 + // Return first node in document order, or empty node if node set is empty.
1147 + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
1148 + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead.
1149 + xpath_node evaluate_node(const xpath_node& n) const;
1150 +
1151 + // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)
1152 + const xpath_parse_result& result() const;
1153 +
1154 + // Safe bool conversion operator
1155 + operator unspecified_bool_type() const;
1156 +
1157 + // Borland C++ workaround
1158 + bool operator!() const;
1159 + };
1160 +
1161 + #ifndef PUGIXML_NO_EXCEPTIONS
1162 + // XPath exception class
1163 + class PUGIXML_CLASS xpath_exception: public std::exception
1164 + {
1165 + private:
1166 + xpath_parse_result _result;
1167 +
1168 + public:
1169 + // Construct exception from parse result
1170 + explicit xpath_exception(const xpath_parse_result& result);
1171 +
1172 + // Get error message
1173 + virtual const char* what() const throw();
1174 +
1175 + // Get parse result
1176 + const xpath_parse_result& result() const;
1177 + };
1178 + #endif
1179 +
1180 + // XPath node class (either xml_node or xml_attribute)
1181 + class PUGIXML_CLASS xpath_node
1182 + {
1183 + private:
1184 + xml_node _node;
1185 + xml_attribute _attribute;
1186 +
1187 + typedef void (*unspecified_bool_type)(xpath_node***);
1188 +
1189 + public:
1190 + // Default constructor; constructs empty XPath node
1191 + xpath_node();
1192 +
1193 + // Construct XPath node from XML node/attribute
1194 + xpath_node(const xml_node& node);
1195 + xpath_node(const xml_attribute& attribute, const xml_node& parent);
1196 +
1197 + // Get node/attribute, if any
1198 + xml_node node() const;
1199 + xml_attribute attribute() const;
1200 +
1201 + // Get parent of contained node/attribute
1202 + xml_node parent() const;
1203 +
1204 + // Safe bool conversion operator
1205 + operator unspecified_bool_type() const;
1206 +
1207 + // Borland C++ workaround
1208 + bool operator!() const;
1209 +
1210 + // Comparison operators
1211 + bool operator==(const xpath_node& n) const;
1212 + bool operator!=(const xpath_node& n) const;
1213 + };
1214 +
1215 +#ifdef __BORLANDC__
1216 + // Borland C++ workaround
1217 + bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs);
1218 + bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs);
1219 +#endif
1220 +
1221 + // A fixed-size collection of XPath nodes
1222 + class PUGIXML_CLASS xpath_node_set
1223 + {
1224 + public:
1225 + // Collection type
1226 + enum type_t
1227 + {
1228 + type_unsorted, // Not ordered
1229 + type_sorted, // Sorted by document order (ascending)
1230 + type_sorted_reverse // Sorted by document order (descending)
1231 + };
1232 +
1233 + // Constant iterator type
1234 + typedef const xpath_node* const_iterator;
1235 +
1236 + // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work
1237 + typedef const xpath_node* iterator;
1238 +
1239 + // Default constructor. Constructs empty set.
1240 + xpath_node_set();
1241 +
1242 + // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful
1243 + xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);
1244 +
1245 + // Destructor
1246 + ~xpath_node_set();
1247 +
1248 + // Copy constructor/assignment operator
1249 + xpath_node_set(const xpath_node_set& ns);
1250 + xpath_node_set& operator=(const xpath_node_set& ns);
1251 +
1252 + // Get collection type
1253 + type_t type() const;
1254 +
1255 + // Get collection size
1256 + size_t size() const;
1257 +
1258 + // Indexing operator
1259 + const xpath_node& operator[](size_t index) const;
1260 +
1261 + // Collection iterators
1262 + const_iterator begin() const;
1263 + const_iterator end() const;
1264 +
1265 + // Sort the collection in ascending/descending order by document order
1266 + void sort(bool reverse = false);
1267 +
1268 + // Get first node in the collection by document order
1269 + xpath_node first() const;
1270 +
1271 + // Check if collection is empty
1272 + bool empty() const;
1273 +
1274 + private:
1275 + type_t _type;
1276 +
1277 + xpath_node _storage;
1278 +
1279 + xpath_node* _begin;
1280 + xpath_node* _end;
1281 +
1282 + void _assign(const_iterator begin, const_iterator end);
1283 + };
1284 +#endif
1285 +
1286 +#ifndef PUGIXML_NO_STL
1287 + // Convert wide string to UTF8
1288 + std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str);
1289 + std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str);
1290 +
1291 + // Convert UTF8 to wide string
1292 + std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str);
1293 + std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >& str);
1294 +#endif
1295 +
1296 + // Memory allocation function interface; returns pointer to allocated memory or NULL on failure
1297 + typedef void* (*allocation_function)(size_t size);
1298 +
1299 + // Memory deallocation function interface
1300 + typedef void (*deallocation_function)(void* ptr);
1301 +
1302 + // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.
1303 + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
1304 +
1305 + // Get current memory management functions
1306 + allocation_function PUGIXML_FUNCTION get_memory_allocation_function();
1307 + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
1308 +}
1309 +
1310 +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
1311 +namespace std
1312 +{
1313 + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
1314 + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&);
1315 + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&);
1316 + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&);
1317 +}
1318 +#endif
1319 +
1320 +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
1321 +namespace std
1322 +{
1323 + // Workarounds for (non-standard) iterator category detection
1324 + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&);
1325 + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&);
1326 + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&);
1327 +}
1328 +#endif
1329 +
1330 +#endif
1331 +
1332 +/**
1333 + * Copyright (c) 2006-2014 Arseny Kapoulkine
1334 + *
1335 + * Permission is hereby granted, free of charge, to any person
1336 + * obtaining a copy of this software and associated documentation
1337 + * files (the "Software"), to deal in the Software without
1338 + * restriction, including without limitation the rights to use,
1339 + * copy, modify, merge, publish, distribute, sublicense, and/or sell
1340 + * copies of the Software, and to permit persons to whom the
1341 + * Software is furnished to do so, subject to the following
1342 + * conditions:
1343 + *
1344 + * The above copyright notice and this permission notice shall be
1345 + * included in all copies or substantial portions of the Software.
1346 + *
1347 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1348 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1349 + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1350 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1351 + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1352 + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1353 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1354 + * OTHER DEALINGS IN THE SOFTWARE.
1355 + */
1 +#ifndef IDC_STATIC
2 +#define IDC_STATIC (-1)
3 +#endif
4 +
5 +#define IDD_DIALOG2 102
6 +#define IDD_DIALOG4 104
7 +#define IDI_ICON1 110
8 +#define IDC_CHECK1 1000
9 +#define IDC_CHECK2 1001
10 +#define IDC_CHECK3 1002
11 +#define IDC_CHECK4 1003
12 +#define IDC_CHECK5 1004
13 +#define IDC_EDIT1 1011
14 +#define IDC_EDIT2 1012
15 +#define IDC_EDIT3 1013
16 +#define IDC_EDIT4 1014
17 +#define IDC_BUTTON1 1020
18 +#define IDC_BUTTON2 1021
19 +#define IDC_BUTTON3 1022
20 +#define IDC_BUTTON5 1024
21 +#define IDC_LIST1 1028
22 +#define IDC_BUTTON6 40000
23 +#define IDC_CHECK6 40001
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#include "utility.h"
19 +#include "ith/host/srv.h"
20 +#include "ith/host/hookman.h"
21 +#include "ith/common/types.h"
22 +#include "ith/common/const.h"
23 +
24 +extern HookManager* man; // main.cpp
25 +
26 +std::wstring GetDriveLetter(const std::wstring& devicePath);
27 +std::wstring GetWindowsPath(const std::wstring& fileObjectPath);
28 +PVOID GetAllocationBase(DWORD pid, LPCVOID);
29 +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase);
30 +std::wstring GetModuleFileNameAsString();
31 +std::wstring GetProcessPath(HANDLE hProc);
32 +
33 +void ConsoleOutput(LPCWSTR text)
34 +{
35 + man->AddConsoleOutput(text);
36 +}
37 +
38 +void ConsoleOutput(LPCSTR text)
39 +{
40 + int wc_length = MB_WC_count(text, -1);
41 + LPWSTR wc = new WCHAR[wc_length];
42 + MB_WC(text, wc, wc_length);
43 + man->AddConsoleOutput(wc);
44 + delete wc;
45 +}
46 +
47 +std::wstring GetProcessPath(DWORD pid)
48 +{
49 + UniqueHandle hProc(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid));
50 + if (hProc)
51 + return GetProcessPath(hProc.get());
52 + else
53 + return L"";
54 +}
55 +
56 +std::wstring GetProcessPath(HANDLE hProc)
57 +{
58 + wchar_t path[MAX_PATH];
59 + GetProcessImageFileName(hProc, path, MAX_PATH);
60 + return GetWindowsPath(path);
61 +}
62 +
63 +std::wstring GetWindowsPath(const std::wstring& path)
64 +{
65 + // path is in device form
66 + // \Device\HarddiskVolume2\Windows\System32\taskhost.exe
67 + auto pathOffset = path.find(L'\\', 1) + 1;
68 + pathOffset = path.find(L'\\', pathOffset);
69 + std::wstring devicePath = path.substr(0, pathOffset); // \Device\HarddiskVolume2
70 + std::wstring dosDrive = GetDriveLetter(devicePath); // C:
71 + if (dosDrive.empty())
72 + return L"";
73 + std::wstring dosPath = dosDrive; // C:
74 + dosPath += path.substr(pathOffset); // C:\Windows\System32\taskhost.exe
75 + return dosPath;
76 +}
77 +
78 +std::wstring GetDriveLetter(const std::wstring& devicePath)
79 +{
80 + for (wchar_t drive = L'A'; drive <= L'Z'; drive++)
81 + {
82 + wchar_t szDriveName[3] = { drive, L':', L'\0' };
83 + wchar_t szTarget[512];
84 + if (QueryDosDevice(szDriveName, szTarget, 512))
85 + if (devicePath.compare(szTarget) == 0)
86 + return szDriveName;
87 + }
88 + return L"";
89 +}
90 +
91 +std::wstring GetCode(const HookParam& hp, DWORD pid)
92 +{
93 + std::wstring code(L"/H");
94 + WCHAR c;
95 + if (hp.type & PRINT_DWORD)
96 + c = L'H';
97 + else if (hp.type & USING_UNICODE)
98 + {
99 + if (hp.type & USING_STRING)
100 + c = L'Q';
101 + else if (hp.type & STRING_LAST_CHAR)
102 + c = L'L';
103 + else
104 + c = L'W';
105 + }
106 + else
107 + {
108 + if (hp.type & USING_STRING)
109 + c = L'S';
110 + else if (hp.type & BIG_ENDIAN)
111 + c = L'A';
112 + else if (hp.type & STRING_LAST_CHAR)
113 + c = L'E';
114 + else
115 + c = L'B';
116 + }
117 + code += c;
118 + if (hp.type & NO_CONTEXT)
119 + code += L'N';
120 + if (hp.off >> 31)
121 + code += L"-" + ToHexString(-(hp.off + 4));
122 + else
123 + code += ToHexString(hp.off);
124 + if (hp.type & DATA_INDIRECT)
125 + {
126 + if (hp.ind >> 31)
127 + code += L"*-" + ToHexString(-hp.ind);
128 + else
129 + code += L"*" + ToHexString(hp.ind);
130 + }
131 + if (hp.type & USING_SPLIT)
132 + {
133 + if (hp.split >> 31)
134 + code += L":-" + ToHexString(-(4 + hp.split));
135 + else
136 + code += L":" + ToHexString(hp.split);
137 + }
138 + if (hp.type & SPLIT_INDIRECT)
139 + {
140 + if (hp.split_ind >> 31)
141 + code += L"*-" + ToHexString(-hp.split_ind);
142 + else
143 + code += L"*" + ToHexString(hp.split_ind);
144 + }
145 + if (pid)
146 + {
147 + PVOID allocationBase = GetAllocationBase(pid, (LPCVOID)hp.addr);
148 + if (allocationBase)
149 + {
150 + std::wstring path = GetModuleFileNameAsString(pid, allocationBase);
151 + if (!path.empty())
152 + {
153 + auto fileName = path.substr(path.rfind(L'\\') + 1);
154 + DWORD relativeHookAddress = hp.addr - (DWORD)allocationBase;
155 + code += L"@" + ToHexString(relativeHookAddress) + L":" + fileName;
156 + return code;
157 + }
158 + }
159 + }
160 + if (hp.module)
161 + {
162 + code += L"@" + ToHexString(hp.addr) + L"!" + ToHexString(hp.module);
163 + if (hp.function)
164 + code += L"!" + ToHexString(hp.function);
165 + }
166 + else
167 + {
168 + // hack, the original address is stored in the function field
169 + // if (module == NULL && function != NULL)
170 + // in TextHook::UnsafeInsertHookCode() MODULE_OFFSET and FUNCTION_OFFSET are removed from
171 + // HookParam.type
172 + if (hp.function)
173 + code += L"@" + ToHexString(hp.function);
174 + else
175 + code += L"@" + ToHexString(hp.addr) + L":";
176 + }
177 + return code;
178 +}
179 +
180 +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase)
181 +{
182 + const ProcessRecord* pr = man->GetProcessRecord(pid);
183 + if (pr)
184 + {
185 + HANDLE hProc = pr->process_handle;
186 + WCHAR path[MAX_PATH];
187 + if (GetModuleFileNameEx(hProc, (HMODULE)allocationBase, path, MAX_PATH))
188 + return path;
189 + }
190 + return L"";
191 +}
192 +
193 +PVOID GetAllocationBase(DWORD pid, LPCVOID addr)
194 +{
195 + const ProcessRecord *pr = man->GetProcessRecord(pid);
196 + if (pr)
197 + {
198 + MEMORY_BASIC_INFORMATION info;
199 + HANDLE hProc = pr->process_handle;
200 + if (VirtualQueryEx(hProc, addr, &info, sizeof(info)))
201 + {
202 + if (info.Type & MEM_IMAGE)
203 + return info.AllocationBase;
204 + }
205 + }
206 + return NULL;
207 +}
208 +
209 +struct TitleParam
210 +{
211 + DWORD pid, buffer_len, retn_len;
212 + std::wstring buffer;
213 +};
214 +
215 +BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
216 +{
217 + TitleParam* p = (TitleParam*)lParam;
218 + DWORD pid;
219 + GetWindowThreadProcessId(hwnd, &pid);
220 + if (pid == p->pid)
221 + {
222 + if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)
223 + {
224 + int len = GetWindowTextLength(hwnd);
225 + std::unique_ptr<wchar_t[]> result(new wchar_t[len + 1]);
226 + GetWindowText(hwnd, result.get(), len + 1);
227 + p->buffer = result.get();
228 + p->retn_len = p->buffer.size();
229 + if (!p->buffer.empty())
230 + return FALSE;
231 + }
232 + }
233 + return TRUE;
234 +}
235 +
236 +std::wstring GetProcessTitle(DWORD pid)
237 +{
238 + TitleParam p;
239 + p.pid = pid;
240 + p.buffer_len = 0;
241 + p.retn_len = 0;
242 + EnumWindows(EnumProc, (LPARAM)&p);
243 + return p.buffer;
244 +}
245 +
246 +WindowsError::WindowsError(DWORD error_code) : error_code(error_code), msg("")
247 +{
248 + CHAR str[512];
249 + std::sprintf(str, "error code 0x%8x", error_code);
250 + msg = str;
251 +}
252 +
253 +const char *WindowsError::what() const
254 +{
255 + return msg.c_str();
256 +}
257 +
258 +HANDLE IthCreateThread(LPVOID start_addr, DWORD param)
259 +{
260 + return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_addr, (LPVOID)param, 0, NULL);
261 +}
262 +
263 +std::wstring GetModuleFileNameAsString()
264 +{
265 + WCHAR path[MAX_PATH];
266 + GetModuleFileName(NULL, path, MAX_PATH);
267 + return path;
268 +}
269 +
270 +bool IthCreateDirectory(LPCWSTR name)
271 +{
272 + std::wstring path = GetModuleFileNameAsString();
273 + path = path.substr(0, path.rfind(L'\\') + 1) + name;
274 + BOOL error_code = CreateDirectory(path.c_str(), NULL);
275 + return error_code != 0 || GetLastError() == ERROR_ALREADY_EXISTS;
276 +}
277 +
278 +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition)
279 +{
280 + std::wstring path = GetModuleFileNameAsString();
281 + path = path.substr(0, path.rfind(L'\\') + 1) + name;
282 + return CreateFile(path.c_str(), option, share, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
283 +}
284 +
285 +//SJIS->Unicode. 'mb' must be null-terminated. 'wc_length' is the length of 'wc' in characters.
286 +int MB_WC(const char* mb, wchar_t* wc, int wc_length)
287 +{
288 + return MultiByteToWideChar(932, 0, mb, -1, wc, wc_length);
289 +}
290 +
291 +// Count characters in wide string. 'mb_length' is the number of bytes from 'mb' to convert or
292 +// -1 if the string is null terminated.
293 +int MB_WC_count(const char* mb, int mb_length)
294 +{
295 + return MultiByteToWideChar(932, 0, mb, mb_length, NULL, 0);
296 +}
297 +
298 +// Unicode->SJIS. Analogous to MB_WC.
299 +int WC_MB(const wchar_t *wc, char* mb, int mb_length)
300 +{
301 + return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL);
302 +}
303 +
304 +DWORD Hash(const std::wstring& module, int length)
305 +{
306 + DWORD hash = 0;
307 + auto end = length < 0 || static_cast<std::size_t>(length) > module.length() ? module.end() : module.begin() + length;
308 + for (auto it = module.begin(); it != end; ++it)
309 + hash = _rotr(hash, 7) + *it;
310 + return hash;
311 +}
1 +#pragma once
2 +#include "ITH.h"
3 +
4 +struct HookParam;
5 +struct ProcessRecord;
6 +
7 +DWORD Hash(const std::wstring& module, int length = -1);
8 +DWORD ProcessCommand(const std::wstring& cmd, DWORD pid);
9 +std::wstring GetProcessPath(DWORD pid);
10 +void ConsoleOutput(LPCWSTR);
11 +void ConsoleOutput(LPCSTR text);
12 +std::wstring GetProcessTitle(DWORD pid);
13 +std::wstring GetCode(const HookParam& hp, DWORD pid = 0);
14 +
15 +// http://codesequoia.wordpress.com/2012/08/26/stdunique_ptr-for-windows-handles/
16 +struct HandleDeleter
17 +{
18 + typedef HANDLE pointer;
19 + void operator() (HANDLE h)
20 + {
21 + if (h != INVALID_HANDLE_VALUE) {
22 + CloseHandle(h);
23 + }
24 + }
25 +};
26 +
27 +typedef std::unique_ptr<HANDLE, HandleDeleter> UniqueHandle;
28 +
29 +class FileWriter : public pugi::xml_writer
30 +{
31 + HANDLE hFile;
32 +public:
33 + FileWriter(HANDLE hFile) : hFile(hFile) {};
34 + ~FileWriter() {};
35 +
36 + virtual void write(const void* data, size_t size)
37 + {
38 + DWORD dwNumberOfBytesWritten;
39 + WriteFile(hFile, data, size, &dwNumberOfBytesWritten, NULL);
40 + }
41 +};
42 +
43 +class WindowsError : public std::exception
44 +{
45 +private:
46 + std::string msg;
47 + DWORD error_code;
48 +public:
49 + WindowsError(DWORD error_code);
50 + virtual const char *what() const;
51 +};
52 +
53 +HANDLE IthCreateThread(LPVOID start_addr, DWORD param);
54 +bool IthCreateDirectory(LPCWSTR name);
55 +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition);
56 +int MB_WC(const char* mb, wchar_t* wc, int wc_length);
57 +int MB_WC_count(const char* mb, int mb_length);
58 +int WC_MB(const wchar_t *wc, char* mb, int mb_length);
59 +bool Parse(const std::wstring& cmd, HookParam& hp);
60 +
61 +template <typename T>
62 +std::wstring ToHexString(T i) {
63 + std::wstringstream ss;
64 + ss << std::uppercase << std::hex << i;
65 + return ss.str();
66 +}
67 +
68 +// http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html
69 +class CriticalSection
70 +{
71 +public:
72 + CriticalSection()
73 + {
74 + ::InitializeCriticalSection(&m_rep);
75 + }
76 + ~CriticalSection()
77 + {
78 + ::DeleteCriticalSection(&m_rep);
79 + }
80 + void Enter()
81 + {
82 + ::EnterCriticalSection(&m_rep);
83 + }
84 + void Leave()
85 + {
86 + ::LeaveCriticalSection(&m_rep);
87 + }
88 +private:
89 + CriticalSection(const CriticalSection&);
90 + CriticalSection& operator=(const CriticalSection&);
91 +
92 + CRITICAL_SECTION m_rep;
93 +};
94 +
95 +class CSLock
96 +{
97 +public:
98 + CSLock(CriticalSection& a_section)
99 + : m_section(a_section)
100 + {
101 + m_section.Enter();
102 + }
103 + ~CSLock()
104 + {
105 + m_section.Leave();
106 + }
107 +private:
108 + CSLock(const CSLock&);
109 + CSLock& operator=(const CSLock&);
110 +
111 + CriticalSection& m_section;
112 +};
1 +const wchar_t* build_date=L"27.01.2013";
2 +const WCHAR program_version[] = L"@CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@";
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +#include "window.h"
18 +#include "ProcessWindow.h"
19 +#include "resource.h"
20 +#include "language.h"
21 +#include "ith/host/srv.h"
22 +#include "ith/host/hookman.h"
23 +#include "ith/common/const.h"
24 +#include "version.h"
25 +#include "ProfileManager.h"
26 +#include "ith/host/SettingManager.h"
27 +#include "CustomFilter.h"
28 +#include "Profile.h"
29 +#include "TextBuffer.h"
30 +
31 +#define CMD_SIZE 512
32 +
33 +static WNDPROC proc, proccmd, procChar;
34 +static WCHAR last_cmd[CMD_SIZE];
35 +extern HINSTANCE hIns; // main.cpp
36 +
37 +HWND hMainWnd, hwndCombo, hwndProcessComboBox, hwndEdit, hwndCmd;
38 +HWND hwndProcess;
39 +HWND hwndOption, hwndTop, hwndClear, hwndSave, hwndRemoveLink, hwndRemoveHook;
40 +HWND hProcDlg, hOptionDlg;
41 +HBRUSH hWhiteBrush;
42 +DWORD background;
43 +ProcessWindow* pswnd;
44 +TextBuffer* texts;
45 +extern ProfileManager* pfman; // ProfileManager.cpp
46 +extern HookManager* man; // main.cpp
47 +extern CustomFilter* mb_filter; // main.cpp
48 +extern CustomFilter* uni_filter; // main.cpp
49 +extern SettingManager* setman; // main.cpp
50 +#define COMMENT_BUFFER_LENGTH 512
51 +static WCHAR comment_buffer[COMMENT_BUFFER_LENGTH];
52 +
53 +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
54 +void SaveSettings(); // main.cpp
55 +extern LONG split_time, process_time, inject_delay, insert_delay,
56 + auto_inject, auto_insert, clipboard_flag, cyclic_remove, global_filter; //main.cpp
57 +static int last_select, last_edit;
58 +void AddLinksToHookManager(const Profile& pf, size_t thread_profile_index, const TextThread& thread);
59 +
60 +ATOM MyRegisterClass(HINSTANCE hInstance)
61 +{
62 + WNDCLASSEX wcex;
63 + wcex.cbSize = sizeof(WNDCLASSEX);
64 + wcex.style = CS_HREDRAW | CS_VREDRAW;
65 + wcex.lpfnWndProc = WndProc;
66 + wcex.cbClsExtra = 0;
67 + wcex.cbWndExtra = 0;
68 + wcex.hInstance = hInstance;
69 + wcex.hIcon = NULL;
70 + wcex.hCursor = NULL;
71 + wcex.hbrBackground = GetStockBrush(WHITE_BRUSH);
72 + wcex.lpszMenuName = NULL;
73 + wcex.lpszClassName = ClassName;
74 + wcex.hIconSm = LoadIcon(hInstance, (LPWSTR)IDI_ICON1);
75 + return RegisterClassEx(&wcex);
76 +}
77 +
78 +BOOL InitInstance(HINSTANCE hInstance, DWORD nAdmin, RECT* rc)
79 +{
80 + hIns = hInstance;
81 + LPCWSTR name = (nAdmin) ? ClassNameAdmin : ClassName;
82 + hMainWnd = CreateWindow(ClassName, name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
83 + rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, NULL, NULL, hInstance, 0);
84 + if (!hMainWnd)
85 + return FALSE;
86 + ShowWindow(hMainWnd, SW_SHOWNORMAL);
87 + UpdateWindow(hMainWnd);
88 + return TRUE;
89 +}
90 +
91 +DWORD SaveProcessProfile(DWORD pid); // ProfileManager.cpp
92 +
93 +BOOL CALLBACK OptionDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
94 +{
95 + switch (uMsg)
96 + {
97 + case WM_INITDIALOG:
98 + {
99 + SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), std::to_wstring((long long)split_time).c_str());
100 + SetWindowText(GetDlgItem(hDlg, IDC_EDIT2), std::to_wstring((long long)process_time).c_str());
101 + SetWindowText(GetDlgItem(hDlg, IDC_EDIT3), std::to_wstring((long long)inject_delay).c_str());
102 + SetWindowText(GetDlgItem(hDlg, IDC_EDIT4), std::to_wstring((long long)insert_delay).c_str());
103 + CheckDlgButton(hDlg, IDC_CHECK1, auto_inject);
104 + CheckDlgButton(hDlg, IDC_CHECK2, auto_insert);
105 + CheckDlgButton(hDlg, IDC_CHECK3, clipboard_flag);
106 + CheckDlgButton(hDlg, IDC_CHECK4, cyclic_remove);
107 + CheckDlgButton(hDlg, IDC_CHECK5, global_filter);
108 + }
109 + return TRUE;
110 + case WM_COMMAND:
111 + {
112 + DWORD wmId = LOWORD(wParam);
113 + DWORD wmEvent = HIWORD(wParam);
114 + switch (wmId)
115 + {
116 + case IDOK:
117 + {
118 + WCHAR str[128];
119 + GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), str, 0x80);
120 + DWORD st = std::stoul(str);
121 + split_time = st > 100 ? st : 100;
122 + GetWindowText(GetDlgItem(hDlg, IDC_EDIT2), str, 0x80);
123 + DWORD pt = std::stoul(str);
124 + process_time = pt > 50 ? pt : 50;
125 + GetWindowText(GetDlgItem(hDlg, IDC_EDIT3), str, 0x80);
126 + DWORD jd = std::stoul(str);
127 + inject_delay = jd > 1000 ? jd : 1000;
128 + GetWindowText(GetDlgItem(hDlg, IDC_EDIT4), str, 0x80);
129 + DWORD sd = std::stoul(str);
130 + insert_delay = sd > 200 ? sd : 200;
131 + if (IsDlgButtonChecked(hDlg, IDC_CHECK6))
132 + {
133 + man->ResetRepeatStatus();
134 + }
135 + auto_inject = IsDlgButtonChecked(hDlg, IDC_CHECK1);
136 + auto_insert = IsDlgButtonChecked(hDlg, IDC_CHECK2);
137 + clipboard_flag = IsDlgButtonChecked(hDlg, IDC_CHECK3);
138 + cyclic_remove = IsDlgButtonChecked(hDlg, IDC_CHECK4);
139 + global_filter = IsDlgButtonChecked(hDlg, IDC_CHECK5);
140 + setman->SetValue(SETTING_CLIPFLAG, clipboard_flag);
141 + setman->SetValue(SETTING_SPLIT_TIME, split_time);
142 + if (auto_inject == 0) auto_insert = 0;
143 + }
144 + case IDCANCEL:
145 + EndDialog(hDlg, 0);
146 + hOptionDlg = NULL;
147 + break;
148 + }
149 + return TRUE;
150 + }
151 + default:
152 + return FALSE;
153 + }
154 + return FALSE;
155 +}
156 +
157 +BOOL CALLBACK ProcessDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
158 +{
159 + switch (uMsg)
160 + {
161 + case WM_INITDIALOG:
162 + {
163 + pswnd = new ProcessWindow(hDlg);
164 + return TRUE;
165 + }
166 + case WM_COMMAND:
167 + {
168 + DWORD wmId, wmEvent;
169 + wmId = LOWORD(wParam);
170 + wmEvent = HIWORD(wParam);
171 + switch (wmId)
172 + {
173 + case WM_DESTROY:
174 + case IDOK:
175 + EndDialog(hDlg, NULL);
176 + hProcDlg = NULL;
177 + delete pswnd;
178 + pswnd = NULL;
179 + break;
180 + case IDC_BUTTON1:
181 + pswnd->RefreshProcess();
182 + break;
183 + case IDC_BUTTON2:
184 + pswnd->AttachProcess();
185 + break;
186 + case IDC_BUTTON3:
187 + pswnd->DetachProcess();
188 + break;
189 + case IDC_BUTTON5:
190 + pswnd->AddCurrentToProfile();
191 + break;
192 + case IDC_BUTTON6:
193 + pswnd->RemoveCurrentFromProfile();
194 + break;
195 + }
196 + }
197 + return TRUE;
198 +
199 + case WM_NOTIFY:
200 + {
201 + LPNMHDR dr = (LPNMHDR)lParam;
202 + switch (dr->code)
203 + {
204 + case LVN_ITEMCHANGED:
205 + if (dr->idFrom == IDC_LIST1)
206 + {
207 + NMLISTVIEW *nmlv = (LPNMLISTVIEW)lParam;
208 + if (nmlv->uNewState & LVIS_SELECTED)
209 + pswnd->RefreshThread(nmlv->iItem);
210 + }
211 + break;
212 + }
213 + }
214 + return TRUE;
215 + default:
216 + return FALSE;
217 + }
218 +}
219 +
220 +LRESULT CALLBACK EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
221 +{
222 +
223 + switch (message)
224 + {
225 + case WM_CHAR: //Filter user input.
226 + if (GetKeyState(VK_CONTROL) & 0x8000)
227 + {
228 + if (wParam == 1)
229 + {
230 + Edit_SetSel(hwndEdit, 0, -1);
231 + SendMessage(hwndEdit, WM_COPY, 0, 0);
232 + }
233 + }
234 + return 0;
235 + case WM_LBUTTONUP:
236 + if (hwndEdit)
237 + SendMessage(hwndEdit, WM_COPY, 0, 0);
238 + default:
239 + {
240 + return proc(hWnd, message, wParam, lParam);
241 + }
242 +
243 + }
244 +}
245 +
246 +LRESULT CALLBACK EditCmdProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
247 +{
248 + switch (message)
249 + {
250 + case WM_KEYDOWN:
251 + if (wParam == VK_UP)
252 + {
253 + SetWindowText(hWnd, last_cmd);
254 + SetFocus(hWnd);
255 + return 0;
256 + }
257 + break;
258 + case WM_CHAR:
259 + if (wParam == VK_RETURN)
260 + {
261 + DWORD s = 0, pid = 0;
262 + WCHAR str[32];
263 + if (GetWindowTextLength(hWnd) == 0)
264 + break;
265 + GetWindowText(hWnd, last_cmd, CMD_SIZE);
266 + //IthBreak();
267 + if (GetWindowText(hwndProcessComboBox, str, 32))
268 + pid = std::stoul(str);
269 + ProcessCommand(last_cmd, pid);
270 + Edit_SetSel(hWnd, 0, -1);
271 + Edit_ReplaceSel(hWnd, &s);
272 + SetFocus(hWnd);
273 + return 0;
274 + }
275 + default:
276 + break;
277 + }
278 + return CallWindowProc(proccmd, hWnd, message, wParam, lParam);
279 +}
280 +
281 +void CreateButtons(HWND hWnd)
282 +{
283 + hwndProcess = CreateWindow(L"Button", L"Process", WS_CHILD | WS_VISIBLE,
284 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
285 + hwndOption = CreateWindow(L"Button", L"Option", WS_CHILD | WS_VISIBLE,
286 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
287 + hwndClear = CreateWindow(L"Button", L"Clear", WS_CHILD | WS_VISIBLE,
288 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
289 + hwndSave = CreateWindow(L"Button", L"Save", WS_CHILD | WS_VISIBLE,
290 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
291 + hwndRemoveLink = CreateWindow(L"Button", L"Unlink", WS_CHILD | WS_VISIBLE,
292 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
293 + hwndRemoveHook = CreateWindow(L"Button", L"Unhook", WS_CHILD | WS_VISIBLE,
294 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
295 + hwndTop = CreateWindow(L"Button", L"Top", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE | BS_CHECKBOX,
296 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
297 + hwndProcessComboBox = CreateWindow(L"ComboBox", NULL,
298 + WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
299 + CBS_SORT | WS_VSCROLL | WS_TABSTOP,
300 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
301 + hwndCmd = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL,
302 + WS_CHILD | WS_VISIBLE | ES_NOHIDESEL| ES_LEFT | ES_AUTOHSCROLL,
303 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
304 + hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL,
305 + WS_CHILD | WS_VISIBLE | ES_NOHIDESEL| WS_VSCROLL |
306 + ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
307 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
308 +}
309 +
310 +void ClickButton(HWND hWnd, HWND h)
311 +{
312 + if (h == hwndProcess)
313 + {
314 + if (hProcDlg)
315 + SetForegroundWindow(hProcDlg);
316 + else
317 + hProcDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG2, 0, ProcessDlgProc);
318 + }
319 + else if (h == hwndOption)
320 + {
321 + if (hOptionDlg)
322 + SetForegroundWindow(hOptionDlg);
323 + else
324 + hOptionDlg = CreateDialog(hIns, (LPWSTR)IDD_DIALOG4, 0, OptionDlgProc);
325 + }
326 + else if (h == hwndClear)
327 + {
328 + WCHAR pwcEntry[128] = {};
329 + DWORD dwId = ComboBox_GetCurSel(hwndCombo);
330 + int len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry);
331 + dwId = std::stoul(pwcEntry, NULL, 16);
332 + if (dwId == 0)
333 + man->ClearCurrent();
334 + else
335 + man->RemoveSingleThread(dwId);
336 + }
337 + else if (h == hwndTop)
338 + {
339 + if (Button_GetCheck(h)==BST_CHECKED)
340 + {
341 + Button_SetCheck(h, BST_UNCHECKED);
342 + SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
343 + if (hProcDlg)
344 + SetWindowPos(hProcDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
345 + if (hOptionDlg)
346 + SetWindowPos(hOptionDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
347 + }
348 + else
349 + {
350 + Button_SetCheck(h, BST_CHECKED);
351 + SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
352 + if (hProcDlg)
353 + SetWindowPos(hProcDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
354 + if (hOptionDlg)
355 + SetWindowPos(hOptionDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
356 + }
357 + }
358 + else if (h == hwndSave)
359 + {
360 + WCHAR str[32];
361 + if (GetWindowText(hwndProcessComboBox, str, 32))
362 + {
363 + DWORD pid = std::stoul(str);
364 + SaveProcessProfile(pid);
365 + }
366 + pfman->SaveProfile();
367 + }
368 + else if (h == hwndRemoveLink)
369 + {
370 + WCHAR str[32];
371 + if (GetWindowText(hwndCombo, str, 32))
372 + {
373 + DWORD from = std::stoul(str, NULL, 16);
374 + if (from != 0)
375 + IHF_UnLink(from);
376 + }
377 + }
378 + else if (h == hwndRemoveHook)
379 + {
380 + WCHAR str[32];
381 + if (GetWindowText(hwndCombo, str, 32))
382 + {
383 + std::wstring entry(str);
384 + std::size_t i;
385 + DWORD threadNumber = std::stoul(entry, &i, 16);
386 + entry = entry.substr(i + 1);
387 + DWORD pid = std::stoul(entry, &i);
388 + entry = entry.substr(i + 1);
389 + DWORD addr = std::stoul(entry, NULL, 16);
390 + if (threadNumber != 0)
391 + IHF_RemoveHook(pid, addr);
392 + }
393 + }
394 +}
395 +
396 +DWORD ThreadFilter(TextThread* thread, BYTE* out,DWORD len, DWORD new_line, PVOID data, bool space)
397 +{
398 + DWORD status = thread->Status();
399 + if (global_filter && !new_line && thread->Number() != 0)
400 + {
401 + if (status & USING_UNICODE)
402 + {
403 + DWORD i, j;
404 + len /= 2;
405 + LPWSTR str = (LPWSTR)out;
406 + for (i = 0, j = 0; i < len; i++)
407 + {
408 + WCHAR c = str[i];
409 + if (!uni_filter->Find(c))
410 + str[j++] = c;
411 + }
412 + memset(str + j, 0, (len - j) * 2);
413 + len = j * 2;
414 + }
415 + else
416 + {
417 + DWORD i, j;
418 + for (i = 0, j = 0; i < len; i++)
419 + {
420 + WORD c = out[i];
421 + if (!IsDBCSLeadByte(c & 0xFF))
422 + {
423 + if (!mb_filter->Find(c))
424 + out[j++] = c & 0xFF;
425 + }
426 + else if (i + 1 < len)
427 + {
428 +
429 + c = out[i + 1];
430 + c <<= 8;
431 + c |= out[i];
432 + if (!mb_filter->Find(c))
433 + {
434 + out[j++] = c & 0xFF;
435 + out[j++] = c >> 8;
436 + }
437 + i++;
438 + }
439 + }
440 + memset(out + j, 0, len - j);
441 + len = j;
442 + }
443 + }
444 + return len;
445 +}
446 +
447 +DWORD ThreadOutput(TextThread* thread, BYTE* out,DWORD len, DWORD new_line, PVOID data, bool space)
448 +{
449 + if (len == 0)
450 + return len;
451 + DWORD status = thread->Status();
452 + if (status & CURRENT_SELECT)
453 + {
454 + if (new_line)
455 + {
456 + if (thread->Number() == 0)
457 + texts->AddText(L"\r\n", 2, true);
458 + else
459 + texts->AddText(L"\r\n\r\n", 4, true);
460 + }
461 + else if (status & USING_UNICODE)
462 + {
463 + texts->AddText((LPWSTR)out, len / 2, false);
464 + }
465 + else
466 + {
467 + int uni_len = MB_WC_count((char*)out, len);
468 + LPWSTR str = new WCHAR[uni_len + 1];
469 + MB_WC((char*)out, str, uni_len + 1);
470 + str[uni_len] = L'\0';
471 + texts->AddText(str, uni_len, false);
472 + delete str;
473 + }
474 + }
475 + return len;
476 +}
477 +
478 +bool GetHookParam(DWORD pid, DWORD hook_addr, HookParam& hp)
479 +{
480 + if (!pid)
481 + return false;
482 + ProcessRecord *pr = ::man->GetProcessRecord(pid);
483 + if (!pr)
484 + return false;
485 + bool result = false;
486 + WaitForSingleObject(pr->hookman_mutex, 0);
487 + const Hook *hks = (Hook *)pr->hookman_map;
488 + for (int i = 0; i < MAX_HOOK; i++)
489 + {
490 + if (hks[i].Address() == hook_addr)
491 + {
492 + hp = hks[i].hp;
493 + result = true;
494 + break;
495 + }
496 + }
497 + ReleaseMutex(pr->hookman_mutex);
498 + return result;
499 +}
500 +
501 +void AddToCombo(TextThread& thread, bool replace)
502 +{
503 + WCHAR entry[512];
504 + thread.GetEntryString(entry, 512);
505 + std::wstring entryWithLink(entry);
506 + if (thread.Link())
507 + entryWithLink += L"->" + ToHexString(thread.LinkNumber());
508 + if (thread.PID() == 0)
509 + entryWithLink += L"ConsoleOutput";
510 + HookParam hp = {};
511 + if (GetHookParam(thread.PID(), thread.Addr(), hp))
512 + entryWithLink += L" (" + GetCode(hp, thread.PID()) + L")";
513 + int i = ComboBox_FindString(hwndCombo, 0, entry);
514 + if (replace)
515 + {
516 + int sel = ComboBox_GetCurSel(hwndCombo);
517 + if (i != CB_ERR)
518 + ComboBox_DeleteString(hwndCombo, i);
519 + ComboBox_AddString(hwndCombo, entryWithLink.c_str());
520 + ComboBox_SetCurSel(hwndCombo, sel);
521 + }
522 + else
523 + {
524 + if (i == CB_ERR)
525 + ComboBox_AddString(hwndCombo, entryWithLink.c_str());
526 + // Why set current selection to 0 when the new thread is selected?
527 + if (thread.Status() & CURRENT_SELECT)
528 + ComboBox_SetCurSel(hwndCombo, 0);
529 + }
530 +}
531 +
532 +void RemoveFromCombo(TextThread* thread)
533 +{
534 + WCHAR entry[512];
535 + thread->GetEntryString(entry, 512);
536 + if (thread->PID() == 0)
537 + std::wcscat(entry, L"ConsoleOutput");
538 + int i = ComboBox_FindString(hwndCombo, 0, entry);
539 + if (i != CB_ERR)
540 + {
541 + if (ComboBox_DeleteString(hwndCombo, i) == CB_ERR)
542 + ConsoleOutput(ErrorDeleteCombo);
543 + }
544 +}
545 +
546 +void ComboSelectCurrent(TextThread* thread)
547 +{
548 + ComboBox_SetCurSel(hwndCombo, thread->Number());
549 +}
550 +
551 +DWORD SetEditText(LPWSTR wc)
552 +{
553 + DWORD line;
554 + Edit_SetText(hwndEdit, wc);
555 + line = Edit_GetLineCount(hwndEdit);
556 + SendMessage(hwndEdit, EM_LINESCROLL, 0, line);
557 + return 0;
558 +}
559 +
560 +DWORD ThreadReset(TextThread* thread)
561 +{
562 + texts->ClearBuffer();
563 + man->SetCurrent(thread);
564 + thread->LockVector();
565 + DWORD uni = thread->Status() & USING_UNICODE;
566 + if (uni)
567 + {
568 + DWORD len = 0;
569 + LPWSTR wc = (LPWSTR)thread->GetStore(&len);
570 + len /= 2;
571 + wc[len] = L'\0';
572 + SetEditText(wc);
573 + }
574 + else
575 + {
576 + DWORD len = MB_WC_count((char*)thread->Storage(), thread->Used());
577 + LPWSTR wc = new WCHAR[len + 1];
578 + MB_WC((char*)thread->Storage(), wc, len + 1);
579 + wc[len] = L'\0';
580 + SetEditText(wc);
581 + delete wc;
582 + }
583 + WCHAR buffer[16];
584 + std::swprintf(buffer, L"%04X", thread->Number());
585 + DWORD tmp = ComboBox_FindString(hwndCombo, 0, buffer);
586 + if (tmp != CB_ERR)
587 + ComboBox_SetCurSel(hwndCombo, tmp);
588 + thread->UnlockVector();
589 + return 0;
590 +}
591 +
592 +DWORD AddRemoveLink(TextThread* thread)
593 +{
594 + AddToCombo(*thread, true);
595 + return 0;
596 +}
597 +
598 +bool IsUnicodeHook(const ProcessRecord& pr, DWORD hook)
599 +{
600 + bool res = false;
601 + WaitForSingleObject(pr.hookman_mutex, 0);
602 + auto hooks = (const Hook*)pr.hookman_map;
603 + for (DWORD i = 0; i < MAX_HOOK; i++)
604 + {
605 + if (hooks[i].Address() == hook)
606 + {
607 + res = hooks[i].Type() & USING_UNICODE;
608 + break;
609 + }
610 + }
611 + ReleaseMutex(pr.hookman_mutex);
612 + return res;
613 +}
614 +
615 +DWORD ThreadCreate(TextThread* thread)
616 +{
617 + thread->RegisterOutputCallBack(ThreadOutput, 0);
618 + thread->RegisterFilterCallBack(ThreadFilter, 0);
619 + AddToCombo(*thread, false);
620 + const auto tp = thread->GetThreadParameter();
621 + auto pr = man->GetProcessRecord(tp->pid);
622 + if (pr != NULL)
623 + {
624 + if (IsUnicodeHook(*pr, tp->hook))
625 + thread->Status() |= USING_UNICODE;
626 + }
627 +
628 + auto pf = pfman->GetProfile(tp->pid);
629 + if (pf)
630 + {
631 + auto thread_profile = pf->FindThreadProfile(*tp);
632 + if (thread_profile != pf->Threads().end())
633 + {
634 + (*thread_profile)->HookManagerIndex() = thread->Number();
635 + auto thread_profile_index = thread_profile - pf->Threads().begin();
636 + AddLinksToHookManager(*pf, thread_profile_index, *thread);
637 + if (pf->SelectedIndex() == thread_profile_index)
638 + ThreadReset(thread);
639 + }
640 + }
641 + return 0;
642 +}
643 +
644 +void AddLinksToHookManager(const Profile& pf, size_t thread_profile_index, const TextThread& thread)
645 +{
646 + for (auto lp = pf.Links().begin(); lp != pf.Links().end(); ++lp)
647 + {
648 + if ((*lp)->FromIndex() == thread_profile_index)
649 + {
650 + WORD to_index = pf.Threads()[(*lp)->ToIndex()]->HookManagerIndex();
651 + if (to_index != 0)
652 + man->AddLink(thread.Number(), to_index);
653 + }
654 + if ((*lp)->ToIndex() == thread_profile_index)
655 + {
656 + WORD from_index = pf.Threads()[(*lp)->FromIndex()]->HookManagerIndex();
657 + if (from_index != 0)
658 + man->AddLink(from_index, thread.Number());
659 + }
660 + }
661 +}
662 +
663 +DWORD ThreadRemove(TextThread* thread)
664 +{
665 + RemoveFromCombo(thread);
666 + const auto tp = thread->GetThreadParameter();
667 + auto pf = pfman->GetProfile(tp->pid);
668 + if (pf)
669 + {
670 + auto thread_profile = pf->FindThreadProfile(*tp);
671 + if (thread_profile != pf->Threads().end())
672 + (*thread_profile)->HookManagerIndex() = 0; // reset hookman index number
673 + }
674 + return 0;
675 +}
676 +
677 +DWORD RegisterProcessList(DWORD pid)
678 +{
679 + auto path = GetProcessPath(pid);
680 + if (!path.empty())
681 + {
682 + WCHAR str[MAX_PATH];
683 + std::swprintf(str, L"%04d:%s", pid, path.substr(path.rfind(L'\\') + 1).c_str());
684 + ComboBox_AddString(hwndProcessComboBox, str);
685 + if (ComboBox_GetCount(hwndProcessComboBox) == 1)
686 + ComboBox_SetCurSel(hwndProcessComboBox, 0);
687 + pfman->FindProfileAndUpdateHookAddresses(pid, path);
688 + }
689 + return 0;
690 +}
691 +
692 +DWORD RemoveProcessList(DWORD pid)
693 +{
694 + WCHAR str[MAX_PATH];
695 + std::swprintf(str, L"%04d", pid);
696 + DWORD i = ComboBox_FindString(hwndProcessComboBox, 0, str);
697 + DWORD j = ComboBox_GetCurSel(hwndProcessComboBox);
698 + if (i != CB_ERR)
699 + {
700 + DWORD k = ComboBox_DeleteString(hwndProcessComboBox, i);
701 + if (i == j)
702 + ComboBox_SetCurSel(hwndProcessComboBox, 0);
703 + }
704 + return 0;
705 +}
706 +
707 +DWORD RefreshProfileOnNewHook(DWORD pid)
708 +{
709 + auto path = GetProcessPath(pid);
710 + if (!path.empty())
711 + pfman->FindProfileAndUpdateHookAddresses(pid, path);
712 + return 0;
713 +}
714 +
715 +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
716 +{
717 + switch (message)
718 + {
719 + case WM_CREATE:
720 + CreateButtons(hWnd);
721 + // Add text to the window.
722 + Edit_LimitText(hwndEdit, -1);
723 + SendMessage(hwndEdit, WM_INPUTLANGCHANGEREQUEST, 0, 0x411);
724 + proc = (WNDPROC)SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)EditProc);
725 + proccmd = (WNDPROC)SetWindowLong(hwndCmd, GWL_WNDPROC, (LONG)EditCmdProc);
726 + hwndCombo = CreateWindow(L"ComboBox", NULL,
727 + WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
728 + CBS_SORT | WS_VSCROLL | WS_TABSTOP,
729 + 0, 0, 0, 0, hWnd, 0, hIns, NULL);
730 + {
731 + HFONT hf = CreateFont(18, 0, 0, 0, FW_LIGHT, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, ANTIALIASED_QUALITY, 0,
732 + L"MS Gothic");
733 + hWhiteBrush = GetStockBrush(WHITE_BRUSH);
734 + SendMessage(hwndCmd, WM_SETFONT, (WPARAM)hf, 0);
735 + SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hf, 0);
736 + SendMessage(hwndCombo, WM_SETFONT, (WPARAM)hf, 0);
737 + SendMessage(hwndProcessComboBox, WM_SETFONT, (WPARAM)hf, 0);
738 + texts = new TextBuffer(hwndEdit);
739 + man->RegisterThreadCreateCallback(ThreadCreate);
740 + man->RegisterThreadRemoveCallback(ThreadRemove);
741 + man->RegisterThreadResetCallback(ThreadReset);
742 + TextThread* console = man->FindSingle(0);
743 + console->RegisterOutputCallBack(ThreadOutput, NULL);
744 + AddToCombo(*console, false);
745 + man->RegisterProcessAttachCallback(RegisterProcessList);
746 + man->RegisterProcessDetachCallback(RemoveProcessList);
747 + man->RegisterProcessNewHookCallback(RefreshProfileOnNewHook);
748 + man->RegisterAddRemoveLinkCallback(AddRemoveLink);
749 + man->RegisterConsoleCallback(ConsoleOutput);
750 + IHF_Start();
751 + {
752 + static const WCHAR program_name[] = L"Interactive Text Hooker";
753 + //static const WCHAR program_version[] = L"3.0";
754 + static WCHAR version_info[256];
755 + std::swprintf(version_info, L"%s %s (%s)", program_name, program_version, build_date);
756 + man->AddConsoleOutput(version_info);
757 + man->AddConsoleOutput(InitMessage);
758 + }
759 +
760 + if (background == 0)
761 + man->AddConsoleOutput(BackgroundMsg);
762 + if (!IHF_IsAdmin())
763 + man->AddConsoleOutput(NotAdmin);
764 + }
765 +
766 + return 0;
767 + case WM_COMMAND:
768 + {
769 + DWORD wmId, wmEvent, dwId;
770 + wmId = LOWORD(wParam);
771 + wmEvent = HIWORD(wParam);
772 + switch (wmEvent)
773 + {
774 + case EN_VSCROLL:
775 + {
776 + SCROLLBARINFO info={sizeof(info)};
777 + GetScrollBarInfo(hwndEdit, OBJID_VSCROLL, &info);
778 + InvalidateRect(hwndEdit, 0, 1);
779 + ValidateRect(hwndEdit, &info.rcScrollBar);
780 + RedrawWindow(hwndEdit, 0, 0, RDW_ERASE);
781 + }
782 + break;
783 + case CBN_SELENDOK:
784 + {
785 + if ((HWND)lParam == hwndProcessComboBox)
786 + return 0;
787 + dwId = ComboBox_GetCurSel(hwndCombo);
788 + int len = ComboBox_GetLBTextLen(hwndCombo, dwId);
789 + if (len > 0)
790 + {
791 + LPWSTR pwcEntry = new WCHAR[len + 1];
792 + len = ComboBox_GetLBText(hwndCombo, dwId, pwcEntry);
793 + DWORD num = std::stoul(pwcEntry, NULL, 16);
794 + man->SelectCurrent(num);
795 + delete[] pwcEntry;
796 + }
797 + }
798 + return 0;
799 + case BN_CLICKED:
800 + ClickButton(hWnd, (HWND)lParam);
801 + break;
802 + default:
803 + break;
804 + }
805 + }
806 + break;
807 + case WM_SETFOCUS:
808 + SetFocus(hwndEdit);
809 + return 0;
810 + case WM_SIZE:
811 + {
812 + WORD width = LOWORD(lParam);
813 + WORD height = HIWORD(lParam);
814 + DWORD l = width / 7;
815 + WORD h = HIWORD(GetDialogBaseUnits()); // height of the system font
816 + h = h + (h / 2);
817 + HDC hDC = GetDC(hWnd);
818 + RECT rc;
819 + GetClientRect(hWnd, &rc);
820 + FillRect(hDC, &rc, hWhiteBrush);
821 + ReleaseDC(hWnd, hDC);
822 + MoveWindow(hwndProcess, 0, 0, l, h, TRUE);
823 + MoveWindow(hwndOption, l * 1, 0, l, h, TRUE);
824 + MoveWindow(hwndTop, l * 2, 0, l, h, TRUE);
825 + MoveWindow(hwndClear, l * 3, 0, l, h, TRUE);
826 + MoveWindow(hwndRemoveLink, l * 4, 0, l, h, TRUE);
827 + MoveWindow(hwndRemoveHook, l * 5, 0, l, h, TRUE);
828 + MoveWindow(hwndSave, l * 6, 0, width - 6 * l, h, TRUE);
829 + l *= 2;
830 + MoveWindow(hwndProcessComboBox, 0, h, l, 200, TRUE);
831 + MoveWindow(hwndCmd, l, h, width - l, h, TRUE);
832 + MoveWindow(hwndCombo, 0, h * 2, width, 200, TRUE);
833 + h *= 3;
834 + MoveWindow(hwndEdit, 0, h, width, height - h, TRUE);
835 + }
836 + return 0;
837 + case WM_DESTROY:
838 + man->RegisterThreadCreateCallback(0);
839 + man->RegisterThreadRemoveCallback(0);
840 + man->RegisterThreadResetCallback(0);
841 + man->RegisterProcessAttachCallback(0);
842 + man->RegisterProcessDetachCallback(0);
843 + //delete texts;
844 + SaveSettings();
845 + PostQuitMessage(0);
846 + return 0;
847 + default:
848 + return DefWindowProc(hWnd, message, wParam, lParam);
849 + }
850 + return 0;
851 +}
852 +
853 +DWORD WINAPI FlushThread(LPVOID lParam)
854 +{
855 + TextBuffer* t = (TextBuffer*)lParam;
856 + while (t->Running())
857 + {
858 + t->Flush();
859 + Sleep(10);
860 + }
861 + return 0;
862 +}
1 +/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 + * This file is part of the Interactive Text Hooker.
3 +
4 + * Interactive Text Hooker is free software: you can redistribute it and/or
5 + * modify it under the terms of the GNU General Public License as published
6 + * by the Free Software Foundation, either version 3 of the License, or
7 + * (at your option) any later version.
8 +
9 + * This program is distributed in the hope that it will be useful,
10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 + * GNU General Public License for more details.
13 +
14 + * You should have received a copy of the GNU General Public License
15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 + */
17 +
18 +#pragma once
19 +#include "ITH.h"