Init
This commit is contained in:
167
physx/source/fastxml/include/PsFastXml.h
Normal file
167
physx/source/fastxml/include/PsFastXml.h
Normal file
@ -0,0 +1,167 @@
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef PSFASTXML_PSFASTXML_H
|
||||
#define PSFASTXML_PSFASTXML_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h" // defines basic data types; modify for your platform as needed.
|
||||
#include "foundation/PxIO.h"
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "PsAllocator.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace shdfnd
|
||||
{
|
||||
|
||||
class FastXml
|
||||
{
|
||||
PX_NOCOPY(FastXml)
|
||||
|
||||
public:
|
||||
class AttributePairs
|
||||
{
|
||||
int argc;
|
||||
const char** argv;
|
||||
|
||||
public:
|
||||
AttributePairs() : argc(0), argv(NULL)
|
||||
{
|
||||
}
|
||||
AttributePairs(int c, const char** v) : argc(c), argv(v)
|
||||
{
|
||||
}
|
||||
|
||||
PX_INLINE int getNbAttr() const
|
||||
{
|
||||
return argc / 2;
|
||||
}
|
||||
|
||||
const char* getKey(uint32_t index) const
|
||||
{
|
||||
PX_ASSERT((index * 2) < uint32_t(argc));
|
||||
return argv[index * 2];
|
||||
}
|
||||
|
||||
const char* getValue(uint32_t index) const
|
||||
{
|
||||
PX_ASSERT((index * 2 + 1) < uint32_t(argc));
|
||||
return argv[index * 2 + 1];
|
||||
}
|
||||
|
||||
const char* get(const char* attr) const
|
||||
{
|
||||
int32_t count = argc / 2;
|
||||
for(int32_t i = 0; i < count; ++i)
|
||||
{
|
||||
const char* key = argv[i * 2], *value = argv[i * 2 + 1];
|
||||
if(strcmp(key, attr) == 0)
|
||||
return value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
/***
|
||||
* Callbacks to the user with the contents of the XML file properly digested.
|
||||
*/
|
||||
class Callback
|
||||
{
|
||||
public:
|
||||
virtual ~Callback()
|
||||
{
|
||||
}
|
||||
virtual bool processComment(const char* comment) = 0; // encountered a comment in the XML
|
||||
|
||||
// 'element' is the name of the element that is being closed.
|
||||
// depth is the recursion depth of this element.
|
||||
// Return true to continue processing the XML file.
|
||||
// Return false to stop processing the XML file; leaves the read pointer of the stream right after this close
|
||||
// tag.
|
||||
// The bool 'isError' indicates whether processing was stopped due to an error, or intentionally canceled early.
|
||||
virtual bool processClose(const char* element, uint32_t depth, bool& isError) = 0; // process the 'close'
|
||||
// indicator for a previously
|
||||
// encountered element
|
||||
|
||||
// return true to continue processing the XML document, false to skip.
|
||||
virtual bool processElement(const char* elementName, // name of the element
|
||||
const char* elementData, // element data, null if none
|
||||
const AttributePairs& attr, // attributes
|
||||
int32_t lineno) = 0; // line number in the source XML file
|
||||
|
||||
// process the XML declaration header
|
||||
virtual bool processXmlDeclaration(const AttributePairs&, // attributes
|
||||
const char* /*elementData*/, int32_t /*lineno*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processDoctype(const char* /*rootElement*/, // Root element tag
|
||||
const char* /*type*/, // SYSTEM or PUBLIC
|
||||
const char* /*fpi*/, // Formal Public Identifier
|
||||
const char* /*uri*/) // Path to schema file
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void* allocate(uint32_t size)
|
||||
{
|
||||
return getAllocator().allocate(size, "FastXml", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
virtual void deallocate(void* ptr)
|
||||
{
|
||||
getAllocator().deallocate(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
virtual bool processXml(PxInputData& buff, bool streamFromMemory = false) = 0;
|
||||
|
||||
virtual const char* getError(int32_t& lineno) = 0; // report the reason for a parsing error, and the line number
|
||||
// where it occurred.
|
||||
|
||||
FastXml()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void release(void) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~FastXml()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
FastXml* createFastXml(FastXml::Callback* iface);
|
||||
|
||||
} // shdfnd
|
||||
} // physx
|
||||
|
||||
#endif // PSFASTXML_PSFASTXML_H
|
||||
834
physx/source/fastxml/src/PsFastXml.cpp
Normal file
834
physx/source/fastxml/src/PsFastXml.cpp
Normal file
@ -0,0 +1,834 @@
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "foundation/PxFoundationConfig.h"
|
||||
#include "Ps.h"
|
||||
#include "PsFastXml.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <new>
|
||||
#include <ctype.h>
|
||||
|
||||
using namespace physx;
|
||||
|
||||
namespace
|
||||
{
|
||||
#define MIN_CLOSE_COUNT 2
|
||||
#define DEFAULT_READ_BUFFER_SIZE (16 * 1024)
|
||||
#define NUM_ENTITY 5
|
||||
|
||||
struct Entity
|
||||
{
|
||||
const char* str;
|
||||
unsigned int strLength;
|
||||
char chr;
|
||||
};
|
||||
|
||||
static const Entity entity[NUM_ENTITY] = {
|
||||
{ "<", 4, '<' }, { "&", 5, '&' }, { ">", 4, '>' }, { """, 6, '\"' }, { "'", 6, '\'' }
|
||||
};
|
||||
|
||||
class MyFastXml : public physx::shdfnd::FastXml
|
||||
{
|
||||
public:
|
||||
enum CharType
|
||||
{
|
||||
CT_DATA,
|
||||
CT_EOF,
|
||||
CT_SOFT,
|
||||
CT_END_OF_ELEMENT, // either a forward slash or a greater than symbol
|
||||
CT_END_OF_LINE
|
||||
};
|
||||
|
||||
MyFastXml(Callback* c)
|
||||
{
|
||||
mStreamFromMemory = true;
|
||||
mCallback = c;
|
||||
memset(mTypes, CT_DATA, sizeof(mTypes));
|
||||
mTypes[0] = CT_EOF;
|
||||
mTypes[uint8_t(' ')] = mTypes[uint8_t('\t')] = CT_SOFT;
|
||||
mTypes[uint8_t('/')] = mTypes[uint8_t('>')] = mTypes[uint8_t('?')] = CT_END_OF_ELEMENT;
|
||||
mTypes[uint8_t('\n')] = mTypes[uint8_t('\r')] = CT_END_OF_LINE;
|
||||
mError = 0;
|
||||
mStackIndex = 0;
|
||||
mFileBuf = NULL;
|
||||
mReadBufferEnd = NULL;
|
||||
mReadBuffer = NULL;
|
||||
mReadBufferSize = DEFAULT_READ_BUFFER_SIZE;
|
||||
mOpenCount = 0;
|
||||
mLastReadLoc = 0;
|
||||
for(uint32_t i = 0; i < (MAX_STACK + 1); i++)
|
||||
{
|
||||
mStack[i] = NULL;
|
||||
mStackAllocated[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
char* processClose(char c, const char* element, char* scan, int32_t argc, const char** argv,
|
||||
FastXml::Callback* iface, bool& isError)
|
||||
{
|
||||
AttributePairs attr(argc, argv);
|
||||
isError = true; // by default, if we return null it's due to an error.
|
||||
if(c == '/' || c == '?')
|
||||
{
|
||||
char* slash = const_cast<char*>(static_cast<const char*>(strchr(element, c)));
|
||||
if(slash)
|
||||
*slash = 0;
|
||||
|
||||
if(c == '?' && strcmp(element, "xml") == 0)
|
||||
{
|
||||
if(!iface->processXmlDeclaration(attr, 0, mLineNo))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!iface->processElement(element, 0, attr, mLineNo))
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pushElement(element);
|
||||
|
||||
const char* close = popElement();
|
||||
|
||||
if(!iface->processClose(close, mStackIndex, isError))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!slash)
|
||||
++scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan = skipNextData(scan);
|
||||
char* data = scan; // this is the data portion of the element, only copies memory if we encounter line feeds
|
||||
char* dest_data = 0;
|
||||
while(*scan && *scan != '<')
|
||||
{
|
||||
if(getCharType(scan) == CT_END_OF_LINE)
|
||||
{
|
||||
if(*scan == '\r')
|
||||
mLineNo++;
|
||||
dest_data = scan;
|
||||
*dest_data++ = ' '; // replace the linefeed with a space...
|
||||
scan = skipNextData(scan);
|
||||
while(*scan && *scan != '<')
|
||||
{
|
||||
if(getCharType(scan) == CT_END_OF_LINE)
|
||||
{
|
||||
if(*scan == '\r')
|
||||
mLineNo++;
|
||||
*dest_data++ = ' '; // replace the linefeed with a space...
|
||||
scan = skipNextData(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest_data++ = *scan++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if('&' == *scan)
|
||||
{
|
||||
dest_data = scan;
|
||||
while(*scan && *scan != '<')
|
||||
{
|
||||
if('&' == *scan)
|
||||
{
|
||||
if(*(scan + 1) && *(scan + 1) == '#' && *(scan + 2))
|
||||
{
|
||||
if(*(scan + 2) == 'x')
|
||||
{
|
||||
// Hexadecimal.
|
||||
if(!*(scan + 3))
|
||||
break;
|
||||
|
||||
char* q = scan + 3;
|
||||
q = strchr(q, ';');
|
||||
|
||||
if(!q || !*q)
|
||||
PX_ASSERT(0);
|
||||
|
||||
--q;
|
||||
char ch = char(*q > '9' ? (tolower(*q) - 'a' + 10) : *q - '0');
|
||||
if(*(--q) != tolower('x'))
|
||||
ch |= char(*q > '9' ? (tolower(*q) - 'a' + 10) : *q - '0') << 4;
|
||||
|
||||
*dest_data++ = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decimal.
|
||||
if(!*(scan + 2))
|
||||
break;
|
||||
|
||||
const char* q = scan + 2;
|
||||
q = strchr(q, ';');
|
||||
|
||||
if(!q || !*q)
|
||||
PX_ASSERT(0);
|
||||
|
||||
--q;
|
||||
char ch = *q - '0';
|
||||
if(*(--q) != '#')
|
||||
ch |= (*q - '0') * 10;
|
||||
|
||||
*dest_data++ = ch;
|
||||
}
|
||||
|
||||
char* start = scan;
|
||||
char* end = strchr(start, ';');
|
||||
if(end)
|
||||
{
|
||||
*end = 0;
|
||||
scan = end + 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_ENTITY; ++i)
|
||||
{
|
||||
if(strncmp(entity[i].str, scan, entity[i].strLength) == 0)
|
||||
{
|
||||
*dest_data++ = entity[i].chr;
|
||||
scan += entity[i].strLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest_data++ = *scan++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
++scan;
|
||||
}
|
||||
|
||||
if(*scan == '<')
|
||||
{
|
||||
if(scan[1] != '/')
|
||||
{
|
||||
PX_ASSERT(mOpenCount > 0);
|
||||
mOpenCount--;
|
||||
}
|
||||
if(dest_data)
|
||||
{
|
||||
*dest_data = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*scan = 0;
|
||||
}
|
||||
|
||||
scan++; // skip it..
|
||||
|
||||
if(*data == 0)
|
||||
data = 0;
|
||||
|
||||
if(!iface->processElement(element, data, attr, mLineNo))
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
return 0;
|
||||
}
|
||||
|
||||
pushElement(element);
|
||||
|
||||
// check for the comment use case...
|
||||
if(scan[0] == '!' && scan[1] == '-' && scan[2] == '-')
|
||||
{
|
||||
scan += 3;
|
||||
while(*scan && *scan == ' ')
|
||||
++scan;
|
||||
|
||||
char* comment = scan;
|
||||
char* comment_end = strstr(scan, "-->");
|
||||
if(comment_end)
|
||||
{
|
||||
*comment_end = 0;
|
||||
scan = comment_end + 3;
|
||||
if(!iface->processComment(comment))
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*scan == '/')
|
||||
{
|
||||
scan = processClose(scan, iface, isError);
|
||||
if(scan == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mError = "Data portion of an element wasn't terminated properly";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(mOpenCount < MIN_CLOSE_COUNT)
|
||||
{
|
||||
scan = readData(scan);
|
||||
}
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
char* processClose(char* scan, FastXml::Callback* iface, bool& isError)
|
||||
{
|
||||
const char* start = popElement(), *close = start;
|
||||
if(scan[1] != '>')
|
||||
{
|
||||
scan++;
|
||||
close = scan;
|
||||
while(*scan && *scan != '>')
|
||||
scan++;
|
||||
*scan = 0;
|
||||
}
|
||||
|
||||
if(0 != strcmp(start, close))
|
||||
{
|
||||
mError = "Open and closing tags do not match";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!iface->processClose(close, mStackIndex, isError))
|
||||
{
|
||||
// we need to set the read pointer!
|
||||
uint32_t offset = uint32_t(mReadBufferEnd - scan) - 1;
|
||||
uint32_t readLoc = mLastReadLoc - offset;
|
||||
mFileBuf->seek(readLoc);
|
||||
return NULL;
|
||||
}
|
||||
++scan;
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
virtual bool processXml(physx::PxInputData& fileBuf, bool streamFromMemory)
|
||||
{
|
||||
releaseMemory();
|
||||
mFileBuf = &fileBuf;
|
||||
mStreamFromMemory = streamFromMemory;
|
||||
return processXml(mCallback);
|
||||
}
|
||||
|
||||
// if we have finished processing the data we had pending..
|
||||
char* readData(char* scan)
|
||||
{
|
||||
for(uint32_t i = 0; i < (mStackIndex + 1); i++)
|
||||
{
|
||||
if(!mStackAllocated[i])
|
||||
{
|
||||
const char* text = mStack[i];
|
||||
if(text)
|
||||
{
|
||||
uint32_t tlen = uint32_t(strlen(text));
|
||||
mStack[i] = static_cast<const char*>(mCallback->allocate(tlen + 1));
|
||||
PxMemCopy(const_cast<void*>(static_cast<const void*>(mStack[i])), text, tlen + 1);
|
||||
mStackAllocated[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!mStreamFromMemory)
|
||||
{
|
||||
if(scan == NULL)
|
||||
{
|
||||
uint32_t seekLoc = mFileBuf->tell();
|
||||
mReadBufferSize = (mFileBuf->getLength() - seekLoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return scan;
|
||||
}
|
||||
}
|
||||
|
||||
if(mReadBuffer == NULL)
|
||||
{
|
||||
mReadBuffer = static_cast<char*>(mCallback->allocate(mReadBufferSize + 1));
|
||||
}
|
||||
uint32_t offset = 0;
|
||||
uint32_t readLen = mReadBufferSize;
|
||||
|
||||
if(scan)
|
||||
{
|
||||
offset = uint32_t(scan - mReadBuffer);
|
||||
uint32_t copyLen = mReadBufferSize - offset;
|
||||
if(copyLen)
|
||||
{
|
||||
PX_ASSERT(scan >= mReadBuffer);
|
||||
memmove(mReadBuffer, scan, copyLen);
|
||||
mReadBuffer[copyLen] = 0;
|
||||
readLen = mReadBufferSize - copyLen;
|
||||
}
|
||||
offset = copyLen;
|
||||
}
|
||||
|
||||
uint32_t readCount = mFileBuf->read(&mReadBuffer[offset], readLen);
|
||||
|
||||
while(readCount > 0)
|
||||
{
|
||||
|
||||
mReadBuffer[readCount + offset] = 0; // end of string terminator...
|
||||
mReadBufferEnd = &mReadBuffer[readCount + offset];
|
||||
|
||||
const char* scan_ = &mReadBuffer[offset];
|
||||
while(*scan_)
|
||||
{
|
||||
if(*scan_ == '<' && scan_[1] != '/')
|
||||
{
|
||||
mOpenCount++;
|
||||
}
|
||||
scan_++;
|
||||
}
|
||||
|
||||
if(mOpenCount < MIN_CLOSE_COUNT)
|
||||
{
|
||||
uint32_t oldSize = uint32_t(mReadBufferEnd - mReadBuffer);
|
||||
mReadBufferSize = mReadBufferSize * 2;
|
||||
char* oldReadBuffer = mReadBuffer;
|
||||
mReadBuffer = static_cast<char*>(mCallback->allocate(mReadBufferSize + 1));
|
||||
PxMemCopy(mReadBuffer, oldReadBuffer, oldSize);
|
||||
mCallback->deallocate(oldReadBuffer);
|
||||
offset = oldSize;
|
||||
uint32_t readSize = mReadBufferSize - oldSize;
|
||||
readCount = mFileBuf->read(&mReadBuffer[offset], readSize);
|
||||
if(readCount == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mLastReadLoc = mFileBuf->tell();
|
||||
|
||||
return mReadBuffer;
|
||||
}
|
||||
|
||||
bool processXml(FastXml::Callback* iface)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
const int MAX_ATTRIBUTE = 2048; // can't imagine having more than 2,048 attributes in a single element right?
|
||||
|
||||
mLineNo = 1;
|
||||
|
||||
char* element, *scan = readData(0);
|
||||
|
||||
while(*scan)
|
||||
{
|
||||
|
||||
scan = skipNextData(scan);
|
||||
|
||||
if(*scan == 0)
|
||||
break;
|
||||
|
||||
if(*scan == '<')
|
||||
{
|
||||
|
||||
if(scan[1] != '/')
|
||||
{
|
||||
PX_ASSERT(mOpenCount > 0);
|
||||
mOpenCount--;
|
||||
}
|
||||
scan++;
|
||||
|
||||
if(*scan == '?') // Allow xml declarations
|
||||
{
|
||||
scan++;
|
||||
}
|
||||
else if(scan[0] == '!' && scan[1] == '-' && scan[2] == '-')
|
||||
{
|
||||
scan += 3;
|
||||
while(*scan && *scan == ' ')
|
||||
scan++;
|
||||
char* comment = scan, *comment_end = strstr(scan, "-->");
|
||||
if(comment_end)
|
||||
{
|
||||
*comment_end = 0;
|
||||
scan = comment_end + 3;
|
||||
if(!iface->processComment(comment))
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(scan[0] == '!') // Allow doctype
|
||||
{
|
||||
scan++;
|
||||
|
||||
// DOCTYPE syntax differs from usual XML so we parse it here
|
||||
|
||||
// Read DOCTYPE
|
||||
const char* tag = "DOCTYPE";
|
||||
if(!strstr(scan, tag))
|
||||
{
|
||||
mError = "Invalid DOCTYPE";
|
||||
return false;
|
||||
}
|
||||
|
||||
scan += strlen(tag);
|
||||
|
||||
// Skip whites
|
||||
while(CT_SOFT == getCharType(scan))
|
||||
++scan;
|
||||
|
||||
// Read rootElement
|
||||
const char* rootElement = scan;
|
||||
while(CT_DATA == getCharType(scan))
|
||||
++scan;
|
||||
|
||||
char* endRootElement = scan;
|
||||
|
||||
// TODO: read remaining fields (fpi, uri, etc.)
|
||||
while(CT_END_OF_ELEMENT != getCharType(scan++))
|
||||
;
|
||||
|
||||
*endRootElement = 0;
|
||||
|
||||
if(!iface->processDoctype(rootElement, 0, 0, 0))
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
return false;
|
||||
}
|
||||
|
||||
continue; // Restart loop
|
||||
}
|
||||
}
|
||||
|
||||
if(*scan == '/')
|
||||
{
|
||||
bool isError;
|
||||
scan = processClose(scan, iface, isError);
|
||||
if(!scan)
|
||||
{
|
||||
if(isError)
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*scan == '?')
|
||||
scan++;
|
||||
element = scan;
|
||||
int32_t argc = 0;
|
||||
const char* argv[MAX_ATTRIBUTE];
|
||||
bool close;
|
||||
scan = nextSoftOrClose(scan, close);
|
||||
if(close)
|
||||
{
|
||||
char c = *(scan - 1);
|
||||
if(c != '?' && c != '/')
|
||||
{
|
||||
c = '>';
|
||||
}
|
||||
*scan++ = 0;
|
||||
bool isError;
|
||||
scan = processClose(c, element, scan, argc, argv, iface, isError);
|
||||
if(!scan)
|
||||
{
|
||||
if(isError)
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*scan == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
*scan = 0; // place a zero byte to indicate the end of the element name...
|
||||
scan++;
|
||||
|
||||
while(*scan)
|
||||
{
|
||||
scan = skipNextData(scan); // advance past any soft seperators (tab or space)
|
||||
|
||||
if(getCharType(scan) == CT_END_OF_ELEMENT)
|
||||
{
|
||||
char c = *scan++;
|
||||
if('?' == c)
|
||||
{
|
||||
if('>' != *scan) //?>
|
||||
{
|
||||
PX_ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
scan++;
|
||||
}
|
||||
bool isError;
|
||||
scan = processClose(c, element, scan, argc, argv, iface, isError);
|
||||
if(!scan)
|
||||
{
|
||||
if(isError)
|
||||
{
|
||||
mError = "User aborted the parsing process";
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argc >= MAX_ATTRIBUTE)
|
||||
{
|
||||
mError = "encountered too many attributes";
|
||||
return false;
|
||||
}
|
||||
argv[argc] = scan;
|
||||
scan = nextSep(scan); // scan up to a space, or an equal
|
||||
if(*scan)
|
||||
{
|
||||
if(*scan != '=')
|
||||
{
|
||||
*scan = 0;
|
||||
scan++;
|
||||
while(*scan && *scan != '=')
|
||||
scan++;
|
||||
if(*scan == '=')
|
||||
scan++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*scan = 0;
|
||||
scan++;
|
||||
}
|
||||
|
||||
if(*scan) // if not eof...
|
||||
{
|
||||
scan = skipNextData(scan);
|
||||
if(*scan == '"')
|
||||
{
|
||||
scan++;
|
||||
argc++;
|
||||
argv[argc] = scan;
|
||||
argc++;
|
||||
while(*scan && *scan != 34)
|
||||
scan++;
|
||||
if(*scan == '"')
|
||||
{
|
||||
*scan = 0;
|
||||
scan++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mError = "Failed to find closing quote for attribute";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// mError = "Expected quote to begin attribute";
|
||||
// return false;
|
||||
// PH: let's try to have a more graceful fallback
|
||||
argc--;
|
||||
while(*scan != '/' && *scan != '>' && *scan != 0)
|
||||
scan++;
|
||||
}
|
||||
}
|
||||
} // if( *scan )
|
||||
} // if ( mTypes[*scan]
|
||||
} // if( close )
|
||||
} // if( *scan == '/'
|
||||
} // while( *scan )
|
||||
}
|
||||
|
||||
if(mStackIndex)
|
||||
{
|
||||
mError = "Invalid file format";
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* getError(int32_t& lineno)
|
||||
{
|
||||
const char* ret = mError;
|
||||
lineno = mLineNo;
|
||||
mError = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void release(void)
|
||||
{
|
||||
Callback* c = mCallback; // get the user allocator interface
|
||||
MyFastXml* f = this; // cast the this pointer
|
||||
f->~MyFastXml(); // explicitely invoke the destructor for this class
|
||||
c->deallocate(f); // now free up the memory associated with it.
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~MyFastXml(void)
|
||||
{
|
||||
releaseMemory();
|
||||
}
|
||||
|
||||
PX_INLINE void releaseMemory(void)
|
||||
{
|
||||
mFileBuf = NULL;
|
||||
mCallback->deallocate(mReadBuffer);
|
||||
mReadBuffer = NULL;
|
||||
mStackIndex = 0;
|
||||
mReadBufferEnd = NULL;
|
||||
mOpenCount = 0;
|
||||
mLastReadLoc = 0;
|
||||
mError = NULL;
|
||||
for(uint32_t i = 0; i < (mStackIndex + 1); i++)
|
||||
{
|
||||
if(mStackAllocated[i])
|
||||
{
|
||||
mCallback->deallocate(const_cast<void*>(static_cast<const void*>(mStack[i])));
|
||||
mStackAllocated[i] = false;
|
||||
}
|
||||
mStack[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PX_INLINE CharType getCharType(char* scan) const
|
||||
{
|
||||
return mTypes[uint8_t(*scan)];
|
||||
}
|
||||
|
||||
PX_INLINE char* nextSoftOrClose(char* scan, bool& close)
|
||||
{
|
||||
while(*scan && getCharType(scan) != CT_SOFT && *scan != '>')
|
||||
scan++;
|
||||
close = *scan == '>';
|
||||
return scan;
|
||||
}
|
||||
|
||||
PX_INLINE char* nextSep(char* scan)
|
||||
{
|
||||
while(*scan && getCharType(scan) != CT_SOFT && *scan != '=')
|
||||
scan++;
|
||||
return scan;
|
||||
}
|
||||
|
||||
PX_INLINE char* skipNextData(char* scan)
|
||||
{
|
||||
// while we have data, and we encounter soft seperators or line feeds...
|
||||
while(*scan && (getCharType(scan) == CT_SOFT || getCharType(scan) == CT_END_OF_LINE))
|
||||
{
|
||||
if(*scan == '\n')
|
||||
mLineNo++;
|
||||
scan++;
|
||||
}
|
||||
return scan;
|
||||
}
|
||||
|
||||
void pushElement(const char* element)
|
||||
{
|
||||
PX_ASSERT(mStackIndex < uint32_t(MAX_STACK));
|
||||
if(mStackIndex < uint32_t(MAX_STACK))
|
||||
{
|
||||
if(mStackAllocated[mStackIndex])
|
||||
{
|
||||
mCallback->deallocate(const_cast<void*>(static_cast<const void*>(mStack[mStackIndex])));
|
||||
mStackAllocated[mStackIndex] = false;
|
||||
}
|
||||
mStack[mStackIndex++] = element;
|
||||
}
|
||||
}
|
||||
|
||||
const char* popElement(void)
|
||||
{
|
||||
PX_ASSERT(mStackIndex > 0);
|
||||
if(mStackAllocated[mStackIndex])
|
||||
{
|
||||
mCallback->deallocate(const_cast<void*>(static_cast<const void*>(mStack[mStackIndex])));
|
||||
mStackAllocated[mStackIndex] = false;
|
||||
}
|
||||
mStack[mStackIndex] = NULL;
|
||||
return mStackIndex ? mStack[--mStackIndex] : NULL;
|
||||
}
|
||||
|
||||
static const int MAX_STACK = 2048;
|
||||
|
||||
CharType mTypes[256];
|
||||
|
||||
physx::PxInputData* mFileBuf;
|
||||
|
||||
char* mReadBuffer;
|
||||
char* mReadBufferEnd;
|
||||
|
||||
uint32_t mOpenCount;
|
||||
uint32_t mReadBufferSize;
|
||||
uint32_t mLastReadLoc;
|
||||
|
||||
int32_t mLineNo;
|
||||
const char* mError;
|
||||
uint32_t mStackIndex;
|
||||
const char* mStack[MAX_STACK + 1];
|
||||
bool mStreamFromMemory;
|
||||
bool mStackAllocated[MAX_STACK + 1];
|
||||
Callback* mCallback;
|
||||
};
|
||||
}
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace shdfnd
|
||||
{
|
||||
|
||||
FastXml* createFastXml(FastXml::Callback* iface)
|
||||
{
|
||||
MyFastXml* m = static_cast<MyFastXml*>(iface->allocate(sizeof(MyFastXml)));
|
||||
if(m)
|
||||
{
|
||||
new (m) MyFastXml(iface);
|
||||
}
|
||||
return static_cast<FastXml*>(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user