diff options
-rw-r--r-- | gyp/expat.gyp | 14 | ||||
-rw-r--r-- | gyp/xml.gyp | 21 | ||||
-rw-r--r-- | include/xml/SkDOM.h | 9 | ||||
-rw-r--r-- | src/xml/SkDOM.cpp | 46 | ||||
-rw-r--r-- | src/xml/SkXMLParser.cpp | 64 | ||||
-rw-r--r-- | tests/SkDOMTest.cpp | 39 |
6 files changed, 134 insertions, 59 deletions
diff --git a/gyp/expat.gyp b/gyp/expat.gyp index 90f7b02fbc..90e4e44f41 100644 --- a/gyp/expat.gyp +++ b/gyp/expat.gyp @@ -12,9 +12,12 @@ 'cflags': [ '-Wno-missing-field-initializers' ], 'xcode_settings': { 'WARNING_CFLAGS': [ '-Wno-missing-field-initializers', ], }, 'msvs_disabled_warnings': [4244], - 'defines': [ 'HAVE_EXPAT_CONFIG_H' ], + 'defines': [ + 'HAVE_EXPAT_CONFIG_H', + 'XML_STATIC', # Compile for static linkage. + ], 'include_dirs': [ - '../third_party/externals/expat', + '../third_party/externals/expat', ], 'sources': [ '../third_party/externals/expat/lib/xmlparse.c', @@ -22,7 +25,12 @@ '../third_party/externals/expat/lib/xmltok.c', ], 'direct_dependent_settings': { - 'include_dirs': [ '../third_party/externals/expat/lib' ], + 'include_dirs': [ + '../third_party/externals/expat/lib', + ], + 'defines': [ + 'XML_STATIC', # Tell dependants to expect static linkage. + ], }, }] } diff --git a/gyp/xml.gyp b/gyp/xml.gyp index 8060076747..f7cb429dc0 100644 --- a/gyp/xml.gyp +++ b/gyp/xml.gyp @@ -14,21 +14,22 @@ 'expat.gyp:expat', ], 'include_dirs': [ - '../include/private', - '../include/xml', + '<(skia_include_path)/private', + '<(skia_include_path)/xml', ], 'sources': [ - '../include/xml/SkDOM.h', - '../include/xml/SkXMLParser.h', - '../include/xml/SkXMLWriter.h', + '<(skia_include_path)/xml/SkDOM.h', + '<(skia_include_path)/xml/SkXMLParser.h', + '<(skia_include_path)/xml/SkXMLWriter.h', - '../src/xml/SkDOM.cpp', - '../src/xml/SkXMLParser.cpp', - '../src/xml/SkXMLPullParser.cpp', - '../src/xml/SkXMLWriter.cpp', + '<(skia_src_path)/xml/SkDOM.cpp', + '<(skia_src_path)/xml/SkXMLParser.cpp', + '<(skia_src_path)/xml/SkXMLPullParser.cpp', + '<(skia_src_path)/xml/SkXMLWriter.cpp', ], 'sources!': [ - '../src/xml/SkXMLPullParser.cpp', #if 0 around class decl in header + # time to kill this? + '<(skia_src_path)/xml/SkXMLPullParser.cpp', #if 0 around class decl in header ], 'direct_dependent_settings': { 'include_dirs': [ diff --git a/include/xml/SkDOM.h b/include/xml/SkDOM.h index 14d79cf8af..2a6ccc4f63 100644 --- a/include/xml/SkDOM.h +++ b/include/xml/SkDOM.h @@ -13,14 +13,16 @@ #include "../private/SkTemplates.h" #include "SkChunkAlloc.h" #include "SkScalar.h" +#include "SkTypes.h" struct SkDOMNode; struct SkDOMAttr; class SkDOMParser; +class SkStream; class SkXMLParser; -class SkDOM { +class SK_API SkDOM : public SkNoncopyable { public: SkDOM(); ~SkDOM(); @@ -31,6 +33,7 @@ public: /** Returns null on failure */ const Node* build(const char doc[], size_t len); + const Node* build(SkStream&); const Node* copy(const SkDOM& dom, const Node* node); const Node* getRootNode() const; @@ -85,15 +88,13 @@ public: }; SkDEBUGCODE(void dump(const Node* node = NULL, int tabLevel = 0) const;) - SkDEBUGCODE(static void UnitTest();) private: SkChunkAlloc fAlloc; Node* fRoot; SkAutoTDelete<SkDOMParser> fParser; - friend class AttrIter; - friend class SkDOMParser; + typedef SkNoncopyable INHERITED; }; #endif diff --git a/src/xml/SkDOM.cpp b/src/xml/SkDOM.cpp index 15b458e4fb..78cf6f07e9 100644 --- a/src/xml/SkDOM.cpp +++ b/src/xml/SkDOM.cpp @@ -310,10 +310,9 @@ private: int fLevel; }; -const SkDOM::Node* SkDOM::build(const char doc[], size_t len) -{ +const SkDOM::Node* SkDOM::build(SkStream& docStream) { SkDOMParser parser(&fAlloc); - if (!parser.parse(doc, len)) + if (!parser.parse(docStream)) { SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());) fRoot = nullptr; @@ -324,6 +323,11 @@ const SkDOM::Node* SkDOM::build(const char doc[], size_t len) return fRoot; } +const SkDOM::Node* SkDOM::build(const char doc[], size_t len) { + SkMemoryStream docStream(doc, len); + return this->build(docStream); +} + /////////////////////////////////////////////////////////////////////////// static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser) @@ -475,40 +479,4 @@ void SkDOM::dump(const Node* node, int level) const xmlWriter.writeDOM(*this, node, false); } -void SkDOM::UnitTest() -{ -#ifdef SK_SUPPORT_UNITTEST - static const char gDoc[] = - "<root a='1' b='2'>" - "<elem1 c='3' />" - "<elem2 d='4' />" - "<elem3 e='5'>" - "<subelem1/>" - "<subelem2 f='6' g='7'/>" - "</elem3>" - "<elem4 h='8'/>" - "</root>" - ; - - SkDOM dom; - - SkASSERT(dom.getRootNode() == nullptr); - - const Node* root = dom.build(gDoc, sizeof(gDoc) - 1); - SkASSERT(root && dom.getRootNode() == root); - - const char* v = dom.findAttr(root, "a"); - SkASSERT(v && !strcmp(v, "1")); - v = dom.findAttr(root, "b"); - SkASSERT(v && !strcmp(v, "2")); - v = dom.findAttr(root, "c"); - SkASSERT(v == nullptr); - - SkASSERT(dom.getFirstChild(root, "elem1")); - SkASSERT(!dom.getFirstChild(root, "subelem1")); - - dom.dump(); -#endif -} - #endif diff --git a/src/xml/SkXMLParser.cpp b/src/xml/SkXMLParser.cpp index 11f4c6bf72..77903cbb05 100644 --- a/src/xml/SkXMLParser.cpp +++ b/src/xml/SkXMLParser.cpp @@ -5,7 +5,9 @@ * found in the LICENSE file. */ +#include "expat.h" +#include "SkStream.h" #include "SkXMLParser.h" static char const* const gErrorStrings[] = { @@ -47,9 +49,32 @@ void SkXMLParserError::reset() { fNativeCode = -1; } - //////////////// +namespace { + +const XML_Memory_Handling_Suite sk_XML_alloc = { + sk_malloc_throw, + sk_realloc_throw, + sk_free +}; + +void XMLCALL start_element_handler(void *data, const char* tag, const char** attributes) { + SkXMLParser* parser = static_cast<SkXMLParser*>(data); + + parser->startElement(tag); + + for (size_t i = 0; attributes[i]; i += 2) { + parser->addAttribute(attributes[i], attributes[i + 1]); + } +} + +void XMLCALL end_element_handler(void* data, const char* tag) { + static_cast<SkXMLParser*>(data)->endElement(tag); +} + +} // anonymous namespace + SkXMLParser::SkXMLParser(SkXMLParserError* parserError) : fParser(nullptr), fError(parserError) { } @@ -60,12 +85,45 @@ SkXMLParser::~SkXMLParser() bool SkXMLParser::parse(SkStream& docStream) { - return false; + SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> + parser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)); + if (!parser) { + SkDebugf("could not create XML parser\n"); + return false; + } + + XML_SetUserData(parser, this); + XML_SetElementHandler(parser, start_element_handler, end_element_handler); + + static const int kBufferSize = 512 SkDEBUGCODE( - 507); + bool done = false; + do { + void* buffer = XML_GetBuffer(parser, kBufferSize); + if (!buffer) { + SkDebugf("could not buffer enough to continue\n"); + return false; + } + + size_t len = docStream.read(buffer, kBufferSize); + done = docStream.isAtEnd(); + XML_Status status = XML_ParseBuffer(parser, SkToS32(len), done); + if (XML_STATUS_ERROR == status) { + XML_Error error = XML_GetErrorCode(parser); + int line = XML_GetCurrentLineNumber(parser); + int column = XML_GetCurrentColumnNumber(parser); + const XML_LChar* errorString = XML_ErrorString(error); + SkDebugf("parse error @%d:%d: %d (%s).\n", line, column, error, errorString); + return false; + } + } while (!done); + + return true; } bool SkXMLParser::parse(const char doc[], size_t len) { - return false; + SkMemoryStream docStream(doc, len); + return this->parse(docStream); } void SkXMLParser::GetNativeErrorString(int error, SkString* str) diff --git a/tests/SkDOMTest.cpp b/tests/SkDOMTest.cpp new file mode 100644 index 0000000000..aca2c4870b --- /dev/null +++ b/tests/SkDOMTest.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkDOM.h" +#include "Test.h" + +DEF_TEST(SkDOM_test, r) { + static const char gDoc[] = + "<root a='1' b='2'>" + "<elem1 c='3' />" + "<elem2 d='4' />" + "<elem3 e='5'>" + "<subelem1/>" + "<subelem2 f='6' g='7'/>" + "</elem3>" + "<elem4 h='8'/>" + "</root>" + ; + + SkDOM dom; + REPORTER_ASSERT(r, !dom.getRootNode()); + + const SkDOM::Node* root = dom.build(gDoc, sizeof(gDoc) - 1); + REPORTER_ASSERT(r, root && dom.getRootNode() == root); + + const char* v = dom.findAttr(root, "a"); + REPORTER_ASSERT(r, v && !strcmp(v, "1")); + v = dom.findAttr(root, "b"); + REPORTER_ASSERT(r, v && !strcmp(v, "2")); + v = dom.findAttr(root, "c"); + REPORTER_ASSERT(r, v == nullptr); + + REPORTER_ASSERT(r, dom.getFirstChild(root, "elem1")); + REPORTER_ASSERT(r, !dom.getFirstChild(root, "subelem1")); +} |