OLD | NEW |
| (Empty) |
1 /* libs/graphics/ports/SkXMLParser_expat.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkXMLParser.h" | |
19 #include "SkChunkAlloc.h" | |
20 #include "SkString.h" | |
21 #include "SkStream.h" | |
22 | |
23 #include "expat.h" | |
24 | |
25 static inline char* dupstr(SkChunkAlloc& chunk, const char src[], size_t len) | |
26 { | |
27 SkASSERT(src); | |
28 char* dst = (char*)chunk.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType
); | |
29 | |
30 memcpy(dst, src, len); | |
31 dst[len] = 0; | |
32 return dst; | |
33 } | |
34 | |
35 static inline int count_pairs(const char** p) | |
36 { | |
37 const char** start = p; | |
38 while (*p) | |
39 { | |
40 SkASSERT(p[1] != NULL); | |
41 p += 2; | |
42 } | |
43 return (p - start) >> 1; | |
44 } | |
45 | |
46 struct Data { | |
47 Data() : fAlloc(2048), fState(NORMAL) {} | |
48 | |
49 XML_Parser fParser; | |
50 SkXMLPullParser::Curr* fCurr; | |
51 SkChunkAlloc fAlloc; | |
52 | |
53 enum State { | |
54 NORMAL, | |
55 MISSED_START_TAG, | |
56 RETURN_END_TAG | |
57 }; | |
58 State fState; | |
59 const char* fEndTag; // if state is RETURN_END_TAG | |
60 }; | |
61 | |
62 static void XMLCALL start_proc(void *data, const char *el, const char **attr) | |
63 { | |
64 Data* p = (Data*)data; | |
65 SkXMLPullParser::Curr* c = p->fCurr; | |
66 SkChunkAlloc& alloc = p->fAlloc; | |
67 | |
68 c->fName = dupstr(alloc, el, strlen(el)); | |
69 | |
70 int n = count_pairs(attr); | |
71 SkXMLPullParser::AttrInfo* info = (SkXMLPullParser::AttrInfo*)alloc.alloc(n
* sizeof(SkXMLPullParser::AttrInfo), | |
72 Sk
ChunkAlloc::kThrow_AllocFailType); | |
73 c->fAttrInfoCount = n; | |
74 c->fAttrInfos = info; | |
75 | |
76 for (int i = 0; i < n; i++) | |
77 { | |
78 info[i].fName = dupstr(alloc, attr[0], strlen(attr[0])); | |
79 info[i].fValue = dupstr(alloc, attr[1], strlen(attr[1])); | |
80 attr += 2; | |
81 } | |
82 | |
83 c->fEventType = SkXMLPullParser::START_TAG; | |
84 XML_StopParser(p->fParser, true); | |
85 } | |
86 | |
87 static void XMLCALL end_proc(void *data, const char *el) | |
88 { | |
89 Data* p = (Data*)data; | |
90 SkXMLPullParser::Curr* c = p->fCurr; | |
91 | |
92 if (c->fEventType == SkXMLPullParser::START_TAG) | |
93 { | |
94 /* if we get here, we were called with a start_tag immediately | |
95 followed by this end_tag. The caller will only see the end_tag, | |
96 so we set a flag to notify them of the missed start_tag | |
97 */ | |
98 p->fState = Data::MISSED_START_TAG; | |
99 | |
100 SkASSERT(c->fName != NULL); | |
101 SkASSERT(strcmp(c->fName, el) == 0); | |
102 } | |
103 else | |
104 c->fName = dupstr(p->fAlloc, el, strlen(el)); | |
105 | |
106 c->fEventType = SkXMLPullParser::END_TAG; | |
107 XML_StopParser(p->fParser, true); | |
108 } | |
109 | |
110 #include <ctype.h> | |
111 | |
112 static bool isws(const char s[]) | |
113 { | |
114 for (; *s; s++) | |
115 if (!isspace(*s)) | |
116 return false; | |
117 return true; | |
118 } | |
119 | |
120 static void XMLCALL text_proc(void* data, const char* text, int len) | |
121 { | |
122 Data* p = (Data*)data; | |
123 SkXMLPullParser::Curr* c = p->fCurr; | |
124 | |
125 c->fName = dupstr(p->fAlloc, text, len); | |
126 c->fIsWhitespace = isws(c->fName); | |
127 | |
128 c->fEventType = SkXMLPullParser::TEXT; | |
129 XML_StopParser(p->fParser, true); | |
130 } | |
131 | |
132 ////////////////////////////////////////////////////////////////////////// | |
133 | |
134 struct SkXMLPullParser::Impl { | |
135 Data fData; | |
136 void* fBuffer; | |
137 size_t fBufferLen; | |
138 }; | |
139 | |
140 static void reportError(XML_Parser parser) | |
141 { | |
142 XML_Error code = XML_GetErrorCode(parser); | |
143 int lineNumber = XML_GetCurrentLineNumber(parser); | |
144 const char* msg = XML_ErrorString(code); | |
145 | |
146 printf("-------- XML error [%d] on line %d, %s\n", code, lineNumber, msg); | |
147 } | |
148 | |
149 bool SkXMLPullParser::onInit() | |
150 { | |
151 fImpl = new Impl; | |
152 | |
153 XML_Parser p = XML_ParserCreate(NULL); | |
154 SkASSERT(p); | |
155 | |
156 fImpl->fData.fParser = p; | |
157 fImpl->fData.fCurr = &fCurr; | |
158 | |
159 XML_SetElementHandler(p, start_proc, end_proc); | |
160 XML_SetCharacterDataHandler(p, text_proc); | |
161 XML_SetUserData(p, &fImpl->fData); | |
162 | |
163 size_t len = fStream->read(NULL, 0); | |
164 fImpl->fBufferLen = len; | |
165 fImpl->fBuffer = sk_malloc_throw(len); | |
166 fStream->rewind(); | |
167 size_t len2 = fStream->read(fImpl->fBuffer, len); | |
168 return len2 == len; | |
169 } | |
170 | |
171 void SkXMLPullParser::onExit() | |
172 { | |
173 sk_free(fImpl->fBuffer); | |
174 XML_ParserFree(fImpl->fData.fParser); | |
175 delete fImpl; | |
176 fImpl = NULL; | |
177 } | |
178 | |
179 SkXMLPullParser::EventType SkXMLPullParser::onNextToken() | |
180 { | |
181 if (Data::RETURN_END_TAG == fImpl->fData.fState) | |
182 { | |
183 fImpl->fData.fState = Data::NORMAL; | |
184 fCurr.fName = fImpl->fData.fEndTag; // restore name from (below) save | |
185 return SkXMLPullParser::END_TAG; | |
186 } | |
187 | |
188 fImpl->fData.fAlloc.reuse(); | |
189 | |
190 XML_Parser p = fImpl->fData.fParser; | |
191 XML_Status status; | |
192 | |
193 status = XML_ResumeParser(p); | |
194 | |
195 CHECK_STATUS: | |
196 switch (status) { | |
197 case XML_STATUS_OK: | |
198 return SkXMLPullParser::END_DOCUMENT; | |
199 | |
200 case XML_STATUS_ERROR: | |
201 if (XML_GetErrorCode(p) != XML_ERROR_NOT_SUSPENDED) | |
202 { | |
203 reportError(p); | |
204 return SkXMLPullParser::ERROR; | |
205 } | |
206 status = XML_Parse(p, (const char*)fImpl->fBuffer, fImpl->fBufferLen, tr
ue); | |
207 goto CHECK_STATUS; | |
208 | |
209 case XML_STATUS_SUSPENDED: | |
210 if (Data::MISSED_START_TAG == fImpl->fData.fState) | |
211 { | |
212 // return a start_tag, and clear the flag so we return end_tag next | |
213 SkASSERT(SkXMLPullParser::END_TAG == fCurr.fEventType); | |
214 fImpl->fData.fState = Data::RETURN_END_TAG; | |
215 fImpl->fData.fEndTag = fCurr.fName; // save this pointer
| |
216 return SkXMLPullParser::START_TAG; | |
217 } | |
218 break; | |
219 } | |
220 return fCurr.fEventType; | |
221 } | |
222 | |
OLD | NEW |