@@ -34,12 +34,18 @@ CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(SFileObjectInstance* obj)
3434 return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*, const char *))0x538090 )(obj, nullptr );
3535}
3636
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+
3743class CAtomicModelInfo
3844{
3945public:
40- void CAtomicModelInfo:: DeleteRwObject () { ((void (__thiscall*)(CAtomicModelInfo*))(*(void ***)this )[8 ])(this ); }
46+ void DeleteRwObject () { ((void (__thiscall*)(CAtomicModelInfo*))(*(void ***)this )[8 ])(this ); }
4147
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); }
4349};
4450
4551class CDamagableModelInfo
@@ -70,9 +76,10 @@ void GetNameAndDamage(const char* nodeName, char (&outName)[OutBuffSize], bool&
7076 // Copy `nodeName` into `outName` with `off` trimmed from the end
7177 // Eg.: `dmg_dam` with `off = 4` becomes `dmg`
7278 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
7683 };
7784
7885 if (NodeNameEndsWith (" _dam" ))
@@ -90,7 +97,9 @@ void GetNameAndDamage(const char* nodeName, char (&outName)[OutBuffSize], bool&
9097 else
9198 {
9299 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
94103 }
95104 }
96105}
@@ -172,7 +181,19 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo*
172181 RwFrame* pOldFrame = reinterpret_cast <RwFrame*>(atomic->object .object .parent );
173182 char * frameNodeName = GetFrameNodeName (pOldFrame);
174183 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+
176197 CVisibilityPlugins_SetAtomicRenderCallback (atomic, 0 );
177198
178199 RpAtomic* pOldAtomic = reinterpret_cast <RpAtomic*>(pBaseModelInfo->pRwObject );
@@ -212,16 +233,34 @@ CEntitySAInterface* CFileLoader_LoadObjectInstance(const char* szLine)
212233 char szModelName[24 ];
213234 SFileObjectInstance inst;
214235
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 ,
216238 &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+ }
217245
218246 /*
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,
220248 but custom exporters might not contain the normalization. And we must do it instead.
221249 */
222250 const float fLenSq = inst.rotation .LengthSquared ();
223251 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+ }
225264
226265 return ((CEntitySAInterface * (__cdecl*)(SFileObjectInstance*))0x538090 )(&inst);
227266}
0 commit comments