243 lines
6.0 KiB
C++
243 lines
6.0 KiB
C++
// 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
|