1
0
forked from 0ad/0ad

fix to prevent further issues due to invalid XMB files (c.f. matt's "crash upon combat" bug report, http://www.wildfiregames.com/forum/index.php?showtopic=11703). as per philip's excellent suggestion, they are now only tagged with a header iff the file contents are valid.

details:
- add a new magic string "XMBu" to indicate an unfinished XMB file;
- header magic fields are now exclusively strings to avoid type punning;
- XMBFile::Initialize now has a return value which is checked by
ReadXMBFile;
- the XML loader re-creates the XMB if that fails.

This was SVN commit r6016.
This commit is contained in:
janwas 2008-06-15 17:24:32 +00:00
parent 34fec9cb85
commit 6324deb7d0
3 changed files with 27 additions and 13 deletions

View File

@ -2,20 +2,25 @@
#include "Xeromyces.h"
#include "lib/byte_order.h" // FOURCC_LE
#include "ps/utf16string.h"
const u32 HeaderMagic = 0x30424D58; // = "XMB0" (little-endian)
// external linkage (also used by Xeromyces.cpp)
const char* HeaderMagicStr = "XMB0";
const char* UnfinishedHeaderMagicStr = "XMBu";
// Warning: May contain traces of pointer abuse
void XMBFile::Initialise(const char* FileData)
bool XMBFile::Initialise(const char* FileData)
{
m_Pointer = FileData;
u32 Header = *(u32 *)m_Pointer; m_Pointer += 4;
debug_assert(Header == HeaderMagic && "Invalid XMB header!");
char Header[5];
strncpy_s(Header, 5, m_Pointer, 4);
m_Pointer += 4;
// (c.f. @return documentation of this function)
if(!strcmp(Header, UnfinishedHeaderMagicStr))
return false;
debug_assert(!strcmp(Header, HeaderMagicStr) && "Invalid XMB header!");
int i;
@ -47,6 +52,7 @@ void XMBFile::Initialise(const char* FileData)
m_Pointer += 4 + *(int*)m_Pointer; // skip over the string
#endif
return true; // success
}
std::string XMBFile::ReadZStrA()

View File

@ -94,8 +94,8 @@ XMB_Text {
#endif
// File headers, to make sure it doesn't try loading anything other than an XMB
extern const u32 HeaderMagic;
extern const char* HeaderMagicStr;
extern const char* UnfinishedHeaderMagicStr;
class XMBElement;
class XMBElementList;
@ -111,7 +111,10 @@ public:
// Initialise from the contents of an XMB file.
// FileData must remain allocated and unchanged while
// the XMBFile is being used.
void Initialise(const char* FileData);
// @return indication of success; main cause for failure is attempting to
// load a partially valid XMB file (e.g. if the game was interrupted
// while writing it), which we detect by checking the magic string.
bool Initialise(const char* FileData);
// Returns the root element
XMBElement GetRoot() const;

View File

@ -177,8 +177,8 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
{
if (ReadXMBFile(xmbPath))
return PSRETURN_OK;
else
return PSRETURN_Xeromyces_XMLOpenFailed;
// (no longer return PSRETURN_Xeromyces_XMLOpenFailed here because
// failure legitimately happens due to partially-written XMB files.)
}
@ -243,7 +243,8 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
XMBBuffer = writeBuffer.Data(); // add a reference
// Set up the XMBFile
Initialise((const char*)XMBBuffer.get());
const bool ok = Initialise((const char*)XMBBuffer.get());
debug_assert(ok);
return PSRETURN_OK;
}
@ -256,7 +257,8 @@ bool CXeromyces::ReadXMBFile(const VfsPath& filename)
debug_assert(size >= 42); // else: invalid XMB file size. (42 bytes is the smallest possible XMB. (Well, maybe not quite, but it's a nice number.))
// Set up the XMBFile
Initialise((const char*)XMBBuffer.get());
if(!Initialise((const char*)XMBBuffer.get()))
return false;
return true;
}
@ -349,7 +351,7 @@ void XeroHandler::characters(const XMLCh* const chars, const unsigned int UNUSED
void XeroHandler::CreateXMB()
{
// Header
writeBuffer.Append((void*)HeaderMagicStr, 4);
writeBuffer.Append(UnfinishedHeaderMagicStr, 4);
std::set<std::string>::iterator it;
int i;
@ -385,6 +387,9 @@ void XeroHandler::CreateXMB()
delete Root;
Root = NULL;
// file is now valid, so insert correct magic string
writeBuffer.Overwrite(HeaderMagicStr, 4, 0);
}
// Writes a whole element (recursively if it has children) into the buffer,