Skip to content

Commit 5035ffd

Browse files
authored
chore(lib): Implement Usp10Loader class (#3241)
1 parent 61d4465 commit 5035ffd

3 files changed

Lines changed: 286 additions & 0 deletions

File tree

Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ if(WIN32)
162162
rcfile.h
163163
registry.cpp
164164
registry.h
165+
Usp10Loader.cpp
166+
Usp10Loader.h
165167
verchk.cpp
166168
verchk.h
167169
WWCOMUtil.cpp
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2026 TheSuperHackers
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "Usp10Loader.h"
20+
21+
22+
CriticalSectionClass Usp10Loader::CriticalSection;
23+
HMODULE Usp10Loader::Module = HMODULE(nullptr);
24+
bool Usp10Loader::LoadAttempted = false;
25+
Usp10Loader::ScriptIsComplex_t Usp10Loader::ScriptIsComplexPtr = nullptr;
26+
Usp10Loader::ScriptItemize_t Usp10Loader::ScriptItemizePtr = nullptr;
27+
Usp10Loader::ScriptBreak_t Usp10Loader::ScriptBreakPtr = nullptr;
28+
Usp10Loader::ScriptLayout_t Usp10Loader::ScriptLayoutPtr = nullptr;
29+
Usp10Loader::ScriptStringAnalyse_t Usp10Loader::ScriptStringAnalysePtr = nullptr;
30+
Usp10Loader::ScriptStringFree_t Usp10Loader::ScriptStringFreePtr = nullptr;
31+
Usp10Loader::ScriptString_pSize_t Usp10Loader::ScriptString_pSizePtr = nullptr;
32+
Usp10Loader::ScriptStringOut_t Usp10Loader::ScriptStringOutPtr = nullptr;
33+
34+
35+
bool Usp10Loader::load()
36+
{
37+
if (LoadAttempted) {
38+
return Module != HMODULE(nullptr);
39+
}
40+
LoadAttempted = true;
41+
42+
char dll_path[MAX_PATH];
43+
const char dll_name[] = "\\usp10.dll";
44+
const UINT path_length = ::GetSystemDirectoryA(dll_path, ARRAY_SIZE(dll_path));
45+
if (path_length == 0 || path_length + ARRAY_SIZE(dll_name) > ARRAY_SIZE(dll_path)) {
46+
return false;
47+
}
48+
strcpy(dll_path + path_length, dll_name);
49+
50+
Module = ::LoadLibraryA(dll_path);
51+
if (Module == HMODULE(nullptr)) {
52+
return false;
53+
}
54+
55+
ScriptIsComplexPtr = reinterpret_cast<ScriptIsComplex_t>(::GetProcAddress(Module, "ScriptIsComplex"));
56+
ScriptItemizePtr = reinterpret_cast<ScriptItemize_t>(::GetProcAddress(Module, "ScriptItemize"));
57+
ScriptBreakPtr = reinterpret_cast<ScriptBreak_t>(::GetProcAddress(Module, "ScriptBreak"));
58+
ScriptLayoutPtr = reinterpret_cast<ScriptLayout_t>(::GetProcAddress(Module, "ScriptLayout"));
59+
ScriptStringAnalysePtr = reinterpret_cast<ScriptStringAnalyse_t>(::GetProcAddress(Module, "ScriptStringAnalyse"));
60+
ScriptStringFreePtr = reinterpret_cast<ScriptStringFree_t>(::GetProcAddress(Module, "ScriptStringFree"));
61+
ScriptString_pSizePtr = reinterpret_cast<ScriptString_pSize_t>(::GetProcAddress(Module, "ScriptString_pSize"));
62+
ScriptStringOutPtr = reinterpret_cast<ScriptStringOut_t>(::GetProcAddress(Module, "ScriptStringOut"));
63+
64+
if (ScriptIsComplexPtr == nullptr || ScriptItemizePtr == nullptr || ScriptBreakPtr == nullptr ||
65+
ScriptLayoutPtr == nullptr || ScriptStringAnalysePtr == nullptr || ScriptStringFreePtr == nullptr ||
66+
ScriptString_pSizePtr == nullptr || ScriptStringOutPtr == nullptr)
67+
{
68+
freeResources();
69+
return false;
70+
}
71+
72+
return true;
73+
}
74+
75+
76+
void Usp10Loader::unload()
77+
{
78+
CriticalSectionClass::LockClass lock(CriticalSection);
79+
80+
freeResources();
81+
LoadAttempted = false;
82+
}
83+
84+
85+
void Usp10Loader::freeResources()
86+
{
87+
if (Module != HMODULE(nullptr)) {
88+
::FreeLibrary(Module);
89+
Module = HMODULE(nullptr);
90+
}
91+
92+
ScriptIsComplexPtr = nullptr;
93+
ScriptItemizePtr = nullptr;
94+
ScriptBreakPtr = nullptr;
95+
ScriptLayoutPtr = nullptr;
96+
ScriptStringAnalysePtr = nullptr;
97+
ScriptStringFreePtr = nullptr;
98+
ScriptString_pSizePtr = nullptr;
99+
ScriptStringOutPtr = nullptr;
100+
}
101+
102+
103+
HRESULT Usp10Loader::ScriptIsComplex(const WCHAR *text, int text_length, DWORD flags)
104+
{
105+
CriticalSectionClass::LockClass lock(CriticalSection);
106+
return load() ? ScriptIsComplexPtr(text, text_length, flags) : E_FAIL;
107+
}
108+
109+
110+
HRESULT Usp10Loader::ScriptItemize(const WCHAR *text, int text_length, int item_capacity,
111+
const ScriptControl *control, const ScriptState *state, ScriptItem *items, int *item_count)
112+
{
113+
CriticalSectionClass::LockClass lock(CriticalSection);
114+
return load() ? ScriptItemizePtr(text, text_length, item_capacity, control, state, items, item_count) : E_FAIL;
115+
}
116+
117+
118+
HRESULT Usp10Loader::ScriptBreak(const WCHAR *text, int text_length, const ScriptAnalysis *analysis,
119+
ScriptLogAttr *attributes)
120+
{
121+
CriticalSectionClass::LockClass lock(CriticalSection);
122+
return load() ? ScriptBreakPtr(text, text_length, analysis, attributes) : E_FAIL;
123+
}
124+
125+
126+
HRESULT Usp10Loader::ScriptLayout(int run_count, const BYTE *levels, int *visual_to_logical,
127+
int *logical_to_visual)
128+
{
129+
CriticalSectionClass::LockClass lock(CriticalSection);
130+
return load() ? ScriptLayoutPtr(run_count, levels, visual_to_logical, logical_to_visual) : E_FAIL;
131+
}
132+
133+
134+
HRESULT Usp10Loader::ScriptStringAnalyse(HDC dc, const void *text, int text_length, int glyph_count,
135+
int charset, DWORD flags, int required_width, ScriptControl *control, ScriptState *state,
136+
const int *spacing, ScriptTabDefinition *tabs, const BYTE *character_classes, ScriptStringAnalysis *analysis)
137+
{
138+
CriticalSectionClass::LockClass lock(CriticalSection);
139+
return load() ? ScriptStringAnalysePtr(dc, text, text_length, glyph_count, charset, flags, required_width,
140+
control, state, spacing, tabs, character_classes, analysis) : E_FAIL;
141+
}
142+
143+
144+
HRESULT Usp10Loader::ScriptStringFree(ScriptStringAnalysis *analysis)
145+
{
146+
CriticalSectionClass::LockClass lock(CriticalSection);
147+
return load() ? ScriptStringFreePtr(analysis) : E_FAIL;
148+
}
149+
150+
151+
const SIZE *Usp10Loader::ScriptString_pSize(ScriptStringAnalysis analysis)
152+
{
153+
CriticalSectionClass::LockClass lock(CriticalSection);
154+
return load() ? ScriptString_pSizePtr(analysis) : nullptr;
155+
}
156+
157+
158+
HRESULT Usp10Loader::ScriptStringOut(ScriptStringAnalysis analysis, int x, int y, UINT options,
159+
const RECT *rect, int minimum_selection, int maximum_selection, BOOL disabled)
160+
{
161+
CriticalSectionClass::LockClass lock(CriticalSection);
162+
return load() ? ScriptStringOutPtr(analysis, x, y, options, rect, minimum_selection, maximum_selection, disabled) : E_FAIL;
163+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2026 TheSuperHackers
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#pragma once
20+
21+
#include "mutex.h"
22+
#include "win.h"
23+
24+
25+
// This static class loads usp10.dll on first use and unloads it during engine shutdown.
26+
27+
class Usp10Loader
28+
{
29+
public:
30+
31+
typedef void *ScriptStringAnalysis;
32+
struct ScriptControl;
33+
struct ScriptTabDefinition;
34+
35+
struct ScriptState
36+
{
37+
WORD bidi_level : 5;
38+
WORD reserved : 11;
39+
};
40+
41+
struct ScriptAnalysis
42+
{
43+
WORD script : 10;
44+
WORD right_to_left : 1;
45+
WORD layout_right_to_left : 1;
46+
WORD link_before : 1;
47+
WORD link_after : 1;
48+
WORD logical_order : 1;
49+
WORD no_glyph_index : 1;
50+
ScriptState state;
51+
};
52+
53+
struct ScriptItem
54+
{
55+
int character_position;
56+
ScriptAnalysis analysis;
57+
};
58+
59+
struct ScriptLogAttr
60+
{
61+
BYTE soft_break : 1;
62+
BYTE white_space : 1;
63+
BYTE char_stop : 1;
64+
BYTE word_stop : 1;
65+
BYTE invalid : 1;
66+
BYTE reserved : 3;
67+
};
68+
69+
enum
70+
{
71+
SIC_COMPLEX = 0x00000001,
72+
SSA_FALLBACK = 0x00000020,
73+
SSA_GLYPHS = 0x00000080,
74+
SSA_RTL = 0x00000100,
75+
};
76+
77+
static HRESULT ScriptIsComplex(const WCHAR *text, int text_length, DWORD flags);
78+
static HRESULT ScriptItemize(const WCHAR *text, int text_length, int item_capacity,
79+
const ScriptControl *control, const ScriptState *state, ScriptItem *items, int *item_count);
80+
static HRESULT ScriptBreak(const WCHAR *text, int text_length, const ScriptAnalysis *analysis,
81+
ScriptLogAttr *attributes);
82+
static HRESULT ScriptLayout(int run_count, const BYTE *levels, int *visual_to_logical,
83+
int *logical_to_visual);
84+
static HRESULT ScriptStringAnalyse(HDC dc, const void *text, int text_length, int glyph_count,
85+
int charset, DWORD flags, int required_width, ScriptControl *control, ScriptState *state,
86+
const int *spacing, ScriptTabDefinition *tabs, const BYTE *character_classes,
87+
ScriptStringAnalysis *analysis);
88+
static HRESULT ScriptStringFree(ScriptStringAnalysis *analysis);
89+
static const SIZE *ScriptString_pSize(ScriptStringAnalysis analysis);
90+
static HRESULT ScriptStringOut(ScriptStringAnalysis analysis, int x, int y, UINT options,
91+
const RECT *rect, int minimum_selection, int maximum_selection, BOOL disabled);
92+
static void unload();
93+
94+
private:
95+
96+
static bool load();
97+
static void freeResources();
98+
99+
typedef HRESULT (WINAPI *ScriptIsComplex_t)(const WCHAR *, int, DWORD);
100+
typedef HRESULT (WINAPI *ScriptItemize_t)(const WCHAR *, int, int, const ScriptControl *,
101+
const ScriptState *, ScriptItem *, int *);
102+
typedef HRESULT (WINAPI *ScriptBreak_t)(const WCHAR *, int, const ScriptAnalysis *, ScriptLogAttr *);
103+
typedef HRESULT (WINAPI *ScriptLayout_t)(int, const BYTE *, int *, int *);
104+
typedef HRESULT (WINAPI *ScriptStringAnalyse_t)(HDC, const void *, int, int, int, DWORD, int,
105+
ScriptControl *, ScriptState *, const int *, ScriptTabDefinition *, const BYTE *, ScriptStringAnalysis *);
106+
typedef HRESULT (WINAPI *ScriptStringFree_t)(ScriptStringAnalysis *);
107+
typedef const SIZE *(WINAPI *ScriptString_pSize_t)(ScriptStringAnalysis);
108+
typedef HRESULT (WINAPI *ScriptStringOut_t)(ScriptStringAnalysis, int, int, UINT, const RECT *, int, int, BOOL);
109+
110+
static CriticalSectionClass CriticalSection;
111+
static HMODULE Module;
112+
static bool LoadAttempted;
113+
static ScriptIsComplex_t ScriptIsComplexPtr;
114+
static ScriptItemize_t ScriptItemizePtr;
115+
static ScriptBreak_t ScriptBreakPtr;
116+
static ScriptLayout_t ScriptLayoutPtr;
117+
static ScriptStringAnalyse_t ScriptStringAnalysePtr;
118+
static ScriptStringFree_t ScriptStringFreePtr;
119+
static ScriptString_pSize_t ScriptString_pSizePtr;
120+
static ScriptStringOut_t ScriptStringOutPtr;
121+
};

0 commit comments

Comments
 (0)