Index: ps/trunk/source/ps/XercesErrorHandler.h =================================================================== --- ps/trunk/source/ps/XercesErrorHandler.h (revision 664) +++ ps/trunk/source/ps/XercesErrorHandler.h (revision 665) @@ -1,104 +1,100 @@ /* Xerces Error Handler for Prometheus (and the GUI) by Gustav Larsson gee@pyro.nu --Overview-- This is a class that that will let us output Xerces C++ Parser errors in our own Log or whatever, fit to Prometheus and foremost the GUI. --More info-- http://xml.apache.org/xerces-c/apiDocs/classErrorHandler.html */ #ifndef XercesErrorHandler_H #define XercesErrorHandler_H #include "XML.h" -//#include -//#include - - #include /** * @author Gustav Larsson * * Adapter function that catches Xerces Reading Exceptions * and lets us output them in Prometheus CLogFile. * * Used for all Xerces C++ Parser reading. * * @see http://xml.apache.org/xerces-c/apiDocs/classErrorHandler.html */ class CXercesErrorHandler : public XERCES_CPP_NAMESPACE::ErrorHandler { public: CXercesErrorHandler() : fSawErrors(false) {} ~CXercesErrorHandler() {} // ----------------------------------------------------------------------- /** @name Implementation of the error handler interface */ // ----------------------------------------------------------------------- //@{ /** * Sends warning exceptions here. */ void warning(const XERCES_CPP_NAMESPACE::SAXParseException& toCatch); /** * Sends error exceptions here. */ void error(const XERCES_CPP_NAMESPACE::SAXParseException& toCatch); /** * Sends fatal error exceptions here. */ void fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& toCatch); /** * Sets fSawError to false. */ void resetErrors(); //@} // ----------------------------------------------------------------------- /** @name Access Functions */ // ----------------------------------------------------------------------- //@{ /** * @return true if Errors Occured */ bool getSawErrors() const { return fSawErrors; } //@} private: // ----------------------------------------------------------------------- /** @name Private data members */ // ----------------------------------------------------------------------- //@{ /** * This is set if we get any errors, and is queryable via an access * function. Its used by the main code to suppress output if there are * errors. * * @see getSawErrors() */ bool fSawErrors; //@} }; #endif Index: ps/trunk/source/ps/Xeromyces.h =================================================================== --- ps/trunk/source/ps/Xeromyces.h (nonexistent) +++ ps/trunk/source/ps/Xeromyces.h (revision 665) @@ -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_ \ No newline at end of file Property changes on: ps/trunk/source/ps/Xeromyces.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +author date id revision \ No newline at end of property Index: ps/trunk/source/ps/XeroXMB.cpp =================================================================== --- ps/trunk/source/ps/XeroXMB.cpp (nonexistent) +++ ps/trunk/source/ps/XeroXMB.cpp (revision 665) @@ -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 + +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= 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, EXAMPLE : Simple usage: CVFSEntityResolver *entRes=new CVFSEntityResolver(filename); parser->setEntityResolver(entRes); CVFSInputSource src; if (src.OpenFile("this/is/a/vfs/path.xml")==0) parser->parse(src); delete entRes; The input source object should be kept alive as long as the parser is using its input stream (i.e. until the parse is complete). The same goes for the entity resolver. */ #ifndef _XercesVFS_H #define _XercesVFS_H -#include -#include +// Temporarily undefine new, because the Xerces headers don't like it +#ifdef HAVE_DEBUGALLOC +# undef new +#endif + #include #include #include #include #include #include -#include #include -#include - +#ifdef HAVE_DEBUGALLOC +# define new new(_NORMAL_BLOCK, __FILE__, __LINE__) +#endif +#include "lib/crc32.h" #include "res/h_mgr.h" #include "lib.h" #include "XercesErrorHandler.h" #include "CStr.h" XERCES_CPP_NAMESPACE_USE CStr XMLTranscode(const XMLCh *); XMLCh *XMLTranscode(const char *); /* CLASS : CVFSInputSource DESCRIPTION : Use instead of LocalFileInputSource to read XML files from VFS */ class CVFSInputSource: public InputSource { Handle m_hFile; void *m_pBuffer; size_t m_BufferSize; public: CVFSInputSource(): m_hFile(0), m_pBuffer(NULL), m_BufferSize(0) {} ~CVFSInputSource(); // Open a VFS path for XML parsing // 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; }; class CVFSEntityResolver: public EntityResolver { const char *m_DocName; public: virtual InputSource *resolveEntity( const XMLCh *const publicId, const XMLCh *const systemId); inline CVFSEntityResolver(const char *docName): m_DocName(docName) {} }; #endif // _XercesVFS_H Index: ps/trunk/source/ps/Xeromyces.cpp =================================================================== --- ps/trunk/source/ps/Xeromyces.cpp (nonexistent) +++ ps/trunk/source/ps/Xeromyces.cpp (revision 665) @@ -0,0 +1,463 @@ +// $Id: Xeromyces.cpp,v 1.1 2004/07/08 15:21:42 philip Exp $ + +#include "precompiled.h" + +#include +#include +#include +#include + +#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 +#include + +// 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 childs; + std::vector 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 ElementNames; + std::set AttributeNames; + XMLElement* Root; + XMLElement* CurrentElement; + std::stack ElementStack; + + std::map ElementID; + std::map 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::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; +} \ No newline at end of file Property changes on: ps/trunk/source/ps/Xeromyces.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +author date id revision \ No newline at end of property Index: ps/trunk/source/ps/XMLUtils.cpp =================================================================== --- ps/trunk/source/ps/XMLUtils.cpp (revision 664) +++ ps/trunk/source/ps/XMLUtils.cpp (revision 665) @@ -1,177 +1,179 @@ #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 #include "res/vfs.h" /* // but static Xerces => tons of warnings due to missing debug info, // and warnings about invalid pointers (conflicting CRT heaps?) in parser => allow for now #ifndef XERCES_STATIC_LIB #error "need to define XERCES_STATIC_LIB in project options (so that Xerces uses the same CRT as the other libs)" #endif */ #ifdef _MSC_VER # ifdef XERCES_STATIC_LIB # ifndef NDEBUG # pragma comment(lib, "xerces-c_2D-static.lib") # else # pragma comment(lib, "xerces-c_2D-static.lib") # endif // NDEBUG # else // XERCES_STATIC_LIB # ifndef NDEBUG # pragma comment(lib, "xerces-c_2D.lib") # else # pragma comment(lib, "xerces-c_2.lib") # endif // NDEBUG # endif // XERCES_STATIC_LIB #endif // _MSC_VER XERCES_CPP_NAMESPACE_USE CStr XMLTranscode(const XMLCh* xmltext) { char* str=XMLString::transcode((const XMLCh *)xmltext); CStr result(str); XMLString::release(&str); return result; } XMLCh *XMLTranscode(const char *str) { return XMLString::transcode(str); } int CVFSInputSource::OpenFile(const char *path) { debug_out("CVFSInputSource::OpenFile(): opening file %s.\n", path); m_hFile=vfs_open(path); if (m_hFile <= 0) { LOG(ERROR, "CVFSInputSource: file %s couldn't be opened (vfs_open: %lld)\n", path, m_hFile); return -1; } int err; if ((err=vfs_map(m_hFile, 0, m_pBuffer, m_BufferSize)) != 0) { LOG(ERROR, "CVFSInputSource: file %s couldn't be opened (vfs_map: %d)\n", path, err); vfs_close(m_hFile); m_hFile=0; return -1; } XMLCh *sysId=XMLString::transcode(path); setSystemId(sysId); XMLString::release(&sysId); return 0; } CVFSInputSource::~CVFSInputSource() { if (m_hFile > 0) { vfs_unmap(m_hFile); vfs_close(m_hFile); } } BinInputStream *CVFSInputSource::makeStream() const { if (m_hFile > 0) { return new BinMemInputStream((XMLByte *)m_pBuffer, (unsigned int)m_BufferSize, BinMemInputStream::BufOpt_Reference); } else return NULL; } #define IS_PATH_SEP(_chr) (_chr == '/' || _chr == '\\') // Return a pointer to the last path separator preceding *end, while not // going further back than *beginning const char *prevpathcomp(const char *end, const char *beginning) { do end--; while (end > beginning && !IS_PATH_SEP(*end)); return end; } InputSource *CVFSEntityResolver::resolveEntity(const XMLCh *const publicId, const XMLCh *const systemId) { CVFSInputSource *ret=new CVFSInputSource(); char *path=XMLString::transcode(systemId); char *orgpath=path; char abspath[VFS_MAX_PATH]; const char *end=strchr(m_DocName, '\0'); const char *orgend=end; if (IS_PATH_SEP(*path)) path++; else { // We know that we have a relative path here: // - Remove the file name // - If we have a ../ components - remove them and remove one component // off the end of the document path for each ../ component // - prefix of document path + suffix of input path => the VFS path // Remove the file name end=prevpathcomp(end, m_DocName); // Remove one path component for each opening ../ (or ..\) // Note that this loop will stop when all path components from the // document name have been stripped - the resulting path will be invalid, but // so was the input path. // Also note that this will not handle ../ path components in the middle of // the input path. while (strncmp(path, "..", 2) == 0 && IS_PATH_SEP(path[2]) && end > m_DocName) { end=prevpathcomp(end, m_DocName); path += 3; } // include one slash from prefix end++; const ptrdiff_t prefixlen=end-m_DocName; memcpy(abspath, m_DocName, prefixlen); strncpy(abspath+prefixlen, path, VFS_MAX_PATH-prefixlen); // strncpy might not have terminated, if path was too long abspath[VFS_MAX_PATH-1]=0; path=abspath; } LOG(NORMAL, "EntityResolver: path \"%s\" translated to \"%s\"", orgpath, path); char *pos=path; if ((pos=strchr(pos, '\\')) != NULL) { LOG(WARNING, "While resolving XML entities for %s: path %s [%s] contains non-portable path separator \\", m_DocName, orgpath, path); do *pos='/'; while ((pos=strchr(pos+1, '\\')) != NULL); } if (ret->OpenFile(path)!=0) { delete ret; ret=NULL; } XMLString::release(&orgpath); return ret; } Index: ps/trunk/source/ps/XeroXMB.h =================================================================== --- ps/trunk/source/ps/XeroXMB.h (nonexistent) +++ ps/trunk/source/ps/XeroXMB.h (revision 665) @@ -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 - + "
Text
" and "
Text
" 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 + +#ifdef XERO_USEMAP +# include +#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 m_ElementNames; + std::map 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_ Property changes on: ps/trunk/source/ps/XeroXMB.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +author date id revision \ No newline at end of property Index: ps/trunk/source/simulation/BaseEntity.cpp =================================================================== --- ps/trunk/source/simulation/BaseEntity.cpp (revision 664) +++ ps/trunk/source/simulation/BaseEntity.cpp (revision 665) @@ -1,156 +1,125 @@ #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() { m_base = NULL; m_base.associate( this, "super" ); m_name.associate( this, "name" ); m_speed.associate( this, "speed" ); m_turningRadius.associate( this, "turningRadius" ); m_bound_circle = NULL; m_bound_box = NULL; } CBaseEntity::~CBaseEntity() { if( m_bound_box ) delete( m_bound_box ); if( m_bound_circle ) delete( m_bound_circle ); } bool CBaseEntity::loadXML( CStr filename ) { - bool parseOK = false; + CXeromyces XeroFile; + try + { + XeroFile.Load(filename); + } + catch (...) + { + return false; + } + + // 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(); - // Initialize XML library - XMLPlatformUtils::Initialize(); + assert(Root.getNodeName() == el_entity); + + XMBElementList RootChildren = Root.getChildNodes(); + + for (int i = 0; i < RootChildren.Count; ++i) { - // Create parser instance - XercesDOMParser *parser = new XercesDOMParser(); + XMBElement Child = RootChildren.item(i); - // 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; iitem(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; - } - XMLPlatformUtils::Terminate(); + 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 parseOK; + return true; } Index: ps/trunk/source/graphics/ObjectEntry.cpp =================================================================== --- ps/trunk/source/graphics/ObjectEntry.cpp (revision 664) +++ ps/trunk/source/graphics/ObjectEntry.cpp (revision 665) @@ -1,310 +1,265 @@ #include "precompiled.h" -#undef new // if it was redefined for leak detection, since xerces doesn't like it #include "ObjectEntry.h" #include "ObjectManager.h" #include "Model.h" #include "ModelDef.h" #include "CLogger.h" #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) { m_IdleAnim=0; m_WalkAnim=0; m_DeathAnim=0; m_MeleeAnim=0; m_RangedAnim=0; } CObjectEntry::~CObjectEntry() { for (size_t i=0;iGetModelDef() : 0; // build filename CStr modelfilename("mods/official/"); modelfilename+=m_ModelName; // try and create a model CModelDef* modeldef; try { modeldef=CModelDef::Load((const char*) modelfilename); } catch (...) { LOG(ERROR, "CObjectEntry::BuildModel(): Model %s failed to load\n", modelfilename.c_str()); return false; } // create new Model m_Model=new CModel; m_Model->SetTexture((const char*) m_TextureName); m_Model->InitModel(modeldef); // calculate initial object space bounds, based on vertex positions m_Model->CalcObjectBounds(); // load animations for( uint t = 0; t < m_Animations.size(); t++ ) { if( m_Animations[t].m_FileName.Length() > 0 ) { CStr animfilename( "mods/official/" ); animfilename += m_Animations[t].m_FileName; m_Animations[t].m_AnimData = m_Model->BuildAnimation((const char*) animfilename,m_Animations[t].m_Speed); if( m_Animations[t].m_AnimName.LowerCase() == CStr( "idle" ) ) m_IdleAnim = m_Animations[t].m_AnimData; if( m_Animations[t].m_AnimName.LowerCase() == CStr( "walk" ) ) m_WalkAnim = m_Animations[t].m_AnimData; } else { // FIXME, RC - don't store invalid animations (possible?) m_Animations[t].m_AnimData=0; } } // start up idling m_Model->SetAnimation( m_IdleAnim ); // build props - TODO, RC - need to fix up bounds here for (uint p=0;pFindPropPoint((const char*) prop.m_PropPointName); if (proppoint) { CObjectEntry* oe=g_ObjMan.FindObject(prop.m_ModelName); if (oe) { // try and build model if we haven't already got it if (!oe->m_Model) oe->BuildModel(); if (oe->m_Model) { CModel* propmodel=oe->m_Model->Clone(); m_Model->AddProp(proppoint,propmodel); if (oe->m_WalkAnim) propmodel->SetAnimation(oe->m_WalkAnim); } else { LOG(ERROR,"Failed to build prop model \"%s\" on actor \"%s\"\n",(const char*) m_Name,(const char*) prop.m_ModelName); } } } else { LOG(ERROR,"Failed to matching prop point called \"%s\" in model \"%s\"\n", (const char*)prop.m_PropPointName, (const char*)modelfilename); } } // build world space bounds m_Model->CalcBounds(); // replace any units using old model to now use new model; also reprop models, if necessary const std::vector& units=g_UnitMan.GetUnits(); for (uint i=0;iGetModel(); if (unitmodel->GetModelDef()==oldmodel) { unitmodel->InitModel(m_Model->GetModelDef()); const std::vector& newprops=m_Model->GetProps(); for (uint j=0;jAddProp(newprops[j].m_Point,newprops[j].m_Model->Clone()); } } } // and were done with the old model .. delete oldmodel; return true; } CSkeletonAnim* CObjectEntry::GetNamedAnimation( CStr animationName ) { for( uint t = 0; t < m_Animations.size(); t++ ) { if( m_Animations[t].m_AnimName == animationName ) return( m_Animations[t].m_AnimData ); } return( NULL ); } bool CObjectEntry::Load(const char* filename) { - bool parseOK = false; - - // Initialize XML library + CXeromyces XeroFile; + try + { + XeroFile.Load(filename); + } + catch (...) { - 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"); - - // 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); - - // Push the CLogger to mark it's reading this file. - - // Get main node - CVFSInputSource source; - parseOK = source.OpenFile(filename) == 0; - if (parseOK) + return false; + } + + // 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 + + XMBElement root = XeroFile.getRoot(); + + XMBElementList children = root.getChildNodes(); + + for (int i = 0; i < children.Count; ++i) { + // Get node + XMBElement child = children.item(i); + + int element_name = child.getNodeName(); + CStr element_value=tocstr(child.getText()); + + 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(); - - // 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; iitem(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("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; jgetLength(); ++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; jgetLength(); ++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); - } - } - } + for (int j = 0; j < animations.Count; ++j) { + XMBElement anim_element = animations.item(j); + XMBAttributeList attributes=anim_element.getAttributes(); + if (attributes.Count) { + Anim anim; + + anim.m_AnimName=tocstr(attributes.getNamedItem(at_name)); + anim.m_FileName=tocstr(attributes.getNamedItem(at_file)); + CStr16 speedstr=attributes.getNamedItem(at_speed); + + anim.m_Speed=float(speedstr.ToInt())/100.0f; + if (anim.m_Speed<=0.0) anim.m_Speed=1.0f; + + m_Animations.push_back(anim); } } } + else if (element_name == el_props) + { + XMBElementList props=child.getChildNodes(); + + for (int j = 0; j < props.Count; ++j) { + XMBElement prop_element = props.item(j); + XMBAttributeList attributes=prop_element.getAttributes(); + if (attributes.Count) { + Prop prop; + + prop.m_PropPointName=tocstr(attributes.getNamedItem(at_attachpoint)); + prop.m_ModelName=tocstr(attributes.getNamedItem(at_model)); - XMLString::release(&attachpointtext); - XMLString::release(&modeltext); - XMLString::release(&nametext); - XMLString::release(&filetext); - XMLString::release(&speedtext); - - delete parser; - delete errorHandler; - delete entityResolver; + m_Props.push_back(prop); + } + } + } } - return parseOK; + return true; + } + bool CObjectEntry::Save(const char* filename) { FILE* fp=fopen(filename,"w"); if (!fp) return false; // write XML header fprintf(fp,"\n\n"); fprintf(fp,"\n\n"); // write the object itself fprintf(fp,"\n"); fprintf(fp,"\n"); fprintf(fp,"\t%s\n",(const char*) m_Name); fprintf(fp,"\t%s\n",(const char*) m_ModelName); fprintf(fp,"\t%s\n",(const char*) m_TextureName); if (m_Animations.size()>0) { fprintf(fp,"\t\n"); for (uint i=0;i \n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName); } fprintf(fp,"\t\n"); } fprintf(fp,"\n"); fclose(fp); return true; } Index: ps/trunk/source/main.cpp =================================================================== --- ps/trunk/source/main.cpp (revision 664) +++ ps/trunk/source/main.cpp (revision 665) @@ -1,887 +1,883 @@ #include "precompiled.h" #include #include #include #include // Alan: For some reason if this gets included after anything else some // compile time errors get thrown up todo with javascript internal typedefs #include "scripting/ScriptingHost.h" #include "sdl.h" #include "ogl.h" #include "detect.h" #include "timer.h" #include "input.h" #include "lib.h" #include "res/res.h" #include "res/file.h" #ifdef _M_IX86 #include "sysdep/ia32.h" #endif #include "ps/CConsole.h" #include "Config.h" #include "MapReader.h" #include "Terrain.h" #include "TextureManager.h" #include "ObjectManager.h" #include "SkeletonAnimManager.h" #include "Renderer.h" #include "Model.h" #include "UnitManager.h" #include "BaseEntityCollection.h" #include "Entity.h" #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 CConsole* g_Console = 0; extern int conInputHandler(const SDL_Event* ev); u32 game_ticks; bool keys[SDLK_LAST]; bool mouseButtons[5]; // Globals int g_xres, g_yres; int g_bpp; int g_freq; // flag to disable extended GL extensions until fix found - specifically, crashes // using VBOs on laptop Radeon cards static bool g_NoGLVBO=false; // flag to switch on shadows static bool g_Shadows=false; // flag to switch off pbuffers static bool g_NoPBuffer=true; // flag to switch on fixed frame timing (RC: I'm using this for profiling purposes) static bool g_FixedFrameTiming=false; static bool g_VSync = false; static bool g_EntGraph = false; static float g_Gamma = 1.0f; // mapfile to load or null for no map (and to use default terrain) static const char* g_MapFile=0; static Handle g_Font_Console; // for the console static Handle g_Font_Misc; // random font for miscellaneous things extern CCamera g_Camera; extern void terr_init(); extern void terr_update(float time); extern int terr_handler(const SDL_Event* ev); extern int allow_reload(); extern int dir_add_watch(const char* const dir, bool watch_subdirs); void Testing (void) { g_Console->InsertMessage(L"Testing Function Registration"); } void TestingUnicode (void) { // This looks really broken in my IDE's font g_Console->InsertMessage(L" Ai! laurië lantar lassi súrinen,"); g_Console->InsertMessage(L" yéni únótimë ve rámar aldaron!"); g_Console->InsertMessage(L" Yéni ve lintë yuldar avánier"); g_Console->InsertMessage(L" mi oromardi lissë-miruvóreva"); g_Console->InsertMessage(L" Andúnë pella, Vardo tellumar"); g_Console->InsertMessage(L" nu luini yassen tintilar i eleni"); g_Console->InsertMessage(L" ómaryo airetári-lírinen."); } static int write_sys_info() { get_gfx_info(); struct utsname un; uname(&un); FILE* const f = fopen("../logs/system_info.txt", "w"); if(!f) return -1; // .. OS fprintf(f, "%s %s (%s)\n", un.sysname, un.release, un.version); // .. CPU fprintf(f, "%s, %s", un.machine, cpu_type); if(cpus > 1) fprintf(f, " (x%d)", cpus); if(cpu_freq != 0.0f) { if(cpu_freq < 1e9) fprintf(f, ", %.2f MHz\n", cpu_freq*1e-6); else fprintf(f, ", %.2f GHz\n", cpu_freq*1e-9); } else fprintf(f, "\n"); // .. memory fprintf(f, "%lu MB RAM; %lu MB free\n", tot_mem/MB, avl_mem/MB); // .. graphics card fprintf(f, "%s\n", gfx_card); fprintf(f, "%s\n", gfx_drv_ver); fprintf(f, "%dx%d:%d@%d\n", g_xres, g_yres, g_bpp, g_freq); // .. network name / ips char hostname[100]; // possibly nodename != hostname if (gethostname(hostname, sizeof(hostname)) == 0) // make sure it succeeded { fprintf(f, "%s\n", hostname); hostent* host = gethostbyname(hostname); if(host) { struct in_addr** ips = (struct in_addr**)host->h_addr_list; for(int i = 0; ips && ips[i]; i++) fprintf(f, "%s ", inet_ntoa(*ips[i])); fprintf(f, "\n"); } } fclose(f); return 0; } // error before GUI is initialized: display message, and quit // TODO: localization static void display_startup_error(const wchar_t* msg) { const wchar_t* caption = L"0ad startup problem"; write_sys_info(); wdisplay_msg(caption, msg); exit(1); } // error before GUI is initialized: display message, and quit // TODO: localization static void display_startup_error(const char* msg) { const char* caption = "0ad startup problem"; write_sys_info(); display_msg(caption, msg); exit(1); } static int set_vmode(int w, int h, int bpp) { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if(!SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_FULLSCREEN)) return -1; glViewport(0, 0, w, h); #ifndef NO_GUI g_GUI.UpdateResolution(); #endif oglInit(); // required after each mode change return 0; } static void write_screenshot() { const size_t size = g_xres * g_yres * 3; void* img = malloc(size); glReadPixels(0, 0, g_xres, g_yres, GL_BGR_EXT, GL_UNSIGNED_BYTE, img); } bool active = true; static bool quit = false; // break out of main loop static int handler(const SDL_Event* ev) { int c; switch(ev->type) { case SDL_ACTIVE: active = ev->active.gain != 0; break; case SDL_KEYDOWN: c = ev->key.keysym.sym; keys[c] = true; switch(c) { case SDLK_ESCAPE: quit = true; break; case SDLK_PRINT: write_screenshot(); break; } break; case SDL_KEYUP: c = ev->key.keysym.sym; keys[c] = false; break; case SDL_MOUSEBUTTONDOWN: c = ev->button.button; if( c < 5 ) mouseButtons[c] = true; else debug_warn("SDL mouse button defs changed; fix mouseButton array def"); break; case SDL_MOUSEBUTTONUP: c = ev->button.button; if( c < 5 ) mouseButtons[c] = false; else debug_warn("SDL mouse button defs changed; fix mouseButton array def"); break; } return EV_PASS; } ////////////////////////////////////////////////////////////////////////////////////////////////// // RenderTerrain: iterate through all terrain patches and submit all patches in viewing frustum to // the renderer void RenderTerrain() { CFrustum frustum=g_Camera.GetFustum(); u32 patchesPerSide=g_Terrain.GetPatchesPerSide(); for (uint j=0; jGetBounds())) { g_Renderer.Submit(patch); } } } } ////////////////////////////////////////////////////////////////////////////////////////////////// // SubmitModelRecursive: recurse down given model, submitting it and all its descendents to the // renderer void SubmitModelRecursive(CModel* model) { g_Renderer.Submit(model); const std::vector& props=model->GetProps(); for (uint i=0;i& units=g_UnitMan.GetUnits(); for (uint i=0;iGetModel()->GetBounds())) { SubmitModelRecursive(units[i]->GetModel()); } } } ///////////////////////////////////////////////////////////////////////////////////////////// // RenderNoCull: render absolutely everything to a blank frame to force renderer // to load required assets void RenderNoCull() { g_Renderer.BeginFrame(); g_Renderer.SetCamera(g_Camera); uint i,j; const std::vector& units=g_UnitMan.GetUnits(); for (i=0;iGetModel()); } u32 patchesPerSide=g_Terrain.GetPatchesPerSide(); for (j=0; jRender(); // restore glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); g_Renderer.EndFrame(); } static void do_tick() { } ////////////////////////////////////////////////////////////////////////////////////////////// // UpdateWorld: update time dependent data in the world to account for changes over // the given time (in s) void UpdateWorld(float time) { const std::vector& units=g_UnitMan.GetUnits(); for (uint i=0;iGetModel()->Update(time); } g_EntityManager.updateAll( time ); } void ParseArgs(int argc, char* argv[]) { for (int i=1;im_String="true"; break; case 'n': if (strncmp(argv[i]+1,"novbo",5)==0) { g_ConfigDB.CreateValue(CFG_SYSTEM, "novbo") ->m_String="true"; } else if (strncmp(argv[i]+1,"nopbuffer",9)==0) { g_NoPBuffer=true; } break; case 'f': if (strncmp(argv[i]+1,"fixedframe",10)==0) { g_FixedFrameTiming=true; } break; case 's': if (strncmp(argv[i]+1,"shadows",7)==0) { g_ConfigDB.CreateValue(CFG_SYSTEM, "shadows") ->m_String="true"; } break; case 'x': if (strncmp(argv[i], "-xres=", 6)==0) { g_ConfigDB.CreateValue(CFG_SYSTEM, "xres") ->m_String=argv[i]+6; } break; case 'y': if (strncmp(argv[i], "-yres=", 6)==0) { g_ConfigDB.CreateValue(CFG_SYSTEM, "yres") ->m_String=argv[i]+6; } break; case 'c': if (strcmp(argv[i], "-conf") == 0) { if (argc-i >= 1) // At least one arg left { i++; char *arg=argv[i]; char *equ=strchr(arg, '='); if (equ) { *equ=0; g_ConfigDB.CreateValue(CFG_SYSTEM, arg) ->m_String=(equ+1); } } } break; } } } CConfigValue *val; if (val=g_ConfigDB.GetValue(CFG_SYSTEM, "xres")) val->GetInt(g_xres); if (val=g_ConfigDB.GetValue(CFG_SYSTEM, "yres")) val->GetInt(g_yres); if (val=g_ConfigDB.GetValue(CFG_SYSTEM, "vsync")) val->GetBool(g_VSync); if (val=g_ConfigDB.GetValue(CFG_SYSTEM, "novbo")) val->GetBool(g_NoGLVBO); if (val=g_ConfigDB.GetValue(CFG_SYSTEM, "shadows")) val->GetBool(g_Shadows); LOG(NORMAL, "g_x/yres is %dx%d\n", g_xres, g_yres); } - 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"); g_Console = new CConsole(0, g_yres-600.f, (float)g_xres, 600.f); g_Console->m_iFontHeight = unifont_linespacing(g_Font_Console); g_Console->m_iFontOffset = 9; #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 } static void psShutdown() { #ifndef NO_GUI g_GUI.Destroy(); delete &g_GUI; #endif 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( "----------------------------------------\n"\ "MAIN (elapsed = %f ms)\n"\ "----------------------------------------\n", (TSC-PREVTSC)/2e9*1e3); PREVTSC=TSC; #endif + const int ERR_MSG_SIZE = 1000; wchar_t err_msg[ERR_MSG_SIZE]; lib_init(); // set 24 bit (float) FPU precision for faster divides / sqrts #ifdef _M_IX86 _control87(_PC_24, _MCW_PC); #endif // 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 if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) < 0) { swprintf(err_msg, ERR_MSG_SIZE, L"SDL library initialization failed: %s\n", SDL_GetError()); display_startup_error(err_msg); } atexit(SDL_Quit); SDL_EnableUNICODE(1); // preferred video mode = current desktop settings // (command line params may override these) get_cur_vmode(&g_xres, &g_yres, &g_bpp, &g_freq); // set current directory to "$game_dir/data". // this is necessary because it is otherwise unknown, // especially if run from a shortcut / symlink. // // "../data" is relative to the executable (in "$game_dir/system"). // // rationale for data/ being root: untrusted scripts must not be // allowed to overwrite critical game (or worse, OS) files. // the VFS prevents any accesses to files above this directory. int err = file_rel_chdir(argv[0], "../data"); if(err < 0) { swprintf(err_msg, ERR_MSG_SIZE, L"error setting current directory.\n"\ L"argv[0] is probably incorrect. please start the game via command-line."); display_startup_error(err_msg); } new CConfigDB; g_ConfigDB.SetConfigFile(CFG_SYSTEM, false, "config/system.cfg"); g_ConfigDB.Reload(CFG_SYSTEM); g_ConfigDB.SetConfigFile(CFG_MOD, true, "config/mod.cfg"); // No point in reloading mod.cfg here - we haven't mounted mods yet g_ConfigDB.SetConfigFile(CFG_USER, true, "config/user.cfg"); // Same thing here; we haven't even started up yet - this will wait until // the profile dir is VFS mounted (or we will do a new SetConfigFile with // a generated profile path) ParseArgs(argc, argv); // GUI is notified in set_vmode, so this must come before that. #ifndef NO_GUI new CGUI; #endif if(set_vmode(g_xres, g_yres, 32) < 0) { swprintf(err_msg, ERR_MSG_SIZE, L"could not set %dx%d graphics mode: %s\n", g_xres, g_yres, SDL_GetError()); display_startup_error(err_msg); } write_sys_info(); if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine")) display_startup_error(L"required ARB_multitexture or ARB_texture_env_combine extension not available"); // enable/disable VSync // note: "GL_EXT_SWAP_CONTROL" is "historical" according to dox. if(oglExtAvail("WGL_EXT_swap_control")) wglSwapIntervalEXT(g_VSync? 1 : 0); if(SDL_SetGamma(g_Gamma, g_Gamma, g_Gamma) < 0) { debug_warn("SDL_SetGamma failed"); } vfs_mount("", "mods/official/", 0); #ifdef _MSC_VER u64 CURTSC=rdtsc(); debug_out( "----------------------------------------\n"\ "VFS ready (elapsed = %f ms)\n"\ "----------------------------------------\n", (CURTSC-PREVTSC)/2e9*1e3); PREVTSC=CURTSC; #endif psInit(); // create renderer new CRenderer; // set renderer options from command line options - NOVBO must be set before opening the renderer g_Renderer.SetOptionBool(CRenderer::OPT_NOVBO,g_NoGLVBO); g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS,g_Shadows); g_Renderer.SetOptionBool(CRenderer::OPT_NOPBUFFER,g_NoPBuffer); // create terrain related stuff new CTextureManager; // create actor related stuff new CSkeletonAnimManager; new CObjectManager; new CUnitManager; g_Renderer.Open(g_xres,g_yres,g_bpp); // terr_init loads a bunch of resources as well as setting up the terrain terr_init(); // This needs to be done after the renderer has loaded all its actors... new CBaseEntityCollection; new CEntityManager; new CPathfindEngine; 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? if(!g_MapFile) g_MapFile = "test01.pmp"; // load a map if we were given one if (g_MapFile) { CStr mapfilename("mods/official/maps/scenarios/"); mapfilename+=g_MapFile; try { CMapReader reader; reader.LoadMap(mapfilename); } catch (...) { char errmsg[256]; sprintf(errmsg, "Failed to load map %s\n", mapfilename.c_str()); display_startup_error(errmsg); } } // Initialize entities CMessage init_msg (CMessage::EMSG_INIT); g_EntityManager.dispatchAll(&init_msg); #ifndef NO_GUI in_add_handler(gui_handler); #endif in_add_handler(handler); in_add_handler(terr_handler); in_add_handler(conInputHandler); // render everything to a blank frame to force renderer to load everything RenderNoCull(); size_t frameCount=0; if (g_FixedFrameTiming) { #if 0 // TOPDOWN g_Camera.SetProjection(1.0f,10000.0f,DEGTORAD(90)); g_Camera.m_Orientation.SetIdentity(); g_Camera.m_Orientation.RotateX(DEGTORAD(90)); g_Camera.m_Orientation.Translate(CELL_SIZE*250*0.5, 250, CELL_SIZE*250*0.5); #else // std view g_Camera.SetProjection(1.0f,10000.0f,DEGTORAD(20)); g_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); g_Camera.m_Orientation.RotateY(DEGTORAD(-45)); g_Camera.m_Orientation.Translate(350, 350, -275); #endif g_Camera.UpdateFrustum(); } g_Console->RegisterFunc(Testing, L"Testing"); { wchar_t t[] = { 'T',0xE9,'s','t','i','n','g' , 0 }; g_Console->RegisterFunc(TestingUnicode, t); } #ifdef _MSC_VER { u64 CURTSC=rdtsc(); debug_out( "----------------------------------------\n"\ "READY (elapsed = %f ms)\n"\ "----------------------------------------\n", (CURTSC-PREVTSC)/2e9*1e3); PREVTSC=CURTSC; } #endif // fixed timestep main loop const double TICK_TIME = 30e-3; // [s] double time0 = get_time(); while(!quit) { res_reload_changed_files(); // TODO: limiter in case simulation can't keep up? #if 0 double time1 = get_time(); while((time1-time0) > TICK_TIME) { game_ticks++; in_get_events(); do_tick(); time0 += TICK_TIME; } #endif double time1 = get_time(); // 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); assert(TimeSinceLastFrame >= 0.0f); if(TimeSinceLastFrame > 0.0f) { UpdateWorld(TimeSinceLastFrame); if (!g_FixedFrameTiming) terr_update(float(TimeSinceLastFrame)); g_Console->Update(TimeSinceLastFrame); } if(active) { Render(); SDL_GL_SwapBuffers(); } // inactive; relinquish CPU for a little while // don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored else SDL_Delay(10); calc_fps(); time0=time1; frameCount++; 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; delete &g_EntityTemplateCollection; // destroy actor related stuff delete &g_UnitMan; delete &g_ObjMan; delete &g_SkelAnimMan; // destroy terrain related stuff delete &g_TexMan; // destroy renderer delete &g_Renderer; delete &g_ConfigDB; - psShutdown(); - exit(0); return 0; } Index: ps/trunk/source/lib/precompiled.h =================================================================== --- ps/trunk/source/lib/precompiled.h (revision 664) +++ ps/trunk/source/lib/precompiled.h (revision 665) @@ -1,71 +1,55 @@ // if precompiled headers are supported, include all headers we'd ever need // that don't often change. if not supported, include nothing (would actually // slow down the build, since unnecessary headers would be included). // hence, all files include precompiled.h and then all the headers they'd // normally lead => best build performance with or without PCH. #include "config.h" #ifdef _MSC_VER #pragma warning(disable:4996) // function is deprecated #pragma warning(disable:4786) // identifier truncated to 255 chars #endif #ifdef HAVE_PCH #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - // 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) #ifdef HAVE_DEBUGALLOC # include # include // Can't define _CRTDBG_MAP_ALLOC because it has a broken 'new', // so manually redefine the appropriate functions # define new new(_NORMAL_BLOCK, __FILE__, __LINE__) # define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) # define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) # define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) # define free(p) _free_dbg(p, _NORMAL_BLOCK) #endif // HAVE_DEBUGALLOC #endif // #ifdef HAVE_PCH Index: ps/trunk/source/lib/crc32.cpp =================================================================== --- ps/trunk/source/lib/crc32.cpp (nonexistent) +++ ps/trunk/source/lib/crc32.cpp (revision 665) @@ -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; +} Property changes on: ps/trunk/source/lib/crc32.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +author date id revision \ No newline at end of property Index: ps/trunk/source/lib/crc32.h =================================================================== --- ps/trunk/source/lib/crc32.h (nonexistent) +++ ps/trunk/source/lib/crc32.h (revision 665) @@ -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); Property changes on: ps/trunk/source/lib/crc32.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +author date id revision \ No newline at end of property