Skip to content

Commit 9c87f92

Browse files
authored
feat(string): Implement functions for AsciiString, UnicodeString that build a new string with a fixed length (#1494)
1 parent a69c912 commit 9c87f92

File tree

4 files changed

+96
-16
lines changed

4 files changed

+96
-16
lines changed

Core/GameEngine/Include/Common/AsciiString.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ class AsciiString
148148
*/
149149
AsciiString(const char* s);
150150

151+
/**
152+
Constructs an AsciiString with the given string and length.
153+
The length must not be larger than the actual string length.
154+
*/
155+
AsciiString(const char* s, int len);
156+
151157
/**
152158
Destructor. Not too exciting... clean up the works and such.
153159
*/
@@ -200,12 +206,20 @@ class AsciiString
200206
refcount.)
201207
*/
202208
void set(const AsciiString& stringSrc);
209+
203210
/**
204211
Replace the contents of self with the given string.
205212
Note that a copy of the string is made; the input ptr is not saved.
206213
*/
207214
void set(const char* s);
208215

216+
/**
217+
Replace the contents of self with the given string and length.
218+
Note that a copy of the string is made; the input ptr is not saved.
219+
The length must not be larger than the actual string length.
220+
*/
221+
void set(const char* s, int len);
222+
209223
/**
210224
replace contents of self with the given string. Note the
211225
nomenclature is translate rather than set; this is because

Core/GameEngine/Include/Common/UnicodeString.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ class UnicodeString
148148
*/
149149
UnicodeString(const WideChar* s);
150150

151+
/**
152+
Constructs an UnicodeString with the given string and length.
153+
The length must not be larger than the actual string length.
154+
*/
155+
UnicodeString(const WideChar* s, int len);
156+
151157
/**
152158
Destructor. Not too exciting... clean up the works and such.
153159
*/
@@ -200,12 +206,20 @@ class UnicodeString
200206
refcount.)
201207
*/
202208
void set(const UnicodeString& stringSrc);
209+
203210
/**
204211
Replace the contents of self with the given string.
205212
Note that a copy of the string is made; the input ptr is not saved.
206213
*/
207214
void set(const WideChar* s);
208215

216+
/**
217+
Replace the contents of self with the given string and length.
218+
Note that a copy of the string is made; the input ptr is not saved.
219+
The length must not be larger than the actual string length.
220+
*/
221+
void set(const WideChar* s, int len);
222+
209223
/**
210224
replace contents of self with the given string. Note the
211225
nomenclature is translate rather than set; this is because

Core/GameEngine/Source/Common/System/AsciiString.cpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,20 @@ void AsciiString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveData
125125
{
126126
validate();
127127

128+
const int usableNumChars = numCharsNeeded - 1;
129+
128130
if (m_data &&
129131
m_data->m_refCount == 1 &&
130132
m_data->m_numCharsAllocated >= numCharsNeeded)
131133
{
132134
// no buffer manhandling is needed (it's already large enough, and unique to us)
133135
if (strToCopy)
136+
{
134137
// TheSuperHackers @fix Mauller 04/04/2025 Replace strcpy with safer memmove as memory regions can overlap when part of string is copied to itself
135-
memmove(m_data->peek(), strToCopy, strlen(strToCopy) + 1);
138+
DEBUG_ASSERTCRASH(usableNumChars <= strlen(strToCopy), ("strToCopy is too small"));
139+
memmove(m_data->peek(), strToCopy, usableNumChars);
140+
m_data->peek()[usableNumChars] = 0;
141+
}
136142
if (strToCat)
137143
strcat(m_data->peek(), strToCat);
138144
return;
@@ -157,7 +163,11 @@ void AsciiString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveData
157163
// do these BEFORE releasing the old buffer, so that self-copies
158164
// or self-cats will work correctly.
159165
if (strToCopy)
160-
strcpy(newData->peek(), strToCopy);
166+
{
167+
DEBUG_ASSERTCRASH(usableNumChars <= strlen(strToCopy), ("strToCopy is too small"));
168+
strncpy(newData->peek(), strToCopy, usableNumChars);
169+
newData->peek()[usableNumChars] = 0;
170+
}
161171
if (strToCat)
162172
strcat(newData->peek(), strToCat);
163173

@@ -186,11 +196,21 @@ void AsciiString::releaseBuffer()
186196
}
187197

188198
// -----------------------------------------------------
189-
AsciiString::AsciiString(const char* s) : m_data(0)
199+
AsciiString::AsciiString(const char* s) : m_data(NULL)
190200
{
191201
//DEBUG_ASSERTCRASH(isMemoryManagerOfficiallyInited(), ("Initializing AsciiStrings prior to main (ie, as static vars) can cause memory leak reporting problems. Are you sure you want to do this?"));
192-
int len = (s)?strlen(s):0;
193-
if (len)
202+
int len = s ? (int)strlen(s) : 0;
203+
if (len > 0)
204+
{
205+
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
206+
}
207+
validate();
208+
}
209+
210+
// -----------------------------------------------------
211+
AsciiString::AsciiString(const char* s, int len) : m_data(NULL)
212+
{
213+
if (len > 0)
194214
{
195215
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
196216
}
@@ -215,12 +235,18 @@ void AsciiString::set(const AsciiString& stringSrc)
215235

216236
// -----------------------------------------------------
217237
void AsciiString::set(const char* s)
238+
{
239+
int len = s ? strlen(s) : 0;
240+
set(s, len);
241+
}
242+
243+
// -----------------------------------------------------
244+
void AsciiString::set(const char* s, int len)
218245
{
219246
validate();
220247
if (!m_data || s != peek())
221248
{
222-
int len = s ? strlen(s) : 0;
223-
if (len)
249+
if (len > 0)
224250
{
225251
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
226252
}
@@ -375,7 +401,7 @@ void AsciiString::truncateBy(const Int charCount)
375401
const size_t len = strlen(peek());
376402
if (len > 0)
377403
{
378-
ensureUniqueBufferOfSize(len+1, true, NULL, NULL);
404+
ensureUniqueBufferOfSize(len + 1, true, NULL, NULL);
379405
size_t count = charCount;
380406
if (charCount > len)
381407
{

Core/GameEngine/Source/Common/System/UnicodeString.cpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,20 @@ void UnicodeString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveDa
7676
{
7777
validate();
7878

79+
const int usableNumChars = numCharsNeeded - 1;
80+
7981
if (m_data &&
8082
m_data->m_refCount == 1 &&
8183
m_data->m_numCharsAllocated >= numCharsNeeded)
8284
{
8385
// no buffer manhandling is needed (it's already large enough, and unique to us)
8486
if (strToCopy)
87+
{
8588
// TheSuperHackers @fix Mauller 04/04/2025 Replace wcscpy with safer memmove as memory regions can overlap when part of string is copied to itself
86-
memmove(m_data->peek(), strToCopy, (wcslen(strToCopy) + 1) * sizeof(WideChar));
89+
DEBUG_ASSERTCRASH(usableNumChars <= wcslen(strToCopy), ("strToCopy is too small"));
90+
memmove(m_data->peek(), strToCopy, usableNumChars * sizeof(WideChar));
91+
m_data->peek()[usableNumChars] = 0;
92+
}
8793
if (strToCat)
8894
wcscat(m_data->peek(), strToCat);
8995
return;
@@ -108,7 +114,11 @@ void UnicodeString::ensureUniqueBufferOfSize(int numCharsNeeded, Bool preserveDa
108114
// do these BEFORE releasing the old buffer, so that self-copies
109115
// or self-cats will work correctly.
110116
if (strToCopy)
111-
wcscpy(newData->peek(), strToCopy);
117+
{
118+
DEBUG_ASSERTCRASH(usableNumChars <= wcslen(strToCopy), ("strToCopy is too small"));
119+
wcsncpy(newData->peek(), strToCopy, usableNumChars);
120+
newData->peek()[usableNumChars] = 0;
121+
}
112122
if (strToCat)
113123
wcscat(newData->peek(), strToCat);
114124

@@ -136,10 +146,20 @@ void UnicodeString::releaseBuffer()
136146
}
137147

138148
// -----------------------------------------------------
139-
UnicodeString::UnicodeString(const WideChar* s) : m_data(0)
149+
UnicodeString::UnicodeString(const WideChar* s) : m_data(NULL)
140150
{
141-
int len = wcslen(s);
142-
if (len)
151+
int len = s ? (int)wcslen(s) : 0;
152+
if (len > 0)
153+
{
154+
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
155+
}
156+
validate();
157+
}
158+
159+
// -----------------------------------------------------
160+
UnicodeString::UnicodeString(const WideChar* s, int len) : m_data(NULL)
161+
{
162+
if (len > 0)
143163
{
144164
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
145165
}
@@ -164,12 +184,18 @@ void UnicodeString::set(const UnicodeString& stringSrc)
164184

165185
// -----------------------------------------------------
166186
void UnicodeString::set(const WideChar* s)
187+
{
188+
int len = s ? wcslen(s) : 0;
189+
set(s, len);
190+
}
191+
192+
// -----------------------------------------------------
193+
void UnicodeString::set(const WideChar* s, int len)
167194
{
168195
validate();
169196
if (!m_data || s != peek())
170197
{
171-
int len = s ? wcslen(s) : 0;
172-
if (len)
198+
if (len > 0)
173199
{
174200
ensureUniqueBufferOfSize(len + 1, false, s, NULL);
175201
}
@@ -307,7 +333,7 @@ void UnicodeString::truncateBy(const Int charCount)
307333
const size_t len = wcslen(peek());
308334
if (len > 0)
309335
{
310-
ensureUniqueBufferOfSize(len+1, true, NULL, NULL);
336+
ensureUniqueBufferOfSize(len + 1, true, NULL, NULL);
311337
size_t count = charCount;
312338
if (charCount > len)
313339
{

0 commit comments

Comments
 (0)