XMB
This was SVN commit r665.
This commit is contained in:
parent
92f14cd90a
commit
a8f48ff7e0
@ -1,5 +1,4 @@
|
||||
#include "precompiled.h"
|
||||
#undef new // if it was redefined for leak detection, since xerces doesn't like it
|
||||
|
||||
#include "ObjectEntry.h"
|
||||
#include "ObjectManager.h"
|
||||
@ -9,12 +8,7 @@
|
||||
|
||||
#include "UnitManager.h"
|
||||
|
||||
#include "XML.h"
|
||||
|
||||
|
||||
// automatically use namespace ..
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
#include "ps/Xeromyces.h"
|
||||
|
||||
CObjectEntry::CObjectEntry(int type) : m_Model(0), m_Type(type)
|
||||
{
|
||||
@ -36,6 +30,7 @@ CObjectEntry::~CObjectEntry()
|
||||
|
||||
bool CObjectEntry::BuildModel()
|
||||
{
|
||||
|
||||
// check we've enough data to consider building the object
|
||||
if (m_ModelName.Length()==0 || m_TextureName.Length()==0) {
|
||||
return false;
|
||||
@ -149,138 +144,98 @@ CSkeletonAnim* CObjectEntry::GetNamedAnimation( CStr animationName )
|
||||
|
||||
bool CObjectEntry::Load(const char* filename)
|
||||
{
|
||||
bool parseOK = false;
|
||||
|
||||
|
||||
// Initialize XML library
|
||||
CXeromyces XeroFile;
|
||||
try
|
||||
{
|
||||
XMLCh* attachpointtext=XMLString::transcode("attachpoint");
|
||||
XMLCh* modeltext=XMLString::transcode("model");
|
||||
XMLCh* nametext=XMLString::transcode("name");
|
||||
XMLCh* filetext=XMLString::transcode("file");
|
||||
XMLCh* speedtext=XMLString::transcode("speed");
|
||||
XeroFile.Load(filename);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create parser instance
|
||||
XercesDOMParser *parser = new XercesDOMParser();
|
||||
// Define all the elements and attributes used in the XML file
|
||||
#define EL(x) int el_##x = XeroFile.getElementID(L#x)
|
||||
#define AT(x) int at_##x = XeroFile.getAttributeID(L#x)
|
||||
EL(name);
|
||||
EL(modelname);
|
||||
EL(texturename);
|
||||
EL(animations);
|
||||
EL(props);
|
||||
AT(attachpoint);
|
||||
AT(model);
|
||||
AT(name);
|
||||
AT(file);
|
||||
AT(speed);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
// Setup parser
|
||||
parser->setValidationScheme(XercesDOMParser::Val_Auto);
|
||||
parser->setDoNamespaces(false);
|
||||
parser->setDoSchema(false);
|
||||
parser->setCreateEntityReferenceNodes(false);
|
||||
XMBElement root = XeroFile.getRoot();
|
||||
|
||||
// Set customized error handler
|
||||
CXercesErrorHandler *errorHandler = new CXercesErrorHandler();
|
||||
parser->setErrorHandler(errorHandler);
|
||||
XMBElementList children = root.getChildNodes();
|
||||
|
||||
CVFSEntityResolver *entityResolver = new CVFSEntityResolver(filename);
|
||||
parser->setEntityResolver(entityResolver);
|
||||
for (int i = 0; i < children.Count; ++i) {
|
||||
// Get node
|
||||
XMBElement child = children.item(i);
|
||||
|
||||
// Push the CLogger to mark it's reading this file.
|
||||
int element_name = child.getNodeName();
|
||||
CStr element_value=tocstr(child.getText());
|
||||
|
||||
// Get main node
|
||||
CVFSInputSource source;
|
||||
parseOK = source.OpenFile(filename) == 0;
|
||||
if (parseOK)
|
||||
if (element_name == el_name)
|
||||
m_Name=element_value;
|
||||
|
||||
else if (element_name == el_modelname)
|
||||
m_ModelName=element_value;
|
||||
|
||||
else if (element_name == el_texturename)
|
||||
m_TextureName=element_value;
|
||||
|
||||
else if (element_name == el_animations)
|
||||
{
|
||||
// Parse file
|
||||
parser->parse(source);
|
||||
XMBElementList animations=child.getChildNodes();
|
||||
|
||||
// Check how many errors
|
||||
parseOK = parser->getErrorCount() == 0;
|
||||
}
|
||||
if (parseOK) {
|
||||
// parsed successfully - grab our data
|
||||
DOMDocument *doc = parser->getDocument();
|
||||
DOMElement *element = doc->getDocumentElement();
|
||||
for (int j = 0; j < animations.Count; ++j) {
|
||||
XMBElement anim_element = animations.item(j);
|
||||
XMBAttributeList attributes=anim_element.getAttributes();
|
||||
if (attributes.Count) {
|
||||
Anim anim;
|
||||
|
||||
// root_name should be Object
|
||||
CStr root_name = XMLTranscode( element->getNodeName() );
|
||||
anim.m_AnimName=tocstr(attributes.getNamedItem(at_name));
|
||||
anim.m_FileName=tocstr(attributes.getNamedItem(at_file));
|
||||
CStr16 speedstr=attributes.getNamedItem(at_speed);
|
||||
|
||||
// should have at least 3 children - Name, ModelName and TextureName
|
||||
DOMNodeList *children = element->getChildNodes();
|
||||
int numChildren=children->getLength();
|
||||
for (int i=0; i<numChildren; ++i) {
|
||||
// Get node
|
||||
DOMNode *child = children->item(i);
|
||||
anim.m_Speed=float(speedstr.ToInt())/100.0f;
|
||||
if (anim.m_Speed<=0.0) anim.m_Speed=1.0f;
|
||||
|
||||
// A child element
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// First get element and not node
|
||||
DOMElement *child_element = (DOMElement*)child;
|
||||
|
||||
CStr element_name = XMLTranscode( child_element->getNodeName() );
|
||||
DOMNode *value_node= child_element->getChildNodes()->item(0);
|
||||
CStr element_value=value_node ? XMLTranscode(value_node->getNodeValue()) : "";
|
||||
|
||||
if (element_name==CStr("Name")) {
|
||||
m_Name=element_value;
|
||||
} else if (element_name==CStr("ModelName")) {
|
||||
m_ModelName=element_value;
|
||||
} else if (element_name==CStr("TextureName")) {
|
||||
m_TextureName=element_value;
|
||||
} else if (element_name==CStr("Animations")) {
|
||||
DOMNodeList* animations=(DOMNodeList*) child_element->getChildNodes();
|
||||
|
||||
for (uint j=0; j<animations->getLength(); ++j) {
|
||||
DOMElement *anim_element = (DOMElement*) animations->item(j);
|
||||
CStr element_name = XMLTranscode( anim_element->getNodeName() );
|
||||
DOMNamedNodeMap* attributes=anim_element->getAttributes();
|
||||
if (attributes) {
|
||||
Anim anim;
|
||||
|
||||
DOMNode *nameattr=attributes->getNamedItem(nametext);
|
||||
anim.m_AnimName=XMLTranscode(nameattr->getChildNodes()->item(0)->getNodeValue());
|
||||
DOMNode *fileattr=attributes->getNamedItem(filetext);
|
||||
anim.m_FileName=XMLTranscode(fileattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
DOMNode *speedattr=attributes->getNamedItem(speedtext);
|
||||
CStr speedstr=XMLTranscode(speedattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
anim.m_Speed=float(atoi((const char*) speedstr))/100.0f;
|
||||
if (anim.m_Speed<=0) anim.m_Speed=1.0f;
|
||||
|
||||
m_Animations.push_back(anim);
|
||||
}
|
||||
}
|
||||
} else if (element_name==CStr("Props")) {
|
||||
DOMNodeList* props=(DOMNodeList*) child_element->getChildNodes();
|
||||
|
||||
for (uint j=0; j<props->getLength(); ++j) {
|
||||
DOMElement *prop_element = (DOMElement*) props->item(j);
|
||||
CStr element_name = XMLTranscode( prop_element->getNodeName() );
|
||||
DOMNamedNodeMap* attributes=prop_element->getAttributes();
|
||||
if (attributes) {
|
||||
Prop prop;
|
||||
|
||||
DOMNode *nameattr=attributes->getNamedItem(attachpointtext);
|
||||
prop.m_PropPointName=XMLTranscode(nameattr->getChildNodes()->item(0)->getNodeValue());
|
||||
DOMNode *modelattr=attributes->getNamedItem(modeltext);
|
||||
prop.m_ModelName=XMLTranscode(modelattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
m_Props.push_back(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Animations.push_back(anim);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element_name == el_props)
|
||||
{
|
||||
XMBElementList props=child.getChildNodes();
|
||||
|
||||
XMLString::release(&attachpointtext);
|
||||
XMLString::release(&modeltext);
|
||||
XMLString::release(&nametext);
|
||||
XMLString::release(&filetext);
|
||||
XMLString::release(&speedtext);
|
||||
for (int j = 0; j < props.Count; ++j) {
|
||||
XMBElement prop_element = props.item(j);
|
||||
XMBAttributeList attributes=prop_element.getAttributes();
|
||||
if (attributes.Count) {
|
||||
Prop prop;
|
||||
|
||||
delete parser;
|
||||
delete errorHandler;
|
||||
delete entityResolver;
|
||||
prop.m_PropPointName=tocstr(attributes.getNamedItem(at_attachpoint));
|
||||
prop.m_ModelName=tocstr(attributes.getNamedItem(at_model));
|
||||
|
||||
m_Props.push_back(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parseOK;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool CObjectEntry::Save(const char* filename)
|
||||
{
|
||||
FILE* fp=fopen(filename,"w");
|
||||
|
49
source/lib/crc32.cpp
Executable file
49
source/lib/crc32.cpp
Executable file
@ -0,0 +1,49 @@
|
||||
// $Id: crc32.cpp,v 1.1 2004/07/08 15:21:21 philip Exp $
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
// CRC32, based on code copied from anywhere on the internet.
|
||||
// Find a thousand possible sources at
|
||||
// http://www.google.com/search?q=0xEDB88320L
|
||||
|
||||
unsigned long crc_table[256];
|
||||
|
||||
int generate_table()
|
||||
{
|
||||
unsigned long crc;
|
||||
int i, j;
|
||||
|
||||
const unsigned long poly = 0xEDB88320L; // magic
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
crc = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ poly;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
crc_table[i] = crc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned long crc32_calculate(char* data, int len)
|
||||
{
|
||||
// Only calculate the table once
|
||||
static int _temp = generate_table();
|
||||
|
||||
unsigned long crc;
|
||||
|
||||
crc = ~0;
|
||||
while (len)
|
||||
{
|
||||
crc = (crc>>8) ^ crc_table[ (crc^*data) & 0xff ];
|
||||
--len; ++data;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
4
source/lib/crc32.h
Executable file
4
source/lib/crc32.h
Executable file
@ -0,0 +1,4 @@
|
||||
// $Id: crc32.h,v 1.1 2004/07/08 15:21:21 philip Exp $
|
||||
|
||||
// I don't think this really needs any documentation
|
||||
unsigned long crc32_calculate(char* data, int len);
|
@ -37,22 +37,6 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
|
||||
#include <xercesc/sax/InputSource.hpp>
|
||||
#include <xercesc/sax/EntityResolver.hpp>
|
||||
#include <xercesc/util/BinMemInputStream.hpp>
|
||||
|
||||
#include <xercesc/sax/SAXParseException.hpp>
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
#include <xercesc/sax/ErrorHandler.hpp>
|
||||
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
|
||||
// Nicer memory leak reporting in MSVC:
|
||||
// (You've got to include all STL headers first to avoid lots of errors,
|
||||
// so make sure they're in the list above and you compile with PCH)
|
||||
|
@ -38,17 +38,16 @@
|
||||
#include "EntityHandles.h"
|
||||
#include "EntityManager.h"
|
||||
#include "PathfindEngine.h"
|
||||
#include "XML.h"
|
||||
|
||||
#include "scripting/JSInterface_Entity.h"
|
||||
#include "scripting/JSInterface_BaseEntity.h"
|
||||
#include "scripting/JSInterface_Vector3D.h"
|
||||
#include "gui/scripting/JSInterface_IGUIObject.h"
|
||||
#include "gui/scripting/JSInterface_GUITypes.h"
|
||||
|
||||
#include "ConfigDB.h"
|
||||
#include "CLogger.h"
|
||||
|
||||
|
||||
|
||||
#ifndef NO_GUI
|
||||
#include "gui/GUI.h"
|
||||
#endif
|
||||
@ -548,14 +547,8 @@ void ParseArgs(int argc, char* argv[])
|
||||
|
||||
|
||||
|
||||
|
||||
static void psInit()
|
||||
{
|
||||
// start up Xerces - only needs to be done once (unless locale changes mid-game, for
|
||||
// some reason), not on every XML file load; multiple initialization calls are ok, though,
|
||||
// provided there are a matching number of XMLPlatformUtils::Terminate calls
|
||||
XMLPlatformUtils::Initialize();
|
||||
|
||||
g_Font_Console = unifont_load("fonts/console");
|
||||
g_Font_Misc = unifont_load("fonts/verdana16");
|
||||
|
||||
@ -566,9 +559,11 @@ static void psInit()
|
||||
#ifndef NO_GUI
|
||||
// GUI uses VFS, so this must come after VFS init.
|
||||
g_GUI.Initialize();
|
||||
g_GUI.LoadXMLFile("gui/styles.xml");
|
||||
g_GUI.LoadXMLFile("gui/hello.xml");
|
||||
g_GUI.LoadXMLFile("gui/sprite1.xml");
|
||||
|
||||
g_GUI.LoadXMLFile("gui/test/styles.xml");
|
||||
g_GUI.LoadXMLFile("gui/test/hello.xml");
|
||||
g_GUI.LoadXMLFile("gui/test/sprite1.xml");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -582,15 +577,14 @@ static void psShutdown()
|
||||
|
||||
delete g_Console;
|
||||
|
||||
// close down Xerces
|
||||
XMLPlatformUtils::Terminate();
|
||||
// close down Xerces if it was loaded
|
||||
CXeromyces::Terminate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern u64 PREVTSC;
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
u64 TSC=rdtsc();
|
||||
debug_out(
|
||||
@ -600,6 +594,7 @@ debug_out(
|
||||
PREVTSC=TSC;
|
||||
#endif
|
||||
|
||||
|
||||
const int ERR_MSG_SIZE = 1000;
|
||||
wchar_t err_msg[ERR_MSG_SIZE];
|
||||
|
||||
@ -613,6 +608,13 @@ PREVTSC=TSC;
|
||||
// Create the scripting host. This needs to be done before the GUI is created.
|
||||
new ScriptingHost;
|
||||
|
||||
// Register the JavaScript interfaces with the runtime
|
||||
JSI_Entity::init();
|
||||
JSI_BaseEntity::init();
|
||||
JSI_IGUIObject::init();
|
||||
JSI_GUITypes::init();
|
||||
JSI_Vector3D::init();
|
||||
|
||||
detect();
|
||||
|
||||
// init SDL
|
||||
@ -729,11 +731,6 @@ PREVTSC=CURTSC;
|
||||
|
||||
g_EntityTemplateCollection.loadTemplates();
|
||||
|
||||
// Register the JavaScript interfaces with the runtime
|
||||
JSI_Entity::init();
|
||||
// JSI_BaseEntity::init(); // janwas: commented this out to avoid crash in JS_DestroyContext
|
||||
JSI_Vector3D::init();
|
||||
|
||||
// if no map name specified, load test01.pmp (for convenience during
|
||||
// development. that means loading no map at all is currently impossible.
|
||||
// is that a problem?
|
||||
@ -833,7 +830,6 @@ PREVTSC=CURTSC;
|
||||
// ugly, but necessary. these are one-shot events, have to be reset.
|
||||
mouseButtons[SDL_BUTTON_WHEELUP] = false;
|
||||
mouseButtons[SDL_BUTTON_WHEELDOWN] = false;
|
||||
|
||||
in_get_events();
|
||||
|
||||
float TimeSinceLastFrame = (float)(time1-time0);
|
||||
@ -862,6 +858,8 @@ PREVTSC=CURTSC;
|
||||
if (g_FixedFrameTiming && frameCount==100) quit=true;
|
||||
} // main loop, while(!quit)
|
||||
|
||||
psShutdown(); // Must delete g_GUI before g_ScriptingHost
|
||||
|
||||
delete &g_ScriptingHost;
|
||||
delete &g_Pathfinder;
|
||||
delete &g_EntityManager;
|
||||
@ -880,8 +878,6 @@ PREVTSC=CURTSC;
|
||||
|
||||
delete &g_ConfigDB;
|
||||
|
||||
psShutdown();
|
||||
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,8 +22,11 @@
|
||||
#ifndef _XercesVFS_H
|
||||
#define _XercesVFS_H
|
||||
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
// Temporarily undefine new, because the Xerces headers don't like it
|
||||
#ifdef HAVE_DEBUGALLOC
|
||||
# undef new
|
||||
#endif
|
||||
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
|
||||
@ -32,12 +35,13 @@
|
||||
#include <xercesc/util/BinMemInputStream.hpp>
|
||||
|
||||
#include <xercesc/sax/SAXParseException.hpp>
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
#include <xercesc/sax/ErrorHandler.hpp>
|
||||
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
|
||||
#ifdef HAVE_DEBUGALLOC
|
||||
# define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#include "lib/crc32.h"
|
||||
|
||||
#include "res/h_mgr.h"
|
||||
#include "lib.h"
|
||||
@ -73,6 +77,9 @@ public:
|
||||
// returns 0 if successful, -1 on failure
|
||||
int OpenFile(const char *path);
|
||||
|
||||
// Calculate the CRC32 checksum of the file's contents
|
||||
unsigned long CRC32() { return crc32_calculate((char*)m_pBuffer, (int)m_BufferSize); }
|
||||
|
||||
virtual BinInputStream *makeStream() const;
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "precompiled.h"
|
||||
#undef new // if it was redefined for leak detection, since xerces doesn't like it
|
||||
|
||||
#include "XML.h"
|
||||
|
||||
#undef new // if it was redefined for leak detection, since xerces doesn't like it
|
||||
|
||||
#include "CStr.h"
|
||||
#include "CLogger.h"
|
||||
#include "posix.h" // ptrdiff_t
|
||||
|
@ -22,10 +22,6 @@ gee@pyro.nu
|
||||
|
||||
#include "XML.h"
|
||||
|
||||
//#include <xercesc/util/XercesDefs.hpp>
|
||||
//#include <xercesc/sax/ErrorHandler.hpp>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
|
250
source/ps/XeroXMB.cpp
Executable file
250
source/ps/XeroXMB.cpp
Executable file
@ -0,0 +1,250 @@
|
||||
// $Id: XeroXMB.cpp,v 1.1 2004/07/08 15:21:42 philip Exp $
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Xeromyces.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
const int HeaderMagic = 0x30424D58; // = "XMB0" (little-endian)
|
||||
const char* HeaderMagicStr = "XMB0";
|
||||
|
||||
// Warning: May contain traces of pointer abuse
|
||||
|
||||
void XMBFile::Initialise(char* FileData)
|
||||
{
|
||||
m_Pointer = FileData;
|
||||
int Header = *(int*)m_Pointer; m_Pointer += 4;
|
||||
assert(Header == HeaderMagic && "Invalid XMB header!");
|
||||
|
||||
int Checksum = *(int*)m_Pointer; m_Pointer += 4;
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef XERO_USEMAP
|
||||
// Build a std::map of all the names->ids
|
||||
int ElementNameCount = *(int*)m_Pointer; m_Pointer += 4;
|
||||
for (i = 0; i < ElementNameCount; ++i)
|
||||
m_ElementNames[ReadZStr()] = i;
|
||||
|
||||
int AttributeNameCount = *(int*)m_Pointer; m_Pointer += 4;
|
||||
for (i = 0; i < AttributeNameCount; ++i)
|
||||
m_AttributeNames[ReadZStr()] = i;
|
||||
#else
|
||||
// Ignore all the names for now, and skip over them
|
||||
// (remembering the position of the first)
|
||||
m_ElementNameCount = *(int*)m_Pointer; m_Pointer += 4;
|
||||
m_ElementPointer = m_Pointer;
|
||||
for (i = 0; i < m_ElementNameCount; ++i)
|
||||
m_Pointer += 4 + *(int*)m_Pointer; // skip over the string
|
||||
|
||||
m_AttributeNameCount = *(int*)m_Pointer; m_Pointer += 4;
|
||||
m_AttributePointer = m_Pointer;
|
||||
for (i = 0; i < m_AttributeNameCount; ++i)
|
||||
m_Pointer += 4 + *(int*)m_Pointer; // skip over the string
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
std::wstring XMBFile::ReadZStr()
|
||||
{
|
||||
int Length = *(int*)m_Pointer;
|
||||
m_Pointer += 4;
|
||||
std::wstring String ((wchar_t*)m_Pointer);
|
||||
m_Pointer += Length;
|
||||
return String;
|
||||
}
|
||||
|
||||
XMBElement XMBFile::getRoot()
|
||||
{
|
||||
return XMBElement(m_Pointer);
|
||||
}
|
||||
|
||||
|
||||
#ifdef XERO_USEMAP
|
||||
|
||||
int XMBFile::getElementID(const wchar_t* Name)
|
||||
{
|
||||
return m_ElementNames[Name];
|
||||
}
|
||||
|
||||
int XMBFile::getAttributeID(const wchar_t* Name)
|
||||
{
|
||||
return m_AttributeNames[Name];
|
||||
}
|
||||
|
||||
#else // #ifdef XERO_USEMAP
|
||||
|
||||
int XMBFile::getElementID(const wchar_t* Name)
|
||||
{
|
||||
char* Pos = m_ElementPointer;
|
||||
|
||||
int len = ((int)wcslen(Name)+1)<<1; // count bytes, including null terminator
|
||||
|
||||
// Loop through each string to find a match
|
||||
for (int i = 0; i < m_ElementNameCount; ++i)
|
||||
{
|
||||
// See if this could be the right string, checking its
|
||||
// length and then its contents
|
||||
if (*(int*)Pos == len && memcmp((wchar_t*)(Pos+4), Name, len) == 0)
|
||||
return i;
|
||||
// If not, jump to the next string
|
||||
Pos += 4 + *(int*)Pos;
|
||||
}
|
||||
// Failed
|
||||
return -1;
|
||||
}
|
||||
|
||||
int XMBFile::getAttributeID(const wchar_t* Name)
|
||||
{
|
||||
char* Pos = m_AttributePointer;
|
||||
|
||||
int len = ((int)wcslen(Name)+1)<<1; // count bytes, including null terminator
|
||||
|
||||
// Loop through each string to find a match
|
||||
for (int i = 0; i < m_AttributeNameCount; ++i)
|
||||
{
|
||||
// See if this could be the right string, checking its
|
||||
// length and then its contents
|
||||
if (*(int*)Pos == len && memcmp((wchar_t*)(Pos+4), Name, len) == 0)
|
||||
return i;
|
||||
// If not, jump to the next string
|
||||
Pos += 4 + *(int*)Pos;
|
||||
}
|
||||
// Failed
|
||||
return -1;
|
||||
}
|
||||
#endif // #ifdef XERO_USEMAP / #else
|
||||
|
||||
|
||||
// Relatively inefficient, so only use when
|
||||
// laziness overcomes the need for speed
|
||||
std::wstring XMBFile::getElementString(const int ID)
|
||||
{
|
||||
char* Pos = m_ElementPointer;
|
||||
for (int i = 0; i < ID; ++i)
|
||||
Pos += 4 + *(int*)Pos;
|
||||
return std::wstring((wchar_t*)(Pos+4));
|
||||
}
|
||||
|
||||
std::wstring XMBFile::getAttributeString(const int ID)
|
||||
{
|
||||
char* Pos = m_AttributePointer;
|
||||
for (int i = 0; i < ID; ++i)
|
||||
Pos += 4 + *(int*)Pos;
|
||||
return std::wstring((wchar_t*)(Pos+4));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int XMBElement::getNodeName()
|
||||
{
|
||||
return *(int*)(m_Pointer + 4); // == ElementName
|
||||
}
|
||||
|
||||
XMBElementList XMBElement::getChildNodes()
|
||||
{
|
||||
return XMBElementList(
|
||||
m_Pointer + 20 + *(int*)(m_Pointer + 16), // == Children[]
|
||||
*(int*)(m_Pointer + 12) // == ChildCount
|
||||
);
|
||||
}
|
||||
|
||||
XMBAttributeList XMBElement::getAttributes()
|
||||
{
|
||||
return XMBAttributeList(
|
||||
m_Pointer + 24 + *(int*)(m_Pointer + 20), // == Attributes[]
|
||||
*(int*)(m_Pointer + 8) // == AttributeCount
|
||||
);
|
||||
}
|
||||
|
||||
std::wstring XMBElement::getText()
|
||||
{
|
||||
return std::wstring((wchar_t*)(m_Pointer + 24)); // == Text
|
||||
}
|
||||
|
||||
|
||||
XMBElement XMBElementList::item(const int id)
|
||||
{
|
||||
assert(id >= 0 && id < Count && "Element ID out of range");
|
||||
char* Pos;
|
||||
|
||||
// If access is sequential, don't bother scanning
|
||||
// through all the nodes to find the next one
|
||||
if (id == m_LastItemID+1)
|
||||
{
|
||||
Pos = m_LastPointer;
|
||||
Pos += *(int*)Pos; // skip over the last node
|
||||
}
|
||||
else
|
||||
{
|
||||
Pos = m_Pointer;
|
||||
// Skip over each preceding node
|
||||
for (int i=0; i<id; ++i)
|
||||
Pos += *(int*)Pos;
|
||||
}
|
||||
// Cache information about this node
|
||||
m_LastItemID = id;
|
||||
m_LastPointer = Pos;
|
||||
|
||||
return XMBElement(Pos);
|
||||
}
|
||||
|
||||
std::wstring XMBAttributeList::getNamedItem(const int AttributeName)
|
||||
{
|
||||
char* Pos = m_Pointer;
|
||||
|
||||
// Maybe not the cleverest algorithm, but it should be
|
||||
// fast enough with half a dozen attributes:
|
||||
for (int i = 0; i < Count; ++i)
|
||||
{
|
||||
if (*(int*)Pos == AttributeName)
|
||||
return std::wstring((wchar_t*)(Pos+8));
|
||||
Pos += 8 + *(int*)(Pos+4); // Skip over the string
|
||||
}
|
||||
|
||||
// Can't find attribute
|
||||
return std::wstring(L"");
|
||||
}
|
||||
|
||||
XMBAttribute XMBAttributeList::item(const int id)
|
||||
{
|
||||
assert(id >= 0 && id < Count && "Attribute ID out of range");
|
||||
char* Pos;
|
||||
|
||||
// If access is sequential, don't bother scanning through
|
||||
// all the nodes to find the right one
|
||||
if (id == m_LastItemID+1)
|
||||
{
|
||||
Pos = m_LastPointer;
|
||||
// Skip over the last attribute
|
||||
Pos += 8 + *(int*)(Pos+4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pos = m_Pointer;
|
||||
// Skip over each preceding attribute
|
||||
for (int i=0; i<id; ++i)
|
||||
Pos += 8 + *(int*)(Pos+4); // skip ID, length, and string data
|
||||
}
|
||||
// Cache information about this attribute
|
||||
m_LastItemID = id;
|
||||
m_LastPointer = Pos;
|
||||
|
||||
return XMBAttribute(*(int*)Pos, std::wstring((wchar_t*)(Pos+8)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Temporary hackiness. (Could CStr do automatic conversions?)
|
||||
CStr tocstr(std::wstring s)
|
||||
{
|
||||
size_t len = s.size();
|
||||
char* s2 = new char[len+1];
|
||||
const wchar_t* s1 = s.c_str();
|
||||
for (size_t i=0; i<=len; ++i)
|
||||
s2[i] = (char)s1[i];
|
||||
CStr r(s2);
|
||||
delete s2;
|
||||
return r;
|
||||
}
|
213
source/ps/XeroXMB.h
Executable file
213
source/ps/XeroXMB.h
Executable file
@ -0,0 +1,213 @@
|
||||
/* $Id: XeroXMB.h,v 1.1 2004/07/08 15:21:42 philip Exp $
|
||||
|
||||
Xeromyces - XMB reading library
|
||||
|
||||
Philip Taylor (philip@zaynar.demon.co.uk / @wildfiregames.com)
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Brief outline:
|
||||
|
||||
XMB is a binary representation of XML, with some limitations
|
||||
but much more efficiency (particularly for loading simple data
|
||||
classes that don't need much initialisation).
|
||||
|
||||
Main limitations:
|
||||
* Only handles UTF16 internally. (It's meant to be a feature, but
|
||||
can be detrimental if it's always being converted back to
|
||||
ASCII.)
|
||||
* Can't correctly handle mixed text/elements inside elements -
|
||||
"<div> <b> Text </b> </div>" and "<div> Te<b/>xt </div>" are
|
||||
considered identical.
|
||||
* Tries to avoid using strings - you usually have to load the
|
||||
numeric IDs and use them instead.
|
||||
* Case-sensitive (but converts all element/attribute names in
|
||||
the XML file to lowercase, so you only have to be careful in
|
||||
the code)
|
||||
|
||||
|
||||
Theoretical file structure:
|
||||
|
||||
XMB_File {
|
||||
char Header[4]; // because everyone has one; currently "XMB0"
|
||||
|
||||
int Checksum; // CRC32 of original XML file, to detect changes
|
||||
|
||||
int ElementNameCount;
|
||||
XMB_ZStr ElementNames[];
|
||||
|
||||
int AttributeNameCount;
|
||||
ZStr AttributeNames[];
|
||||
|
||||
XMB_Node Root;
|
||||
}
|
||||
|
||||
XMB_Node {
|
||||
0) int Length; // of entire struct, so it can be skipped over
|
||||
|
||||
4) int ElementName;
|
||||
|
||||
8) int AttributeCount;
|
||||
12) int ChildCount;
|
||||
|
||||
16) int ChildrenOffset; // == sizeof(Text)+sizeof(Attributes)
|
||||
20) ZStr Text;
|
||||
XMB_Attribute Attributes[];
|
||||
XMB_Node Children[];
|
||||
|
||||
}
|
||||
|
||||
XMB_Attribute {
|
||||
int Name;
|
||||
XMB_ZStr Value;
|
||||
}
|
||||
|
||||
XMB_ZStr {
|
||||
int Length; // in bytes (always a multiple of 2)
|
||||
wchar_t* Text; // null-terminated, UTF16-LE
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _XEROXMB_H_
|
||||
#define _XEROXMB_H_
|
||||
|
||||
// Define to use a std::map for name lookups rather than a linear search.
|
||||
// (The map is usually slower.)
|
||||
//#define XERO_USEMAP
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef XERO_USEMAP
|
||||
# include <map>
|
||||
#endif
|
||||
|
||||
// File headers, to make sure it doesn't try loading anything other than an XMB
|
||||
extern const int HeaderMagic;
|
||||
extern const char* HeaderMagicStr;
|
||||
|
||||
class XMBElement;
|
||||
class XMBElementList;
|
||||
class XMBAttributeList;
|
||||
|
||||
|
||||
class XMBFile
|
||||
{
|
||||
public:
|
||||
|
||||
XMBFile() : m_Pointer(NULL) {};
|
||||
|
||||
// Initialise from the contents of an XMB file.
|
||||
// FileData must remain allocated and unchanged while
|
||||
// the XMBFile is being used.
|
||||
void Initialise(char* FileData);
|
||||
|
||||
// Returns the root element
|
||||
XMBElement getRoot();
|
||||
|
||||
|
||||
// Returns internal ID for a given element/attribute string.
|
||||
// Use getElementID(L"name") to get a wchar_t*
|
||||
int getElementID(const wchar_t* Name);
|
||||
int getAttributeID(const wchar_t* Name);
|
||||
|
||||
// For lazy people (e.g. me) when speed isn't vital:
|
||||
|
||||
// Returns element/attribute string for a given internal ID
|
||||
std::wstring getElementString(const int ID);
|
||||
std::wstring getAttributeString(const int ID);
|
||||
|
||||
private:
|
||||
char* m_Pointer;
|
||||
|
||||
#ifdef XERO_USEMAP
|
||||
std::map<std::wstring, int> m_ElementNames;
|
||||
std::map<std::wstring, int> m_AttributeNames;
|
||||
#else
|
||||
int m_ElementNameCount;
|
||||
int m_AttributeNameCount;
|
||||
char* m_ElementPointer;
|
||||
char* m_AttributePointer;
|
||||
#endif
|
||||
|
||||
std::wstring ReadZStr();
|
||||
};
|
||||
|
||||
class XMBElement
|
||||
{
|
||||
public:
|
||||
XMBElement(char* offset)
|
||||
: m_Pointer(offset) {}
|
||||
|
||||
int getNodeName(); // == ElementName
|
||||
XMBElementList getChildNodes();
|
||||
XMBAttributeList getAttributes();
|
||||
std::wstring getText();
|
||||
|
||||
private:
|
||||
// Pointer to the start of the node
|
||||
char* m_Pointer;
|
||||
};
|
||||
|
||||
class XMBElementList
|
||||
{
|
||||
public:
|
||||
XMBElementList(char* offset, int count)
|
||||
: Count(count),
|
||||
m_Pointer(offset),
|
||||
m_LastItemID(-2) {} // use -2 because it isn't x-1 where x is a non-negative integer
|
||||
|
||||
XMBElement item(const int id); // returns Children[id]
|
||||
|
||||
int Count;
|
||||
|
||||
private:
|
||||
char* m_Pointer;
|
||||
|
||||
// For optimised sequential access:
|
||||
int m_LastItemID;
|
||||
char* m_LastPointer;
|
||||
};
|
||||
|
||||
|
||||
struct XMBAttribute
|
||||
{
|
||||
XMBAttribute(int name, std::wstring value)
|
||||
: Name(name), Value(value) {};
|
||||
|
||||
int Name;
|
||||
std::wstring Value;
|
||||
};
|
||||
|
||||
class XMBAttributeList
|
||||
{
|
||||
public:
|
||||
XMBAttributeList(char* offset, int count)
|
||||
: Count(count), m_Pointer(offset) {};
|
||||
|
||||
// Get the attribute value directly (unlike Xerces)
|
||||
std::wstring getNamedItem(const int AttributeName);
|
||||
|
||||
// Returns an attribute by position in the list
|
||||
XMBAttribute item(const int id);
|
||||
|
||||
int Count;
|
||||
|
||||
private:
|
||||
// Pointer to start of attribute list
|
||||
char* m_Pointer;
|
||||
|
||||
// For optimised sequential access:
|
||||
int m_LastItemID;
|
||||
char* m_LastPointer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#include "ps/CStr.h"
|
||||
CStr tocstr(std::wstring s);
|
||||
|
||||
#endif // _XEROXMB_H_
|
463
source/ps/Xeromyces.cpp
Executable file
463
source/ps/Xeromyces.cpp
Executable file
@ -0,0 +1,463 @@
|
||||
// $Id: Xeromyces.cpp,v 1.1 2004/07/08 15:21:42 philip Exp $
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#include "ps/Xeromyces.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "lib/res/file.h"
|
||||
|
||||
// Because I (and Xerces) don't like these being redefined by wposix.h:
|
||||
#ifdef HAVE_PCH
|
||||
# undef read
|
||||
# undef write
|
||||
#endif
|
||||
|
||||
#include "XML.h"
|
||||
|
||||
// For Xerces headers:
|
||||
#ifdef HAVE_DEBUGALLOC
|
||||
# undef new
|
||||
#endif
|
||||
|
||||
// The converter uses SAX2, so it should [theoretically]
|
||||
// be fairly easy to swap Xerces for something else (if desired)
|
||||
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
|
||||
// Reenable better memory-leak messages
|
||||
#ifdef HAVE_DEBUGALLOC
|
||||
# define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
|
||||
int CXeromyces::XercesLoaded = 0; // for once-only initialisation
|
||||
|
||||
|
||||
// Slightly nasty fwrite/fseek/ftell style thing
|
||||
class membuffer
|
||||
{
|
||||
public:
|
||||
membuffer()
|
||||
{
|
||||
buffer = (char*)malloc(bufferinc);
|
||||
assert(buffer);
|
||||
allocated = bufferinc;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
~membuffer()
|
||||
{
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void write(void* data, int size)
|
||||
{
|
||||
while (length + size >= allocated) grow();
|
||||
memcpy(&buffer[length], data, size);
|
||||
length += size;
|
||||
}
|
||||
|
||||
void write(void* data, int size, int offset)
|
||||
{
|
||||
assert(offset >= 0 && offset+size <= length);
|
||||
memcpy(&buffer[offset], data, size);
|
||||
}
|
||||
|
||||
int tell()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
char* steal_buffer()
|
||||
{
|
||||
char* ret = buffer;
|
||||
buffer = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* buffer;
|
||||
int length;
|
||||
private:
|
||||
int allocated;
|
||||
static const int bufferinc = 1024;
|
||||
void grow()
|
||||
{
|
||||
allocated += bufferinc;
|
||||
buffer = (char*)realloc(buffer, allocated);
|
||||
assert(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
// Convenient storage for the internal tree
|
||||
typedef struct {
|
||||
std::wstring name;
|
||||
std::wstring value;
|
||||
} XMLAttribute;
|
||||
|
||||
typedef struct XMLElement {
|
||||
std::wstring name;
|
||||
std::wstring text;
|
||||
std::vector<XMLElement*> childs;
|
||||
std::vector<XMLAttribute*> attrs;
|
||||
} XMLElement;
|
||||
|
||||
class XeroHandler : public DefaultHandler
|
||||
{
|
||||
public:
|
||||
// SAX2 event handlers:
|
||||
virtual void startDocument();
|
||||
virtual void endDocument();
|
||||
virtual void startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const Attributes& attrs);
|
||||
virtual void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname);
|
||||
virtual void characters(const XMLCh* const chars, const unsigned int length);
|
||||
|
||||
// Non-SAX2 stuff, used for storing the
|
||||
// parsed data and constructing the XMB:
|
||||
|
||||
void CreateXMB(unsigned long crc);
|
||||
membuffer buffer;
|
||||
private:
|
||||
std::set<std::wstring> ElementNames;
|
||||
std::set<std::wstring> AttributeNames;
|
||||
XMLElement* Root;
|
||||
XMLElement* CurrentElement;
|
||||
std::stack<XMLElement*> ElementStack;
|
||||
|
||||
std::map<std::wstring, int> ElementID;
|
||||
std::map<std::wstring, int> AttributeID;
|
||||
|
||||
void OutputElement(XMLElement* el);
|
||||
};
|
||||
|
||||
|
||||
|
||||
CXeromyces::CXeromyces()
|
||||
: XMBFileHandle(0), XMBBuffer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CXeromyces::~CXeromyces() {
|
||||
|
||||
if (XMBFileHandle)
|
||||
{
|
||||
// If it was read from a file, close it
|
||||
vfs_unmap(XMBFileHandle);
|
||||
vfs_close(XMBFileHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it was converted from a XML directly into memory,
|
||||
// free that memory buffer
|
||||
free(XMBBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CXeromyces::Terminate()
|
||||
{
|
||||
if (XercesLoaded)
|
||||
{
|
||||
XMLPlatformUtils::Terminate();
|
||||
XercesLoaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CXeromyces::Load(const char* filename)
|
||||
{
|
||||
// HACK: This is only done so early because CVFSInputSource
|
||||
// requires XMLTranscode. It would preferably not be done until
|
||||
// we actually need Xerces.
|
||||
if (! XercesLoaded)
|
||||
{
|
||||
XMLPlatformUtils::Initialize();
|
||||
XercesLoaded = 1;
|
||||
}
|
||||
|
||||
|
||||
CVFSInputSource source;
|
||||
if (source.OpenFile(filename))
|
||||
{
|
||||
LOG(ERROR, "CXeromyces: Failed to load XML file '%s'", filename);
|
||||
throw "Failed to load XML file";
|
||||
}
|
||||
unsigned long XMLChecksum = source.CRC32();
|
||||
|
||||
// Check whether the XMB file needs to be regenerated:
|
||||
|
||||
// Generate the XMB's filename
|
||||
CStr filenameXMB = filename;
|
||||
filenameXMB[(int)filenameXMB.Length()-1] = 'b';
|
||||
|
||||
// HACK: Check whether the XMB exists (in a rather unpleasant way)
|
||||
char path[VFS_MAX_PATH];
|
||||
vfs_realpath(filename, path); // can't get the XMB's VFS path because it doesn't exist
|
||||
path[strlen(path)-1] = 'b';
|
||||
bool fileExists = false;
|
||||
{
|
||||
FILE* f = fopen(path, "r");
|
||||
if (f)
|
||||
{
|
||||
fileExists = true;
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the entire file, with the assumption that usually it's
|
||||
// going to be valid and will then be passed to XMBFile().
|
||||
if (fileExists && ReadXMBFile(filenameXMB.c_str(), true, XMLChecksum))
|
||||
return;
|
||||
|
||||
|
||||
// XMB isn't up to date with the XML, so rebuild it:
|
||||
|
||||
|
||||
SAX2XMLReader* Parser = XMLReaderFactory::createXMLReader();
|
||||
|
||||
// Enable validation
|
||||
Parser->setFeature(L"http://xml.org/sax/features/validation", true);
|
||||
Parser->setFeature(L"http://apache.org/xml/features/validation/dynamic", true);
|
||||
|
||||
XeroHandler handler;
|
||||
Parser->setContentHandler(&handler);
|
||||
|
||||
CXercesErrorHandler errorHandler;
|
||||
Parser->setErrorHandler(&errorHandler);
|
||||
|
||||
CVFSEntityResolver entityResolver(filename);
|
||||
Parser->setEntityResolver(&entityResolver);
|
||||
|
||||
// Build a tree inside handler
|
||||
Parser->parse(source);
|
||||
|
||||
// (It's horribly inefficient doing SAX2->tree then tree->XMB,
|
||||
// but the XML->XMB conversion should be done very rarely
|
||||
// anyway. If it's ever needed, the XMB writing can be done
|
||||
// directly from inside the SAX2 event handlers, although that's
|
||||
// a little more complex)
|
||||
|
||||
delete Parser;
|
||||
|
||||
// Convert the data structures into the XMB format
|
||||
handler.CreateXMB(XMLChecksum);
|
||||
|
||||
// Save the file to disk, so it can be loaded quickly next time
|
||||
vfs_uncached_store(filenameXMB, handler.buffer.buffer, handler.buffer.length);
|
||||
|
||||
XMBBuffer = handler.buffer.steal_buffer();
|
||||
|
||||
Initialise(XMBBuffer);
|
||||
}
|
||||
|
||||
bool CXeromyces::ReadXMBFile(const char* filename, bool CheckCRC, unsigned long CRC)
|
||||
{
|
||||
Handle file = vfs_open(filename);
|
||||
if (file <= 0)
|
||||
{
|
||||
LOG(ERROR, "CXeromyces: file '%s' couldn't be opened (vfs_open: %lld)\n", filename, file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* buffer;
|
||||
size_t bufferSize;
|
||||
int err;
|
||||
if ( (err=vfs_map(file, 0, buffer, bufferSize)) )
|
||||
{
|
||||
LOG(ERROR, "CXeromyces: file '%s' couldn't be read (vfs_map: %d)\n", filename, err);
|
||||
vfs_close(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(bufferSize >= 42 && "Invalid XMB file"); // 42 bytes is the smallest possible XMB. (Well, okay, 50 bytes is the smallest, but it was 42 the first time I counted, and 42 is a much nicer number.)
|
||||
assert(*(int*)buffer == HeaderMagic && "Invalid XMB file header");
|
||||
|
||||
if (CheckCRC)
|
||||
{
|
||||
unsigned long fileCRC = *((unsigned long*)buffer + 1); // read the second four-byte number
|
||||
if (CRC != fileCRC)
|
||||
{
|
||||
// Checksums don't match; have to regenerate from the XML
|
||||
vfs_unmap(file);
|
||||
vfs_close(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the Handle so it can be closed later
|
||||
XMBFileHandle = file;
|
||||
|
||||
// Set up the XMBFile
|
||||
Initialise((char*)buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void XeroHandler::startDocument()
|
||||
{
|
||||
Root = new XMLElement;
|
||||
ElementStack.push(Root);
|
||||
}
|
||||
|
||||
void XeroHandler::endDocument()
|
||||
{
|
||||
}
|
||||
|
||||
std::wstring lowercase(std::wstring a)
|
||||
{
|
||||
std::wstring b;
|
||||
b.resize(a.length());
|
||||
for (size_t i = 0; i < a.length(); ++i)
|
||||
b[i] = towlower(a[i]);
|
||||
return b;
|
||||
}
|
||||
|
||||
void XeroHandler::startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const Attributes& attrs)
|
||||
{
|
||||
std::wstring elementName = lowercase(localname);
|
||||
ElementNames.insert(elementName);
|
||||
|
||||
// Create a new element
|
||||
XMLElement* e = new XMLElement;
|
||||
e->name = elementName;
|
||||
|
||||
// Store all the attributes in the new element
|
||||
for (unsigned int i = 0; i < attrs.getLength(); ++i)
|
||||
{
|
||||
std::wstring attrName = lowercase(attrs.getLocalName(i));
|
||||
AttributeNames.insert(attrName);
|
||||
XMLAttribute* a = new XMLAttribute;
|
||||
a->name = attrName;
|
||||
a->value = attrs.getValue(i);
|
||||
e->attrs.push_back(a);
|
||||
}
|
||||
|
||||
// Add the element to its parent
|
||||
ElementStack.top()->childs.push_back(e);
|
||||
|
||||
// Set as parent of following elements
|
||||
ElementStack.push(e);
|
||||
}
|
||||
|
||||
void XeroHandler::endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname)
|
||||
{
|
||||
ElementStack.pop();
|
||||
}
|
||||
|
||||
void XeroHandler::characters(const XMLCh* const chars, const unsigned int length)
|
||||
{
|
||||
ElementStack.top()->text += chars;
|
||||
}
|
||||
|
||||
|
||||
void XeroHandler::CreateXMB(unsigned long crc)
|
||||
{
|
||||
// Header
|
||||
buffer.write((void*)HeaderMagicStr, 4);
|
||||
|
||||
// Checksum
|
||||
buffer.write(&crc, 4);
|
||||
|
||||
std::set<std::wstring>::iterator it;
|
||||
int i;
|
||||
|
||||
// Element names
|
||||
i = 0;
|
||||
int ElementCount = (int)ElementNames.size();
|
||||
buffer.write(&ElementCount, 4);
|
||||
for (it = ElementNames.begin(); it != ElementNames.end(); ++it)
|
||||
{
|
||||
int TextLen = 2*((int)it->length()+1);
|
||||
buffer.write(&TextLen, 4);
|
||||
buffer.write((void*)it->c_str(), TextLen);
|
||||
ElementID[*it] = i++;
|
||||
}
|
||||
|
||||
// Attribute names
|
||||
i = 0;
|
||||
int AttributeCount = (int)AttributeNames.size();
|
||||
buffer.write(&AttributeCount, 4);
|
||||
for (it = AttributeNames.begin(); it != AttributeNames.end(); ++it)
|
||||
{
|
||||
int TextLen = 2*((int)it->length()+1);
|
||||
buffer.write(&TextLen, 4);
|
||||
buffer.write((void*)it->c_str(), TextLen);
|
||||
AttributeID[*it] = i++;
|
||||
}
|
||||
|
||||
// All the XML contents must be surrounded by a single element
|
||||
assert(Root->childs.size() == 1);
|
||||
|
||||
OutputElement(Root->childs[0]);
|
||||
delete Root;
|
||||
}
|
||||
|
||||
// Writes a whole element (recursively if it has children) into the buffer,
|
||||
// and also frees all the memory that has been allocated for that element.
|
||||
void XeroHandler::OutputElement(XMLElement* el)
|
||||
{
|
||||
// Filled in later with the length of the element
|
||||
int Pos_Length = buffer.tell();
|
||||
buffer.write("????", 4);
|
||||
|
||||
int NameID = ElementID[el->name];
|
||||
buffer.write(&NameID, 4);
|
||||
|
||||
int AttrCount = (int)el->attrs.size();
|
||||
buffer.write(&AttrCount, 4);
|
||||
|
||||
int ChildCount = (int)el->childs.size();
|
||||
buffer.write(&ChildCount, 4);
|
||||
|
||||
// Filled in later with the offset to the list of child elements
|
||||
int Pos_ChildrenOffset = buffer.tell();
|
||||
buffer.write("????", 4);
|
||||
|
||||
// Trim excess whitespace
|
||||
std::wstring whitespace = L" \t\r\n";
|
||||
size_t first = el->text.find_first_not_of(whitespace);
|
||||
if (first == -1) // entirely whitespace
|
||||
el->text = L"";
|
||||
else
|
||||
{
|
||||
size_t last = el->text.find_last_not_of(whitespace);
|
||||
el->text = el->text.substr(first, 1+last-first);
|
||||
}
|
||||
// Output text, prefixed by length in bytes
|
||||
int TextLen = 2*((int)el->text.length()+1);
|
||||
buffer.write(&TextLen, 4);
|
||||
buffer.write((void*)el->text.c_str(), TextLen);
|
||||
|
||||
for (int i = 0; i < AttrCount; ++i)
|
||||
{
|
||||
int AttrName = AttributeID[el->attrs[i]->name];
|
||||
buffer.write(&AttrName, 4);
|
||||
|
||||
int AttrLen = 2*((int)el->attrs[i]->value.length()+1);
|
||||
buffer.write(&AttrLen, 4);
|
||||
buffer.write((void*)el->attrs[i]->value.c_str(), AttrLen);
|
||||
|
||||
// Free each attribute as soon as it's been dealt with
|
||||
delete el->attrs[i];
|
||||
}
|
||||
|
||||
// Go back and fill in the child-element offset
|
||||
int ChildrenOffset = buffer.tell() - (Pos_ChildrenOffset+4);
|
||||
buffer.write(&ChildrenOffset, 4, Pos_ChildrenOffset);
|
||||
|
||||
for (int i = 0; i < ChildCount; ++i)
|
||||
OutputElement(el->childs[i]);
|
||||
|
||||
// Go back and fill in the length
|
||||
int Length = buffer.tell() - Pos_Length;
|
||||
buffer.write(&Length, 4, Pos_Length);
|
||||
|
||||
// Tidy up the parser's mess
|
||||
delete el;
|
||||
}
|
46
source/ps/Xeromyces.h
Executable file
46
source/ps/Xeromyces.h
Executable file
@ -0,0 +1,46 @@
|
||||
/* $Id: Xeromyces.h,v 1.1 2004/07/08 15:21:42 philip Exp $
|
||||
|
||||
Xeromyces file-loading interface.
|
||||
Automatically creates and caches relatively
|
||||
efficient binary representations of XML files.
|
||||
|
||||
- Philip Taylor (philip@zaynar.demon.co.uk / @wildfiregames.com)
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _XEROMYCES_H_
|
||||
#define _XEROMYCES_H_
|
||||
|
||||
#include "ps/XeroXMB.h"
|
||||
|
||||
#include "lib/res/vfs.h"
|
||||
|
||||
class CXeromyces : public XMBFile
|
||||
{
|
||||
public:
|
||||
CXeromyces();
|
||||
~CXeromyces();
|
||||
|
||||
// Load from an XML file (with invisible XMB caching).
|
||||
// Throws a const char* if stuff breaks.
|
||||
void Load(const char* filename);
|
||||
|
||||
// Call once when shutting down the program.
|
||||
static void Terminate();
|
||||
|
||||
// Get the XMBFile after having called Load
|
||||
// XMBFile* GetXMB() { assert(XMB); return XMB; }
|
||||
|
||||
|
||||
private:
|
||||
bool ReadXMBFile(const char* filename, bool CheckCRC, unsigned long CRC);
|
||||
|
||||
XMBFile* XMB;
|
||||
Handle XMBFileHandle; // if it's being read from disk
|
||||
char* XMBBuffer; // if it's being read from RAM
|
||||
|
||||
static int XercesLoaded; // for once-only initialisation
|
||||
};
|
||||
|
||||
|
||||
#endif // _XEROMYCES_H_
|
@ -1,14 +1,10 @@
|
||||
#include "precompiled.h"
|
||||
#undef new // if it was redefined for leak detection, since xerces doesn't like it
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "CStr.h"
|
||||
|
||||
#include "XML.h"
|
||||
|
||||
// automatically use namespace ..
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
#include "ps/Xeromyces.h"
|
||||
|
||||
CBaseEntity::CBaseEntity()
|
||||
{
|
||||
@ -32,125 +28,98 @@ CBaseEntity::~CBaseEntity()
|
||||
|
||||
bool CBaseEntity::loadXML( CStr filename )
|
||||
{
|
||||
bool parseOK = false;
|
||||
|
||||
// Initialize XML library
|
||||
XMLPlatformUtils::Initialize();
|
||||
CXeromyces XeroFile;
|
||||
try
|
||||
{
|
||||
// Create parser instance
|
||||
XercesDOMParser *parser = new XercesDOMParser();
|
||||
|
||||
// Setup parser
|
||||
parser->setValidationScheme(XercesDOMParser::Val_Auto);
|
||||
parser->setDoNamespaces(false);
|
||||
parser->setDoSchema(false);
|
||||
parser->setCreateEntityReferenceNodes(false);
|
||||
|
||||
// Set customized error handler
|
||||
CXercesErrorHandler *errorHandler = new CXercesErrorHandler();
|
||||
parser->setErrorHandler(errorHandler);
|
||||
|
||||
CVFSEntityResolver *entityResolver = new CVFSEntityResolver(filename);
|
||||
parser->setEntityResolver(entityResolver);
|
||||
|
||||
// Get main node
|
||||
CVFSInputSource source;
|
||||
parseOK=source.OpenFile(filename)==0;
|
||||
|
||||
if (parseOK)
|
||||
{
|
||||
// Parse file
|
||||
parser->parse(source);
|
||||
|
||||
// Check how many errors
|
||||
parseOK = parser->getErrorCount() == 0;
|
||||
}
|
||||
|
||||
if (parseOK) {
|
||||
// parsed successfully - grab our data
|
||||
DOMDocument *doc = parser->getDocument();
|
||||
DOMElement *element = doc->getDocumentElement();
|
||||
|
||||
// root_name should be Object
|
||||
CStr root_name = XMLTranscode( element->getNodeName() );
|
||||
|
||||
// should have at least 3 children - Name, ModelName and TextureName
|
||||
DOMNodeList *children = element->getChildNodes();
|
||||
int numChildren=children->getLength();
|
||||
for (int i=0; i<numChildren; ++i) {
|
||||
// Get node
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
// A child element
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// First get element and not node
|
||||
DOMElement *child_element = (DOMElement*)child;
|
||||
|
||||
CStr element_name = XMLTranscode( child_element->getNodeName() );
|
||||
DOMNode *value_node= child_element->getChildNodes()->item(0);
|
||||
CStr element_value=value_node ? XMLTranscode(value_node->getNodeValue()) : "";
|
||||
|
||||
if( element_name == CStr( "Name" ) )
|
||||
{
|
||||
m_name = element_value;
|
||||
}
|
||||
else if( element_name == CStr( "Actor" ) )
|
||||
{
|
||||
m_actorObject = g_ObjMan.FindObject( element_value );
|
||||
}
|
||||
else if( element_name == CStr( "Speed" ) )
|
||||
{
|
||||
m_speed = element_value.ToFloat();
|
||||
}
|
||||
else if( element_name == CStr( "TurningRadius" ) )
|
||||
{
|
||||
m_turningRadius = element_value.ToFloat();
|
||||
}
|
||||
else if( element_name == CStr( "Size" ) )
|
||||
{
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
CStr radius = XMLTranscode( child_element->getAttribute( (XMLCh*)L"Radius" ) );
|
||||
m_bound_circle->setRadius( radius.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_CIRCLE;
|
||||
}
|
||||
else if( element_name == CStr( "Footprint" ) )
|
||||
{
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
CStr width = XMLTranscode( child_element->getAttribute( (XMLCh*)L"Width" ) );
|
||||
CStr height = XMLTranscode( child_element->getAttribute( (XMLCh*)L"Height" ) );
|
||||
|
||||
m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_OABB;
|
||||
}
|
||||
else if( element_name == CStr( "BoundsOffset" ) )
|
||||
{
|
||||
CStr x = XMLTranscode( child_element->getAttribute( (XMLCh*)L"x" ) );
|
||||
CStr y = XMLTranscode( child_element->getAttribute( (XMLCh*)L"y" ) );
|
||||
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
|
||||
m_bound_circle->m_offset.x = x.ToFloat();
|
||||
m_bound_circle->m_offset.y = y.ToFloat();
|
||||
m_bound_box->m_offset.x = x.ToFloat();
|
||||
m_bound_box->m_offset.y = y.ToFloat();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
delete parser;
|
||||
delete errorHandler;
|
||||
delete entityResolver;
|
||||
XeroFile.Load(filename);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
XMLPlatformUtils::Terminate();
|
||||
|
||||
return parseOK;
|
||||
// Define all the elements and attributes used in the XML file
|
||||
#define EL(x) int el_##x = XeroFile.getElementID(L#x)
|
||||
#define AT(x) int at_##x = XeroFile.getAttributeID(L#x)
|
||||
EL(entity);
|
||||
EL(name);
|
||||
EL(actor);
|
||||
EL(speed);
|
||||
EL(turningradius);
|
||||
EL(size);
|
||||
EL(footprint);
|
||||
EL(boundsoffset);
|
||||
AT(radius);
|
||||
AT(width);
|
||||
AT(height);
|
||||
AT(x);
|
||||
AT(y);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
XMBElement Root = XeroFile.getRoot();
|
||||
|
||||
assert(Root.getNodeName() == el_entity);
|
||||
|
||||
XMBElementList RootChildren = Root.getChildNodes();
|
||||
|
||||
for (int i = 0; i < RootChildren.Count; ++i)
|
||||
{
|
||||
XMBElement Child = RootChildren.item(i);
|
||||
|
||||
int ChildName = Child.getNodeName();
|
||||
|
||||
if (ChildName == el_name)
|
||||
{
|
||||
m_name = tocstr(Child.getText());
|
||||
}
|
||||
else if (ChildName == el_actor)
|
||||
{
|
||||
m_actorObject = g_ObjMan.FindObject( tocstr(Child.getText()) );
|
||||
}
|
||||
else if (ChildName == el_speed)
|
||||
{
|
||||
m_speed = CStr16(Child.getText()).ToFloat();
|
||||
}
|
||||
else if (ChildName == el_turningradius)
|
||||
{
|
||||
m_turningRadius = CStr16(Child.getText()).ToFloat();
|
||||
}
|
||||
else if (ChildName == el_size)
|
||||
{
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
CStr16 radius = Child.getAttributes().getNamedItem(at_radius);
|
||||
m_bound_circle->setRadius( radius.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_CIRCLE;
|
||||
}
|
||||
else if (ChildName == el_footprint)
|
||||
{
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
CStr16 width = Child.getAttributes().getNamedItem(at_width);
|
||||
CStr16 height = Child.getAttributes().getNamedItem(at_height);
|
||||
|
||||
m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_OABB;
|
||||
}
|
||||
else if (ChildName == el_boundsoffset)
|
||||
{
|
||||
CStr16 x = Child.getAttributes().getNamedItem(at_x);
|
||||
CStr16 y = Child.getAttributes().getNamedItem(at_y);
|
||||
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
|
||||
m_bound_circle->m_offset.x = x.ToFloat();
|
||||
m_bound_circle->m_offset.y = y.ToFloat();
|
||||
m_bound_box->m_offset.x = x.ToFloat();
|
||||
m_bound_box->m_offset.y = y.ToFloat();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user