1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkXMLPullParser_expat.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,213 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkXMLParser.h" 1.14 +#include "SkChunkAlloc.h" 1.15 +#include "SkString.h" 1.16 +#include "SkStream.h" 1.17 + 1.18 +#include "expat.h" 1.19 + 1.20 +static inline char* dupstr(SkChunkAlloc& chunk, const char src[], size_t len) 1.21 +{ 1.22 + SkASSERT(src); 1.23 + char* dst = (char*)chunk.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType); 1.24 + 1.25 + memcpy(dst, src, len); 1.26 + dst[len] = 0; 1.27 + return dst; 1.28 +} 1.29 + 1.30 +static inline int count_pairs(const char** p) 1.31 +{ 1.32 + const char** start = p; 1.33 + while (*p) 1.34 + { 1.35 + SkASSERT(p[1] != NULL); 1.36 + p += 2; 1.37 + } 1.38 + return (p - start) >> 1; 1.39 +} 1.40 + 1.41 +struct Data { 1.42 + Data() : fAlloc(2048), fState(NORMAL) {} 1.43 + 1.44 + XML_Parser fParser; 1.45 + SkXMLPullParser::Curr* fCurr; 1.46 + SkChunkAlloc fAlloc; 1.47 + 1.48 + enum State { 1.49 + NORMAL, 1.50 + MISSED_START_TAG, 1.51 + RETURN_END_TAG 1.52 + }; 1.53 + State fState; 1.54 + const char* fEndTag; // if state is RETURN_END_TAG 1.55 +}; 1.56 + 1.57 +static void XMLCALL start_proc(void *data, const char *el, const char **attr) 1.58 +{ 1.59 + Data* p = (Data*)data; 1.60 + SkXMLPullParser::Curr* c = p->fCurr; 1.61 + SkChunkAlloc& alloc = p->fAlloc; 1.62 + 1.63 + c->fName = dupstr(alloc, el, strlen(el)); 1.64 + 1.65 + int n = count_pairs(attr); 1.66 + SkXMLPullParser::AttrInfo* info = (SkXMLPullParser::AttrInfo*)alloc.alloc(n * sizeof(SkXMLPullParser::AttrInfo), 1.67 + SkChunkAlloc::kThrow_AllocFailType); 1.68 + c->fAttrInfoCount = n; 1.69 + c->fAttrInfos = info; 1.70 + 1.71 + for (int i = 0; i < n; i++) 1.72 + { 1.73 + info[i].fName = dupstr(alloc, attr[0], strlen(attr[0])); 1.74 + info[i].fValue = dupstr(alloc, attr[1], strlen(attr[1])); 1.75 + attr += 2; 1.76 + } 1.77 + 1.78 + c->fEventType = SkXMLPullParser::START_TAG; 1.79 + XML_StopParser(p->fParser, true); 1.80 +} 1.81 + 1.82 +static void XMLCALL end_proc(void *data, const char *el) 1.83 +{ 1.84 + Data* p = (Data*)data; 1.85 + SkXMLPullParser::Curr* c = p->fCurr; 1.86 + 1.87 + if (c->fEventType == SkXMLPullParser::START_TAG) 1.88 + { 1.89 + /* if we get here, we were called with a start_tag immediately 1.90 + followed by this end_tag. The caller will only see the end_tag, 1.91 + so we set a flag to notify them of the missed start_tag 1.92 + */ 1.93 + p->fState = Data::MISSED_START_TAG; 1.94 + 1.95 + SkASSERT(c->fName != NULL); 1.96 + SkASSERT(strcmp(c->fName, el) == 0); 1.97 + } 1.98 + else 1.99 + c->fName = dupstr(p->fAlloc, el, strlen(el)); 1.100 + 1.101 + c->fEventType = SkXMLPullParser::END_TAG; 1.102 + XML_StopParser(p->fParser, true); 1.103 +} 1.104 + 1.105 +#include <ctype.h> 1.106 + 1.107 +static bool isws(const char s[]) 1.108 +{ 1.109 + for (; *s; s++) 1.110 + if (!isspace(*s)) 1.111 + return false; 1.112 + return true; 1.113 +} 1.114 + 1.115 +static void XMLCALL text_proc(void* data, const char* text, int len) 1.116 +{ 1.117 + Data* p = (Data*)data; 1.118 + SkXMLPullParser::Curr* c = p->fCurr; 1.119 + 1.120 + c->fName = dupstr(p->fAlloc, text, len); 1.121 + c->fIsWhitespace = isws(c->fName); 1.122 + 1.123 + c->fEventType = SkXMLPullParser::TEXT; 1.124 + XML_StopParser(p->fParser, true); 1.125 +} 1.126 + 1.127 +////////////////////////////////////////////////////////////////////////// 1.128 + 1.129 +struct SkXMLPullParser::Impl { 1.130 + Data fData; 1.131 + void* fBuffer; 1.132 + size_t fBufferLen; 1.133 +}; 1.134 + 1.135 +static void reportError(XML_Parser parser) 1.136 +{ 1.137 + XML_Error code = XML_GetErrorCode(parser); 1.138 + int lineNumber = XML_GetCurrentLineNumber(parser); 1.139 + const char* msg = XML_ErrorString(code); 1.140 + 1.141 + printf("-------- XML error [%d] on line %d, %s\n", code, lineNumber, msg); 1.142 +} 1.143 + 1.144 +bool SkXMLPullParser::onInit() 1.145 +{ 1.146 + fImpl = new Impl; 1.147 + 1.148 + XML_Parser p = XML_ParserCreate(NULL); 1.149 + SkASSERT(p); 1.150 + 1.151 + fImpl->fData.fParser = p; 1.152 + fImpl->fData.fCurr = &fCurr; 1.153 + 1.154 + XML_SetElementHandler(p, start_proc, end_proc); 1.155 + XML_SetCharacterDataHandler(p, text_proc); 1.156 + XML_SetUserData(p, &fImpl->fData); 1.157 + 1.158 + size_t len = fStream->getLength(); 1.159 + fImpl->fBufferLen = len; 1.160 + fImpl->fBuffer = sk_malloc_throw(len); 1.161 + fStream->rewind(); 1.162 + size_t len2 = fStream->read(fImpl->fBuffer, len); 1.163 + return len2 == len; 1.164 +} 1.165 + 1.166 +void SkXMLPullParser::onExit() 1.167 +{ 1.168 + sk_free(fImpl->fBuffer); 1.169 + XML_ParserFree(fImpl->fData.fParser); 1.170 + delete fImpl; 1.171 + fImpl = NULL; 1.172 +} 1.173 + 1.174 +SkXMLPullParser::EventType SkXMLPullParser::onNextToken() 1.175 +{ 1.176 + if (Data::RETURN_END_TAG == fImpl->fData.fState) 1.177 + { 1.178 + fImpl->fData.fState = Data::NORMAL; 1.179 + fCurr.fName = fImpl->fData.fEndTag; // restore name from (below) save 1.180 + return SkXMLPullParser::END_TAG; 1.181 + } 1.182 + 1.183 + fImpl->fData.fAlloc.reset(); 1.184 + 1.185 + XML_Parser p = fImpl->fData.fParser; 1.186 + XML_Status status; 1.187 + 1.188 + status = XML_ResumeParser(p); 1.189 + 1.190 +CHECK_STATUS: 1.191 + switch (status) { 1.192 + case XML_STATUS_OK: 1.193 + return SkXMLPullParser::END_DOCUMENT; 1.194 + 1.195 + case XML_STATUS_ERROR: 1.196 + if (XML_GetErrorCode(p) != XML_ERROR_NOT_SUSPENDED) 1.197 + { 1.198 + reportError(p); 1.199 + return SkXMLPullParser::ERROR; 1.200 + } 1.201 + status = XML_Parse(p, (const char*)fImpl->fBuffer, fImpl->fBufferLen, true); 1.202 + goto CHECK_STATUS; 1.203 + 1.204 + case XML_STATUS_SUSPENDED: 1.205 + if (Data::MISSED_START_TAG == fImpl->fData.fState) 1.206 + { 1.207 + // return a start_tag, and clear the flag so we return end_tag next 1.208 + SkASSERT(SkXMLPullParser::END_TAG == fCurr.fEventType); 1.209 + fImpl->fData.fState = Data::RETURN_END_TAG; 1.210 + fImpl->fData.fEndTag = fCurr.fName; // save this pointer 1.211 + return SkXMLPullParser::START_TAG; 1.212 + } 1.213 + break; 1.214 + } 1.215 + return fCurr.fEventType; 1.216 +}