Initial release
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_ENABLE_XML_PARSER
|
||||
|
||||
#include "cstream.h"
|
||||
#include "icontentprovider.h"
|
||||
|
||||
/// @cond ignore
|
||||
#if VSTGUI_USE_SYSTEM_EXPAT
|
||||
#include <expat.h>
|
||||
#else
|
||||
#define XML_STATIC 1
|
||||
#define XML_NS 0
|
||||
#define XML_DTD 0
|
||||
#define XML_CONTEXT_BYTES 1024
|
||||
#define XML_LARGE_SIZE 1
|
||||
|
||||
#ifdef BYTEORDER
|
||||
#define OLD_BYTEORDER = BYTEORDER
|
||||
#undef BYTEORDER
|
||||
#endif
|
||||
|
||||
#if MAC && defined (__BIG_ENDIAN__)
|
||||
#define BYTEORDER 4321
|
||||
#else
|
||||
#define BYTEORDER 1234
|
||||
#endif
|
||||
#define HAVE_MEMMOVE
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Xml {
|
||||
#include "../thirdparty/expat/expat.h"
|
||||
}}
|
||||
#endif // VSTGUI_USE_SYSTEM_EXPAT
|
||||
|
||||
#include "xmlparser.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Xml {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Parser::Impl
|
||||
{
|
||||
XML_ParserStruct* parser {nullptr};
|
||||
IHandler* handler {nullptr};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void XMLCALL gStartElementHandler (void* userData, const char* name, const char** atts)
|
||||
{
|
||||
auto parser = static_cast<Parser*> (userData);
|
||||
IHandler* handler = parser ? parser->getHandler () : nullptr;
|
||||
if (handler)
|
||||
handler->startXmlElement (parser, name, atts);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void XMLCALL gEndElementHandler (void* userData, const char* name)
|
||||
{
|
||||
auto parser = static_cast<Parser*> (userData);
|
||||
IHandler* handler = parser ? parser->getHandler () : nullptr;
|
||||
if (handler)
|
||||
handler->endXmlElement (parser, name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void XMLCALL gCharacterDataHandler (void* userData, const char* s, int len)
|
||||
{
|
||||
auto parser = static_cast<Parser*> (userData);
|
||||
IHandler* handler = parser ? parser->getHandler () : nullptr;
|
||||
if (handler)
|
||||
handler->xmlCharData (parser, (const int8_t*)s, len);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void XMLCALL gCommentHandler (void* userData, const char* string)
|
||||
{
|
||||
auto parser = static_cast<Parser*> (userData);
|
||||
IHandler* handler = parser ? parser->getHandler () : nullptr;
|
||||
if (handler)
|
||||
handler->xmlComment (parser, string);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Parser::Parser ()
|
||||
{
|
||||
pImpl = std::unique_ptr<Impl> (new Impl ());
|
||||
pImpl->parser = XML_ParserCreate ("UTF-8");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Parser::~Parser () noexcept
|
||||
{
|
||||
if (pImpl->parser)
|
||||
XML_ParserFree (pImpl->parser);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
IHandler* Parser::getHandler () const
|
||||
{
|
||||
return pImpl->handler;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Parser::parse (IContentProvider* provider, IHandler* handler)
|
||||
{
|
||||
if (provider == nullptr || handler == nullptr)
|
||||
return false;
|
||||
|
||||
pImpl->handler = handler;
|
||||
XML_SetUserData (pImpl->parser, this);
|
||||
XML_SetStartElementHandler (pImpl->parser, gStartElementHandler);
|
||||
XML_SetEndElementHandler (pImpl->parser, gEndElementHandler);
|
||||
XML_SetCharacterDataHandler (pImpl->parser, gCharacterDataHandler);
|
||||
XML_SetCommentHandler (pImpl->parser, gCommentHandler);
|
||||
|
||||
static const uint32_t kBufferSize = 0x8000;
|
||||
|
||||
provider->rewind ();
|
||||
|
||||
while (true)
|
||||
{
|
||||
void* buffer = XML_GetBuffer (pImpl->parser, kBufferSize);
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
pImpl->handler = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t bytesRead = provider->readRawData ((int8_t*)buffer, kBufferSize);
|
||||
if (bytesRead == kStreamIOError)
|
||||
bytesRead = 0;
|
||||
XML_Status status = XML_ParseBuffer (pImpl->parser, static_cast<int> (bytesRead), bytesRead == 0);
|
||||
switch (status)
|
||||
{
|
||||
case XML_STATUS_ERROR:
|
||||
{
|
||||
XML_Error error = XML_GetErrorCode (pImpl->parser);
|
||||
if (error == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) // that's ok
|
||||
{
|
||||
pImpl->handler = nullptr;
|
||||
return true;
|
||||
}
|
||||
#if DEBUG
|
||||
XML_Size currentLineNumber = XML_GetCurrentLineNumber (pImpl->parser);
|
||||
DebugPrint ("XML Parser Error on line: %d\n", currentLineNumber);
|
||||
DebugPrint ("%s\n", XML_ErrorString (XML_GetErrorCode (pImpl->parser)));
|
||||
int offset, size;
|
||||
const char* inputContext = XML_GetInputContext (pImpl->parser, &offset, &size);
|
||||
if (inputContext)
|
||||
{
|
||||
int pos = offset;
|
||||
while (offset > 0 && pos - offset < 20)
|
||||
{
|
||||
if (inputContext[offset] == '\n')
|
||||
{
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
offset--;
|
||||
}
|
||||
for (int i = offset; i < size && i - offset < 40; i++)
|
||||
{
|
||||
if (inputContext[i] == '\n')
|
||||
break;
|
||||
if (inputContext[i] == '\t')
|
||||
DebugPrint (" ");
|
||||
else
|
||||
DebugPrint ("%c", inputContext[i]);
|
||||
}
|
||||
DebugPrint ("\n");
|
||||
for (int i = offset; i < pos; i++)
|
||||
{
|
||||
DebugPrint (" ");
|
||||
}
|
||||
DebugPrint ("^\n");
|
||||
}
|
||||
#endif
|
||||
pImpl->handler = nullptr;
|
||||
return false;
|
||||
}
|
||||
case XML_STATUS_SUSPENDED:
|
||||
{
|
||||
pImpl->handler = nullptr;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
}
|
||||
pImpl->handler = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Parser::stop ()
|
||||
{
|
||||
XML_StopParser (pImpl->parser, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
}} // namespaces
|
||||
|
||||
#if !VSTGUI_USE_SYSTEM_EXPAT
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
#pragma clang diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Xml {
|
||||
#include "../thirdparty/expat/xmltok.c"
|
||||
#include "../thirdparty/expat/xmlrole.c"
|
||||
#include "../thirdparty/expat/xmlparse.c"
|
||||
}}
|
||||
|
||||
#ifdef OLD_BYTEORDER
|
||||
#undef BYTEORDER
|
||||
#define BYTEORDER = OLD_BYTEORDER
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif // VSTGUI_ENABLE_XML_PARSER
|
||||
Reference in New Issue
Block a user