@@ -34,12 +34,18 @@ CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj)
34
34
return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*, const char *))0x538090 )(obj, nullptr );
35
35
}
36
36
37
+ CEntitySAInterface* CFileLoaderSA::LoadObjectInstance (const char * szLine)
38
+ {
39
+ // Delegate to the global function that does the actual work
40
+ return CFileLoader_LoadObjectInstance (szLine);
41
+ }
42
+
37
43
class CAtomicModelInfo
38
44
{
39
45
public:
40
- void CAtomicModelInfo:: DeleteRwObject () { ((void (__thiscall*)(CAtomicModelInfo*))(*(void ***)this )[8 ])(this ); }
46
+ void DeleteRwObject () { ((void (__thiscall*)(CAtomicModelInfo*))(*(void ***)this )[8 ])(this ); }
41
47
42
- void CAtomicModelInfo:: SetAtomic (RpAtomic* atomic) { ((void (__thiscall*)(CAtomicModelInfo*, RpAtomic*))(*(void ***)this )[15 ])(this , atomic); }
48
+ void SetAtomic (RpAtomic* atomic) { ((void (__thiscall*)(CAtomicModelInfo*, RpAtomic*))(*(void ***)this )[15 ])(this , atomic); }
43
49
};
44
50
45
51
class CDamagableModelInfo
@@ -70,9 +76,10 @@ void GetNameAndDamage(const char* nodeName, char (&outName)[OutBuffSize], bool&
70
76
// Copy `nodeName` into `outName` with `off` trimmed from the end
71
77
// Eg.: `dmg_dam` with `off = 4` becomes `dmg`
72
78
const auto TerminatedCopy = [&](size_t off) {
73
- dassert (nodeNameLen - off < OutBuffSize);
74
- strncpy_s (outName, nodeName,
75
- std::min (nodeNameLen - off, OutBuffSize - 1 )); // By providing `OutBuffSize - 1` it is ensured the array will be null terminated
79
+ dassert (nodeNameLen >= off && nodeNameLen - off < OutBuffSize);
80
+ const size_t copyLen = std::min (nodeNameLen - off, OutBuffSize - 1 );
81
+ strncpy_s (outName, nodeName, copyLen);
82
+ outName[copyLen] = ' \0 ' ; // Ensure null termination
76
83
};
77
84
78
85
if (NodeNameEndsWith (" _dam" ))
@@ -90,7 +97,9 @@ void GetNameAndDamage(const char* nodeName, char (&outName)[OutBuffSize], bool&
90
97
else
91
98
{
92
99
dassert (nodeNameLen < OutBuffSize);
93
- strncpy_s (outName, OutBuffSize, nodeName, OutBuffSize - 1 );
100
+ const size_t copyLen = std::min (nodeNameLen, OutBuffSize - 1 );
101
+ strncpy_s (outName, OutBuffSize, nodeName, copyLen);
102
+ outName[copyLen] = ' \0 ' ; // Ensure null termination
94
103
}
95
104
}
96
105
}
@@ -172,7 +181,19 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo*
172
181
RwFrame* pOldFrame = reinterpret_cast <RwFrame*>(atomic->object .object .parent );
173
182
char * frameNodeName = GetFrameNodeName (pOldFrame);
174
183
bool bDamage = false ;
175
- GetNameAndDamage (frameNodeName, name, bDamage);
184
+
185
+ // Check for null pointers before using them
186
+ if (!frameNodeName)
187
+ {
188
+ // Handle case where frame node name is null
189
+ strcpy_s (name, sizeof (name), " unknown" );
190
+ bDamage = false ;
191
+ }
192
+ else
193
+ {
194
+ GetNameAndDamage (frameNodeName, name, bDamage);
195
+ }
196
+
176
197
CVisibilityPlugins_SetAtomicRenderCallback (atomic, 0 );
177
198
178
199
RpAtomic* pOldAtomic = reinterpret_cast <RpAtomic*>(pBaseModelInfo->pRwObject );
@@ -212,16 +233,34 @@ CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine)
212
233
char szModelName[24 ];
213
234
SFileObjectInstance inst;
214
235
215
- sscanf (szLine, " %d %s %d %f %f %f %f %f %f %f %d" , &inst.modelID , szModelName, &inst.interiorID , &inst.position .fX , &inst.position .fY , &inst.position .fZ ,
236
+ // Use safer scanf with width specifier to prevent buffer overflow
237
+ int result = sscanf (szLine, " %d %23s %d %f %f %f %f %f %f %f %d" , &inst.modelID , szModelName, &inst.interiorID , &inst.position .fX , &inst.position .fY , &inst.position .fZ ,
216
238
&inst.rotation .fX , &inst.rotation .fY , &inst.rotation .fZ , &inst.rotation .fW , &inst.lod );
239
+
240
+ // Check if all expected fields were parsed
241
+ if (result != 11 ) {
242
+ // Return null or handle error appropriately
243
+ return nullptr ;
244
+ }
217
245
218
246
/*
219
- A quaternion is must be normalized. GTA is relying on an internal R* exporter and everything is OK,
247
+ A quaternion must be normalized. GTA is relying on an internal R* exporter and everything is OK,
220
248
but custom exporters might not contain the normalization. And we must do it instead.
221
249
*/
222
250
const float fLenSq = inst.rotation .LengthSquared ();
223
251
if (fLenSq > 0 .0f && std::fabs (fLenSq - 1 .0f ) > std::numeric_limits<float >::epsilon ())
224
- inst.rotation /= std::sqrt (fLenSq );
252
+ {
253
+ const float fLength = std::sqrt (fLenSq );
254
+ inst.rotation /= fLength ;
255
+ }
256
+ else if (fLenSq <= 0 .0f )
257
+ {
258
+ // Handle degenerate case: set to identity quaternion
259
+ inst.rotation .fX = 0 .0f ;
260
+ inst.rotation .fY = 0 .0f ;
261
+ inst.rotation .fZ = 0 .0f ;
262
+ inst.rotation .fW = 1 .0f ;
263
+ }
225
264
226
265
return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090 )(&inst);
227
266
}
0 commit comments