/src/xpdf-4.05/xpdf/Zoox.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //======================================================================== |
2 | | // |
3 | | // Zoox.cc |
4 | | // |
5 | | //======================================================================== |
6 | | |
7 | | #include <aconf.h> |
8 | | |
9 | | #include <stdlib.h> |
10 | | #include <stdio.h> |
11 | | #include <string.h> |
12 | | #include "gmem.h" |
13 | | #include "gmempp.h" |
14 | | #include "GString.h" |
15 | | #include "GList.h" |
16 | | #include "GHash.h" |
17 | | #include "Zoox.h" |
18 | | |
19 | | //~ all of this code assumes the encoding is UTF-8 or ASCII or something |
20 | | //~ similar (ISO-8859-*) |
21 | | |
22 | | //------------------------------------------------------------------------ |
23 | | |
24 | | static char nameStartChar[256] = { |
25 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00 |
26 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 |
27 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 |
28 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // 30 |
29 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 |
30 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50 |
31 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 |
32 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 70 |
33 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 |
34 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90 |
35 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // a0 |
36 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // b0 |
37 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // c0 |
38 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // d0 |
39 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // e0 |
40 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // f0 |
41 | | }; |
42 | | |
43 | | static char nameChar[256] = { |
44 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00 |
45 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 |
46 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // 20 |
47 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 30 |
48 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 |
49 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50 |
50 | | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 |
51 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 70 |
52 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 |
53 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90 |
54 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // a0 |
55 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // b0 |
56 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // c0 |
57 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // d0 |
58 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // e0 |
59 | | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // f0 |
60 | | }; |
61 | | |
62 | | //------------------------------------------------------------------------ |
63 | | |
64 | 1.39M | ZxNode::ZxNode() { |
65 | 1.39M | next = NULL; |
66 | 1.39M | parent = NULL; |
67 | 1.39M | firstChild = lastChild = NULL; |
68 | 1.39M | } |
69 | | |
70 | 1.39M | ZxNode::~ZxNode() { |
71 | 1.39M | ZxNode *child; |
72 | | |
73 | 2.78M | while (firstChild) { |
74 | 1.38M | child = firstChild; |
75 | 1.38M | firstChild = firstChild->next; |
76 | 1.38M | delete child; |
77 | 1.38M | } |
78 | 1.39M | } |
79 | | |
80 | 0 | ZxNode *ZxNode::deleteChild(ZxNode *child) { |
81 | 0 | ZxNode *p1, *p2; |
82 | |
|
83 | 0 | for (p1 = NULL, p2 = firstChild; |
84 | 0 | p2 && p2 != child; |
85 | 0 | p1 = p2, p2 = p2->next) ; |
86 | 0 | if (!p2) { |
87 | 0 | return NULL; |
88 | 0 | } |
89 | 0 | if (p1) { |
90 | 0 | p1->next = child->next; |
91 | 0 | } else { |
92 | 0 | firstChild = child->next; |
93 | 0 | } |
94 | 0 | child->parent = NULL; |
95 | 0 | child->next = NULL; |
96 | 0 | return child; |
97 | 0 | } |
98 | | |
99 | 0 | void ZxNode::appendChild(ZxNode *child) { |
100 | 0 | ZxNode *p1; |
101 | |
|
102 | 0 | if (child->parent || child->next) { |
103 | 0 | return; |
104 | 0 | } |
105 | 0 | if (firstChild) { |
106 | 0 | for (p1 = firstChild; p1->next; p1 = p1->next) ; |
107 | 0 | p1->next = child; |
108 | 0 | } else { |
109 | 0 | firstChild = child; |
110 | 0 | } |
111 | 0 | child->parent = this; |
112 | 0 | } |
113 | | |
114 | 0 | void ZxNode::insertChildAfter(ZxNode *child, ZxNode *prev) { |
115 | 0 | if (child->parent || child->next || (prev && prev->parent != this)) { |
116 | 0 | return; |
117 | 0 | } |
118 | 0 | if (prev) { |
119 | 0 | child->next = prev->next; |
120 | 0 | prev->next = child; |
121 | 0 | } else { |
122 | 0 | child->next = firstChild; |
123 | 0 | firstChild = child; |
124 | 0 | } |
125 | 0 | child->parent = this; |
126 | 0 | } |
127 | | |
128 | 0 | ZxElement *ZxNode::findFirstElement(const char *type) { |
129 | 0 | ZxNode *child; |
130 | 0 | ZxElement *result; |
131 | |
|
132 | 0 | if (isElement(type)) { |
133 | 0 | return (ZxElement *)this; |
134 | 0 | } |
135 | 0 | for (child = firstChild; child; child = child->next) { |
136 | 0 | if ((result = child->findFirstElement(type))) { |
137 | 0 | return result; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | return NULL; |
141 | 0 | } |
142 | | |
143 | 0 | ZxElement *ZxNode::findFirstChildElement(const char *type) { |
144 | 0 | ZxNode *child; |
145 | |
|
146 | 0 | for (child = firstChild; child; child = child->next) { |
147 | 0 | if (child->isElement(type)) { |
148 | 0 | return (ZxElement *)child; |
149 | 0 | } |
150 | 0 | } |
151 | 0 | return NULL; |
152 | 0 | } |
153 | | |
154 | 0 | GList *ZxNode::findAllElements(const char *type) { |
155 | 0 | GList *results; |
156 | |
|
157 | 0 | results = new GList(); |
158 | 0 | findAllElements(type, results); |
159 | 0 | return results; |
160 | 0 | } |
161 | | |
162 | 0 | void ZxNode::findAllElements(const char *type, GList *results) { |
163 | 0 | ZxNode *child; |
164 | |
|
165 | 0 | if (isElement(type)) { |
166 | 0 | results->append(this); |
167 | 0 | } |
168 | 0 | for (child = firstChild; child; child = child->next) { |
169 | 0 | child->findAllElements(type, results); |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | 0 | GList *ZxNode::findAllChildElements(const char *type) { |
174 | 0 | GList *results; |
175 | 0 | ZxNode *child; |
176 | |
|
177 | 0 | results = new GList(); |
178 | 0 | for (child = firstChild; child; child = child->next) { |
179 | 0 | if (child->isElement(type)) { |
180 | 0 | results->append(child); |
181 | 0 | } |
182 | 0 | } |
183 | 0 | return results; |
184 | 0 | } |
185 | | |
186 | 1.38M | void ZxNode::addChild(ZxNode *child) { |
187 | 1.38M | if (lastChild) { |
188 | 156k | lastChild->next = child; |
189 | 156k | lastChild = child; |
190 | 1.23M | } else { |
191 | 1.23M | firstChild = lastChild = child; |
192 | 1.23M | } |
193 | 1.38M | child->parent = this; |
194 | 1.38M | child->next = NULL; |
195 | 1.38M | } |
196 | | |
197 | | //------------------------------------------------------------------------ |
198 | | |
199 | 7.89k | ZxDoc::ZxDoc() { |
200 | 7.89k | xmlDecl = NULL; |
201 | 7.89k | docTypeDecl = NULL; |
202 | 7.89k | root = NULL; |
203 | 7.89k | } |
204 | | |
205 | 3.94k | ZxDoc *ZxDoc::loadMem(const char *data, Guint dataLen) { |
206 | 3.94k | ZxDoc *doc; |
207 | | |
208 | 3.94k | doc = new ZxDoc(); |
209 | 3.94k | if (!doc->parse(data, dataLen)) { |
210 | 1.33k | delete doc; |
211 | 1.33k | return NULL; |
212 | 1.33k | } |
213 | 2.60k | return doc; |
214 | 3.94k | } |
215 | | |
216 | 0 | ZxDoc *ZxDoc::loadFile(const char *fileName) { |
217 | 0 | ZxDoc *doc; |
218 | 0 | FILE *f; |
219 | 0 | char *data; |
220 | 0 | Guint dataLen; |
221 | |
|
222 | 0 | if (!(f = fopen(fileName, "rb"))) { |
223 | 0 | return NULL; |
224 | 0 | } |
225 | 0 | fseek(f, 0, SEEK_END); |
226 | 0 | dataLen = (Guint)ftell(f); |
227 | 0 | if (!dataLen) { |
228 | 0 | fclose(f); |
229 | 0 | return NULL; |
230 | 0 | } |
231 | 0 | fseek(f, 0, SEEK_SET); |
232 | 0 | data = (char *)gmalloc(dataLen); |
233 | 0 | if (fread(data, 1, dataLen, f) != dataLen) { |
234 | 0 | fclose(f); |
235 | 0 | gfree(data); |
236 | 0 | return NULL; |
237 | 0 | } |
238 | 0 | fclose(f); |
239 | 0 | doc = loadMem(data, dataLen); |
240 | 0 | gfree(data); |
241 | 0 | return doc; |
242 | 0 | } |
243 | | |
244 | | ZxDoc::~ZxDoc() { |
245 | | } |
246 | | |
247 | 0 | static bool writeToFileFunc(void *stream, const char *data, int length) { |
248 | 0 | return (int)fwrite(data, 1, length, (FILE *)stream) == length; |
249 | 0 | } |
250 | | |
251 | 0 | bool ZxDoc::writeFile(const char *fileName) { |
252 | 0 | FILE *f; |
253 | |
|
254 | 0 | if (!(f = fopen(fileName, "wb"))) { |
255 | 0 | return false; |
256 | 0 | } |
257 | 0 | write(&writeToFileFunc, f); |
258 | 0 | fclose(f); |
259 | 0 | return true; |
260 | 0 | } |
261 | | |
262 | 4.94k | void ZxDoc::addChild(ZxNode *node) { |
263 | 4.94k | if (node->isXMLDecl() && !xmlDecl) { |
264 | 804 | xmlDecl = (ZxXMLDecl *)node; |
265 | 4.14k | } else if (node->isDocTypeDecl() && !docTypeDecl) { |
266 | 225 | docTypeDecl = (ZxDocTypeDecl *)node; |
267 | 3.91k | } else if (node->isElement() && !root) { |
268 | 2.60k | root = (ZxElement *)node; |
269 | 2.60k | } |
270 | 4.94k | ZxNode::addChild(node); |
271 | 4.94k | } |
272 | | |
273 | 3.94k | bool ZxDoc::parse(const char *data, Guint dataLen) { |
274 | 3.94k | parsePtr = data; |
275 | 3.94k | parseEnd = data + dataLen; |
276 | | |
277 | 3.94k | parseSpace(); |
278 | 3.94k | parseBOM(); |
279 | 3.94k | parseSpace(); |
280 | 3.94k | parseXMLDecl(this); |
281 | 3.94k | parseMisc(this); |
282 | 3.94k | parseDocTypeDecl(this); |
283 | 3.94k | parseMisc(this); |
284 | 3.94k | if (match("<")) { |
285 | 2.60k | parseElement(this); |
286 | 2.60k | } |
287 | 3.94k | parseMisc(this); |
288 | 3.94k | return root != NULL; |
289 | 3.94k | } |
290 | | |
291 | 3.94k | void ZxDoc::parseXMLDecl(ZxNode *par) { |
292 | 3.94k | GString *version, *encoding, *s; |
293 | 3.94k | bool standalone; |
294 | | |
295 | 3.94k | if (!match("<?xml")) { |
296 | 3.14k | return; |
297 | 3.14k | } |
298 | 804 | parsePtr += 5; |
299 | 804 | parseSpace(); |
300 | | |
301 | | // version |
302 | 804 | version = NULL; |
303 | 804 | if (match("version")) { |
304 | 180 | parsePtr += 7; |
305 | 180 | parseSpace(); |
306 | 180 | if (match("=")) { |
307 | 124 | ++parsePtr; |
308 | 124 | parseSpace(); |
309 | 124 | version = parseQuotedString(); |
310 | 124 | } |
311 | 180 | } |
312 | 804 | if (!version) { |
313 | 680 | version = new GString("1.0"); |
314 | 680 | } |
315 | 804 | parseSpace(); |
316 | | |
317 | | // encoding |
318 | 804 | encoding = NULL; |
319 | 804 | if (match("encoding")) { |
320 | 167 | parsePtr += 8; |
321 | 167 | parseSpace(); |
322 | 167 | if (match("=")) { |
323 | 108 | ++parsePtr; |
324 | 108 | parseSpace(); |
325 | 108 | encoding = parseQuotedString(); |
326 | 108 | } |
327 | 167 | } |
328 | 804 | parseSpace(); |
329 | | |
330 | | // standalone |
331 | 804 | standalone = false; |
332 | 804 | if (match("standalone")) { |
333 | 188 | parsePtr += 10; |
334 | 188 | parseSpace(); |
335 | 188 | if (match("=")) { |
336 | 114 | ++parsePtr; |
337 | 114 | parseSpace(); |
338 | 114 | s = parseQuotedString(); |
339 | 114 | standalone = !s->cmp("yes"); |
340 | 114 | delete s; |
341 | 114 | } |
342 | 188 | } |
343 | 804 | parseSpace(); |
344 | | |
345 | 804 | if (match("?>")) { |
346 | 3 | parsePtr += 2; |
347 | 3 | } |
348 | | |
349 | 804 | par->addChild(new ZxXMLDecl(version, encoding, standalone)); |
350 | 804 | } |
351 | | |
352 | | //~ this just skips everything after the name |
353 | 3.94k | void ZxDoc::parseDocTypeDecl(ZxNode *par) { |
354 | 3.94k | GString *name; |
355 | 3.94k | int state; |
356 | 3.94k | char c, quote; |
357 | | |
358 | 3.94k | if (!match("<!DOCTYPE")) { |
359 | 3.72k | return; |
360 | 3.72k | } |
361 | 225 | parsePtr += 9; |
362 | 225 | parseSpace(); |
363 | | |
364 | 225 | name = parseName(); |
365 | 225 | parseSpace(); |
366 | | |
367 | 225 | state = 0; |
368 | 225 | quote = '\0'; |
369 | 60.8k | while (parsePtr < parseEnd && state < 4) { |
370 | 60.6k | c = *parsePtr++; |
371 | 60.6k | switch (state) { |
372 | 52.1k | case 0: // not in square brackets; not in quotes |
373 | 52.1k | if (c == '>') { |
374 | 6 | state = 4; |
375 | 52.1k | } else if (c == '"' || c == '\'') { |
376 | 622 | state = 1; |
377 | 51.5k | } else if (c == '[') { |
378 | 421 | state = 2; |
379 | 421 | } |
380 | 52.1k | break; |
381 | 1.71k | case 1: // not in square brackets; in quotes |
382 | 1.71k | if (c == quote) { |
383 | 589 | state = 0; |
384 | 589 | } |
385 | 1.71k | break; |
386 | 5.71k | case 2: // in square brackets; not in quotes |
387 | 5.71k | if (c == ']') { |
388 | 356 | state = 0; |
389 | 5.35k | } else if (c == '"' || c == '\'') { |
390 | 609 | state = 3; |
391 | 609 | } |
392 | 5.71k | break; |
393 | 1.05k | case 3: // in square brackets; in quotes |
394 | 1.05k | if (c == quote) { |
395 | 582 | state = 2; |
396 | 582 | } |
397 | 1.05k | break; |
398 | 60.6k | } |
399 | 60.6k | } |
400 | | |
401 | 225 | par->addChild(new ZxDocTypeDecl(name)); |
402 | 225 | } |
403 | | |
404 | | // assumes match("<") |
405 | 1.30M | void ZxDoc::parseElement(ZxNode *par) { |
406 | 1.30M | GString *type; |
407 | 1.30M | ZxElement *elem; |
408 | 1.30M | ZxAttr *attr; |
409 | | |
410 | 1.30M | ++parsePtr; |
411 | 1.30M | type = parseName(); |
412 | 1.30M | elem = new ZxElement(type); |
413 | 1.30M | parseSpace(); |
414 | 2.06M | while ((attr = parseAttr())) { |
415 | 765k | elem->addAttr(attr); |
416 | 765k | parseSpace(); |
417 | 765k | } |
418 | 1.30M | if (match("/>")) { |
419 | 26.3k | parsePtr += 2; |
420 | 1.27M | } else if (match(">")) { |
421 | 1.22M | ++parsePtr; |
422 | 1.22M | parseContent(elem); |
423 | 1.22M | } |
424 | 1.30M | par->addChild(elem); |
425 | 1.30M | } |
426 | | |
427 | 2.06M | ZxAttr *ZxDoc::parseAttr() { |
428 | 2.06M | GString *name, *value; |
429 | 2.06M | const char *start; |
430 | 2.06M | char quote, c; |
431 | 2.06M | unsigned int x; |
432 | 2.06M | int n; |
433 | | |
434 | 2.06M | name = parseName(); |
435 | 2.06M | parseSpace(); |
436 | 2.06M | if (!match("=")) { |
437 | 1.29M | delete name; |
438 | 1.29M | return NULL; |
439 | 1.29M | } |
440 | 768k | ++parsePtr; |
441 | 768k | parseSpace(); |
442 | 768k | if (!(parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\''))) { |
443 | 3.27k | delete name; |
444 | 3.27k | return NULL; |
445 | 3.27k | } |
446 | 765k | quote = *parsePtr++; |
447 | 765k | value = new GString(); |
448 | 921k | while (parsePtr < parseEnd && *parsePtr != quote) { |
449 | 156k | if (*parsePtr == '&') { |
450 | 83.6k | ++parsePtr; |
451 | 83.6k | if (parsePtr < parseEnd && *parsePtr == '#') { |
452 | 18.7k | ++parsePtr; |
453 | 18.7k | if (parsePtr < parseEnd && *parsePtr == 'x') { |
454 | 5.76k | ++parsePtr; |
455 | 5.76k | x = 0; |
456 | 28.5k | while (parsePtr < parseEnd) { |
457 | 28.5k | c = *parsePtr; |
458 | 28.5k | if (c >= '0' && c <= '9') { |
459 | 2.22k | x = (x << 4) + (c - '0'); |
460 | 26.3k | } else if (c >= 'a' && c <= 'f') { |
461 | 12.5k | x = (x << 4) + (10 + c - 'a'); |
462 | 13.7k | } else if (c >= 'A' && c <= 'F') { |
463 | 8.02k | x = (x << 4) + (10 + c - 'A'); |
464 | 8.02k | } else { |
465 | 5.72k | break; |
466 | 5.72k | } |
467 | 22.8k | ++parsePtr; |
468 | 22.8k | } |
469 | 5.76k | if (parsePtr < parseEnd && *parsePtr == ';') { |
470 | 1.62k | ++parsePtr; |
471 | 1.62k | } |
472 | 5.76k | appendUTF8(value, x); |
473 | 12.9k | } else { |
474 | 12.9k | x = 0; |
475 | 46.3k | while (parsePtr < parseEnd) { |
476 | 46.3k | c = *parsePtr; |
477 | 46.3k | if (c >= '0' && c <= '9') { |
478 | 33.3k | x = x * 10 + (c - '0'); |
479 | 33.3k | } else { |
480 | 12.9k | break; |
481 | 12.9k | } |
482 | 33.3k | ++parsePtr; |
483 | 33.3k | } |
484 | 12.9k | if (parsePtr < parseEnd && *parsePtr == ';') { |
485 | 1.89k | ++parsePtr; |
486 | 1.89k | } |
487 | 12.9k | appendUTF8(value, x); |
488 | 12.9k | } |
489 | 64.9k | } else { |
490 | 64.9k | start = parsePtr; |
491 | 64.9k | for (++parsePtr; |
492 | 7.49M | parsePtr < parseEnd && *parsePtr != ';' && |
493 | 7.49M | *parsePtr != quote && *parsePtr != '&'; |
494 | 7.42M | ++parsePtr) ; |
495 | 64.9k | n = (int)(parsePtr - start); |
496 | 64.9k | if (parsePtr < parseEnd && *parsePtr == ';') { |
497 | 6.66k | ++parsePtr; |
498 | 6.66k | } |
499 | 64.9k | if (n == 2 && !strncmp(start, "lt", 2)) { |
500 | 802 | value->append('<'); |
501 | 64.1k | } else if (n == 2 && !strncmp(start, "gt", 2)) { |
502 | 1.25k | value->append('>'); |
503 | 62.8k | } else if (n == 3 && !strncmp(start, "amp", 3)) { |
504 | 6.20k | value->append('&'); |
505 | 56.6k | } else if (n == 4 && !strncmp(start, "apos", 4)) { |
506 | 928 | value->append('\''); |
507 | 55.7k | } else if (n == 4 && !strncmp(start, "quot", 4)) { |
508 | 2.57k | value->append('"'); |
509 | 53.1k | } else { |
510 | 53.1k | value->append(start - 1, (int)(parsePtr - start) + 1); |
511 | 53.1k | } |
512 | 64.9k | } |
513 | 83.6k | } else { |
514 | 72.5k | start = parsePtr; |
515 | 72.5k | for (++parsePtr; |
516 | 2.23M | parsePtr < parseEnd && *parsePtr != quote && *parsePtr != '&'; |
517 | 2.16M | ++parsePtr) ; |
518 | 72.5k | value->append(start, (int)(parsePtr - start)); |
519 | 72.5k | } |
520 | 156k | } |
521 | 765k | if (parsePtr < parseEnd && *parsePtr == quote) { |
522 | 764k | ++parsePtr; |
523 | 764k | } |
524 | 765k | return new ZxAttr(name, value); |
525 | 768k | } |
526 | | |
527 | | // this consumes the end tag |
528 | 1.22M | void ZxDoc::parseContent(ZxElement *par) { |
529 | 1.22M | GString *endType; |
530 | | |
531 | 1.22M | endType = (new GString("</"))->append(par->getType()); |
532 | | |
533 | 2.61M | while (parsePtr < parseEnd) { |
534 | 1.38M | if (match(endType->getCString())) { |
535 | 6.35k | parsePtr += endType->getLength(); |
536 | 6.35k | parseSpace(); |
537 | 6.35k | if (match(">")) { |
538 | 2.70k | ++parsePtr; |
539 | 2.70k | } |
540 | 6.35k | break; |
541 | 1.38M | } else if (match("<?")) { |
542 | 3.88k | parsePI(par); |
543 | 1.37M | } else if (match("<![CDATA[")) { |
544 | 5.88k | parseCDSect(par); |
545 | 1.37M | } else if (match("<!--")) { |
546 | 2.02k | parseComment(par); |
547 | 1.37M | } else if (match("<")) { |
548 | 1.29M | parseElement(par); |
549 | 1.29M | } else { |
550 | 72.0k | parseCharData(par); |
551 | 72.0k | } |
552 | 1.38M | } |
553 | | |
554 | 1.22M | delete endType; |
555 | 1.22M | } |
556 | | |
557 | 72.0k | void ZxDoc::parseCharData(ZxElement *par) { |
558 | 72.0k | GString *data; |
559 | 72.0k | const char *start; |
560 | 72.0k | char c; |
561 | 72.0k | unsigned int x; |
562 | 72.0k | int n; |
563 | | |
564 | 72.0k | data = new GString(); |
565 | 369k | while (parsePtr < parseEnd && *parsePtr != '<') { |
566 | 297k | if (*parsePtr == '&') { |
567 | 217k | ++parsePtr; |
568 | 217k | if (parsePtr < parseEnd && *parsePtr == '#') { |
569 | 53.6k | ++parsePtr; |
570 | 53.6k | if (parsePtr < parseEnd && *parsePtr == 'x') { |
571 | 17.6k | ++parsePtr; |
572 | 17.6k | x = 0; |
573 | 94.7k | while (parsePtr < parseEnd) { |
574 | 94.5k | c = *parsePtr; |
575 | 94.5k | if (c >= '0' && c <= '9') { |
576 | 44.4k | x = (x << 4) + (c - '0'); |
577 | 50.1k | } else if (c >= 'a' && c <= 'f') { |
578 | 13.7k | x = (x << 4) + (10 + c - 'a'); |
579 | 36.3k | } else if (c >= 'A' && c <= 'F') { |
580 | 18.9k | x = (x << 4) + (10 + c - 'A'); |
581 | 18.9k | } else { |
582 | 17.4k | break; |
583 | 17.4k | } |
584 | 77.0k | ++parsePtr; |
585 | 77.0k | } |
586 | 17.6k | if (parsePtr < parseEnd && *parsePtr == ';') { |
587 | 4.59k | ++parsePtr; |
588 | 4.59k | } |
589 | 17.6k | appendUTF8(data, x); |
590 | 36.0k | } else { |
591 | 36.0k | x = 0; |
592 | 216k | while (parsePtr < parseEnd) { |
593 | 216k | c = *parsePtr; |
594 | 216k | if (c >= '0' && c <= '9') { |
595 | 180k | x = x * 10 + (c - '0'); |
596 | 180k | } else { |
597 | 35.9k | break; |
598 | 35.9k | } |
599 | 180k | ++parsePtr; |
600 | 180k | } |
601 | 36.0k | if (parsePtr < parseEnd && *parsePtr == ';') { |
602 | 2.58k | ++parsePtr; |
603 | 2.58k | } |
604 | 36.0k | appendUTF8(data, x); |
605 | 36.0k | } |
606 | 164k | } else { |
607 | 164k | start = parsePtr; |
608 | 164k | for (++parsePtr; |
609 | 13.1M | parsePtr < parseEnd && *parsePtr != ';' && |
610 | 13.1M | *parsePtr != '<' && *parsePtr != '&'; |
611 | 12.9M | ++parsePtr) ; |
612 | 164k | n = (int)(parsePtr - start); |
613 | 164k | if (parsePtr < parseEnd && *parsePtr == ';') { |
614 | 15.0k | ++parsePtr; |
615 | 15.0k | } |
616 | 164k | if (n == 2 && !strncmp(start, "lt", 2)) { |
617 | 1.33k | data->append('<'); |
618 | 162k | } else if (n == 2 && !strncmp(start, "gt", 2)) { |
619 | 2.49k | data->append('>'); |
620 | 160k | } else if (n == 3 && !strncmp(start, "amp", 3)) { |
621 | 7.67k | data->append('&'); |
622 | 152k | } else if (n == 4 && !strncmp(start, "apos", 4)) { |
623 | 1.60k | data->append('\''); |
624 | 151k | } else if (n == 4 && !strncmp(start, "quot", 4)) { |
625 | 8.93k | data->append('"'); |
626 | 142k | } else { |
627 | 142k | data->append(start - 1, (int)(parsePtr - start) + 1); |
628 | 142k | } |
629 | 164k | } |
630 | 217k | } else { |
631 | 79.5k | start = parsePtr; |
632 | 79.5k | for (++parsePtr; |
633 | 9.36M | parsePtr < parseEnd && *parsePtr != '<' && *parsePtr != '&'; |
634 | 9.28M | ++parsePtr) ; |
635 | 79.5k | data->append(start, (int)(parsePtr - start)); |
636 | 79.5k | } |
637 | 297k | } |
638 | 72.0k | par->addChild(new ZxCharData(data, true)); |
639 | 72.0k | } |
640 | | |
641 | 72.4k | void ZxDoc::appendUTF8(GString *s, unsigned int c) { |
642 | 72.4k | if (c <= 0x7f) { |
643 | 26.3k | s->append((char)c); |
644 | 46.0k | } else if (c <= 0x7ff) { |
645 | 3.41k | s->append((char)(0xc0 + (c >> 6))); |
646 | 3.41k | s->append((char)(0x80 + (c & 0x3f))); |
647 | 42.6k | } else if (c <= 0xffff) { |
648 | 9.67k | s->append((char)(0xe0 + (c >> 12))); |
649 | 9.67k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
650 | 9.67k | s->append((char)(0x80 + (c & 0x3f))); |
651 | 32.9k | } else if (c <= 0x1fffff) { |
652 | 10.0k | s->append((char)(0xf0 + (c >> 18))); |
653 | 10.0k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
654 | 10.0k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
655 | 10.0k | s->append((char)(0x80 + (c & 0x3f))); |
656 | 22.9k | } else if (c <= 0x3ffffff) { |
657 | 1.91k | s->append((char)(0xf8 + (c >> 24))); |
658 | 1.91k | s->append((char)(0x80 + ((c >> 18) & 0x3f))); |
659 | 1.91k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
660 | 1.91k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
661 | 1.91k | s->append((char)(0x80 + (c & 0x3f))); |
662 | 21.0k | } else if (c <= 0x7fffffff) { |
663 | 18.9k | s->append((char)(0xfc + (c >> 30))); |
664 | 18.9k | s->append((char)(0x80 + ((c >> 24) & 0x3f))); |
665 | 18.9k | s->append((char)(0x80 + ((c >> 18) & 0x3f))); |
666 | 18.9k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
667 | 18.9k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
668 | 18.9k | s->append((char)(0x80 + (c & 0x3f))); |
669 | 18.9k | } |
670 | 72.4k | } |
671 | | |
672 | | // assumes match("<![CDATA[") |
673 | 5.88k | void ZxDoc::parseCDSect(ZxNode *par) { |
674 | 5.88k | const char *start; |
675 | | |
676 | 5.88k | parsePtr += 9; |
677 | 5.88k | start = parsePtr; |
678 | 352k | while (parsePtr < parseEnd - 3) { |
679 | 352k | if (!strncmp(parsePtr, "]]>", 3)) { |
680 | 5.84k | par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)), |
681 | 5.84k | false)); |
682 | 5.84k | parsePtr += 3; |
683 | 5.84k | return; |
684 | 5.84k | } |
685 | 346k | ++parsePtr; |
686 | 346k | } |
687 | 46 | parsePtr = parseEnd; |
688 | 46 | par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)), |
689 | 46 | false)); |
690 | 46 | } |
691 | | |
692 | 11.8k | void ZxDoc::parseMisc(ZxNode *par) { |
693 | 14.5k | while (1) { |
694 | 14.5k | if (match("<!--")) { |
695 | 421 | parseComment(par); |
696 | 14.0k | } else if (match("<?")) { |
697 | 929 | parsePI(par); |
698 | 13.1k | } else if (parsePtr < parseEnd && (*parsePtr == '\x20' || |
699 | 8.54k | *parsePtr == '\x09' || |
700 | 8.54k | *parsePtr == '\x0d' || |
701 | 8.54k | *parsePtr == '\x0a')) { |
702 | 1.32k | ++parsePtr; |
703 | 11.8k | } else { |
704 | 11.8k | break; |
705 | 11.8k | } |
706 | 14.5k | } |
707 | 11.8k | } |
708 | | |
709 | | // assumes match("<!--") |
710 | 2.44k | void ZxDoc::parseComment(ZxNode *par) { |
711 | 2.44k | const char *start; |
712 | | |
713 | 2.44k | parsePtr += 4; |
714 | 2.44k | start = parsePtr; |
715 | 12.9k | while (parsePtr <= parseEnd - 3) { |
716 | 12.9k | if (!strncmp(parsePtr, "-->", 3)) { |
717 | 2.39k | par->addChild(new ZxComment(new GString(start, (int)(parsePtr - start)))); |
718 | 2.39k | parsePtr += 3; |
719 | 2.39k | return; |
720 | 2.39k | } |
721 | 10.5k | ++parsePtr; |
722 | 10.5k | } |
723 | 52 | parsePtr = parseEnd; |
724 | 52 | } |
725 | | |
726 | | // assumes match("<?") |
727 | 4.80k | void ZxDoc::parsePI(ZxNode *par) { |
728 | 4.80k | GString *target; |
729 | 4.80k | const char *start; |
730 | | |
731 | 4.80k | parsePtr += 2; |
732 | 4.80k | target = parseName(); |
733 | 4.80k | parseSpace(); |
734 | 4.80k | start = parsePtr; |
735 | 6.09M | while (parsePtr <= parseEnd - 2) { |
736 | 6.09M | if (!strncmp(parsePtr, "?>", 2)) { |
737 | 4.61k | par->addChild(new ZxPI(target, new GString(start, |
738 | 4.61k | (int)(parsePtr - start)))); |
739 | 4.61k | parsePtr += 2; |
740 | 4.61k | return; |
741 | 4.61k | } |
742 | 6.08M | ++parsePtr; |
743 | 6.08M | } |
744 | 195 | parsePtr = parseEnd; |
745 | 195 | par->addChild(new ZxPI(target, new GString(start, (int)(parsePtr - start)))); |
746 | 195 | } |
747 | | |
748 | | //~ this accepts all chars >= 0x80 |
749 | | //~ this doesn't check for properly-formed UTF-8 |
750 | 3.37M | GString *ZxDoc::parseName() { |
751 | 3.37M | GString *name; |
752 | | |
753 | 3.37M | name = new GString(); |
754 | 3.37M | if (parsePtr < parseEnd && nameStartChar[*parsePtr & 0xff]) { |
755 | 103k | name->append(*parsePtr++); |
756 | 10.3M | while (parsePtr < parseEnd && nameChar[*parsePtr & 0xff]) { |
757 | 10.2M | name->append(*parsePtr++); |
758 | 10.2M | } |
759 | 103k | } |
760 | 3.37M | return name; |
761 | 3.37M | } |
762 | | |
763 | 346 | GString *ZxDoc::parseQuotedString() { |
764 | 346 | GString *s; |
765 | 346 | const char *start; |
766 | 346 | char quote; |
767 | | |
768 | 346 | if (parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\'')) { |
769 | 170 | quote = *parsePtr++; |
770 | 170 | start = parsePtr; |
771 | 10.7k | while (parsePtr < parseEnd && *parsePtr != quote) { |
772 | 10.5k | ++parsePtr; |
773 | 10.5k | } |
774 | 170 | s = new GString(start, (int)(parsePtr - start)); |
775 | 170 | if (parsePtr < parseEnd && *parsePtr == quote) { |
776 | 130 | ++parsePtr; |
777 | 130 | } |
778 | 176 | } else { |
779 | 176 | s = new GString(); |
780 | 176 | } |
781 | 346 | return s; |
782 | 346 | } |
783 | | |
784 | 3.94k | void ZxDoc::parseBOM() { |
785 | 3.94k | if (match("\xef\xbb\xbf")) { |
786 | 36 | parsePtr += 3; |
787 | 36 | } |
788 | 3.94k | } |
789 | | |
790 | 4.92M | void ZxDoc::parseSpace() { |
791 | 5.07M | while (parsePtr < parseEnd && (*parsePtr == '\x20' || |
792 | 5.06M | *parsePtr == '\x09' || |
793 | 5.06M | *parsePtr == '\x0d' || |
794 | 5.06M | *parsePtr == '\x0a')) { |
795 | 144k | ++parsePtr; |
796 | 144k | } |
797 | 4.92M | } |
798 | | |
799 | 11.5M | bool ZxDoc::match(const char *s) { |
800 | 11.5M | int n; |
801 | | |
802 | 11.5M | n = (int)strlen(s); |
803 | 11.5M | return parseEnd - parsePtr >= n && !strncmp(parsePtr, s, n); |
804 | 11.5M | } |
805 | | |
806 | 0 | bool ZxDoc::write(ZxWriteFunc writeFunc, void *stream) { |
807 | 0 | ZxNode *child; |
808 | |
|
809 | 0 | for (child = getFirstChild(); child; child = child->getNextChild()) { |
810 | 0 | if (!child->write(writeFunc, stream)) { |
811 | 0 | return false; |
812 | 0 | } |
813 | 0 | if (!(*writeFunc)(stream, "\n", 1)) { |
814 | 0 | return false; |
815 | 0 | } |
816 | 0 | } |
817 | 0 | return true; |
818 | 0 | } |
819 | | |
820 | | //------------------------------------------------------------------------ |
821 | | |
822 | 804 | ZxXMLDecl::ZxXMLDecl(GString *versionA, GString *encodingA, bool standaloneA) { |
823 | 804 | version = versionA; |
824 | 804 | encoding = encodingA; |
825 | 804 | standalone = standaloneA; |
826 | 804 | } |
827 | | |
828 | 804 | ZxXMLDecl::~ZxXMLDecl() { |
829 | 804 | delete version; |
830 | 804 | if (encoding) { |
831 | 108 | delete encoding; |
832 | 108 | } |
833 | 804 | } |
834 | | |
835 | 0 | bool ZxXMLDecl::write(ZxWriteFunc writeFunc, void *stream) { |
836 | 0 | GString *s; |
837 | 0 | bool ok; |
838 | |
|
839 | 0 | s = new GString("<?xml version=\""); |
840 | 0 | s->append(version); |
841 | 0 | s->append("\""); |
842 | 0 | if (encoding) { |
843 | 0 | s->append(" encoding=\""); |
844 | 0 | s->append(encoding); |
845 | 0 | s->append("\""); |
846 | 0 | } |
847 | 0 | if (standalone) { |
848 | 0 | s->append(" standlone=\"yes\""); |
849 | 0 | } |
850 | 0 | s->append("?>"); |
851 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
852 | 0 | delete s; |
853 | 0 | return ok; |
854 | 0 | } |
855 | | |
856 | | //------------------------------------------------------------------------ |
857 | | |
858 | 225 | ZxDocTypeDecl::ZxDocTypeDecl(GString *nameA) { |
859 | 225 | name = nameA; |
860 | 225 | } |
861 | | |
862 | 225 | ZxDocTypeDecl::~ZxDocTypeDecl() { |
863 | 225 | delete name; |
864 | 225 | } |
865 | | |
866 | 0 | bool ZxDocTypeDecl::write(ZxWriteFunc writeFunc, void *stream) { |
867 | 0 | GString *s; |
868 | 0 | bool ok; |
869 | |
|
870 | 0 | s = new GString("<!DOCTYPE "); |
871 | 0 | s->append(name); |
872 | 0 | s->append(">"); |
873 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
874 | 0 | delete s; |
875 | 0 | return ok; |
876 | 0 | } |
877 | | |
878 | | //------------------------------------------------------------------------ |
879 | | |
880 | 2.39k | ZxComment::ZxComment(GString *textA) { |
881 | 2.39k | text = textA; |
882 | 2.39k | } |
883 | | |
884 | 2.39k | ZxComment::~ZxComment() { |
885 | 2.39k | delete text; |
886 | 2.39k | } |
887 | | |
888 | 0 | bool ZxComment::write(ZxWriteFunc writeFunc, void *stream) { |
889 | 0 | GString *s; |
890 | 0 | bool ok; |
891 | |
|
892 | 0 | s = new GString("<!--"); |
893 | 0 | s->append(text); |
894 | 0 | s->append("-->"); |
895 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
896 | 0 | delete s; |
897 | 0 | return ok; |
898 | 0 | } |
899 | | |
900 | | //------------------------------------------------------------------------ |
901 | | |
902 | 4.80k | ZxPI::ZxPI(GString *targetA, GString *textA) { |
903 | 4.80k | target = targetA; |
904 | 4.80k | text = textA; |
905 | 4.80k | } |
906 | | |
907 | 4.80k | ZxPI::~ZxPI() { |
908 | 4.80k | delete target; |
909 | 4.80k | delete text; |
910 | 4.80k | } |
911 | | |
912 | 0 | bool ZxPI::write(ZxWriteFunc writeFunc, void *stream) { |
913 | 0 | GString *s; |
914 | 0 | bool ok; |
915 | |
|
916 | 0 | s = new GString("<?"); |
917 | 0 | s->append(target); |
918 | 0 | s->append(" "); |
919 | 0 | s->append(text); |
920 | 0 | s->append("?>"); |
921 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
922 | 0 | delete s; |
923 | 0 | return ok; |
924 | 0 | } |
925 | | |
926 | | //------------------------------------------------------------------------ |
927 | | |
928 | 1.30M | ZxElement::ZxElement(GString *typeA) { |
929 | 1.30M | type = typeA; |
930 | 1.30M | attrs = new GHash(); |
931 | 1.30M | firstAttr = lastAttr = NULL; |
932 | 1.30M | } |
933 | | |
934 | 1.30M | ZxElement::~ZxElement() { |
935 | 1.30M | delete type; |
936 | 1.30M | deleteGHash(attrs, ZxAttr); |
937 | 1.30M | } |
938 | | |
939 | 0 | bool ZxElement::isElement(const char *typeA) { |
940 | 0 | return !type->cmp(typeA); |
941 | 0 | } |
942 | | |
943 | 0 | ZxAttr *ZxElement::findAttr(const char *attrName) { |
944 | 0 | return (ZxAttr *)attrs->lookup(attrName); |
945 | 0 | } |
946 | | |
947 | 765k | void ZxElement::addAttr(ZxAttr *attr) { |
948 | 765k | attrs->add(attr->getName(), attr); |
949 | 765k | if (lastAttr) { |
950 | 731k | lastAttr->next = attr; |
951 | 731k | lastAttr= attr; |
952 | 731k | } else { |
953 | 33.7k | firstAttr = lastAttr = attr; |
954 | 33.7k | } |
955 | 765k | attr->parent = this; |
956 | 765k | attr->next = NULL; |
957 | 765k | } |
958 | | |
959 | 0 | bool ZxElement::write(ZxWriteFunc writeFunc, void *stream) { |
960 | 0 | GString *s; |
961 | 0 | ZxAttr *attr; |
962 | 0 | ZxNode *child; |
963 | 0 | bool ok; |
964 | |
|
965 | 0 | s = new GString("<"); |
966 | 0 | s->append(type); |
967 | 0 | for (attr = firstAttr; attr; attr = attr->getNextAttr()) { |
968 | 0 | s->append(" "); |
969 | 0 | s->append(attr->name); |
970 | 0 | s->append("=\""); |
971 | 0 | appendEscapedAttrValue(s, attr->value); |
972 | 0 | s->append("\""); |
973 | 0 | } |
974 | 0 | if ((child = getFirstChild())) { |
975 | 0 | s->append(">"); |
976 | 0 | } else { |
977 | 0 | s->append("/>"); |
978 | 0 | } |
979 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
980 | 0 | delete s; |
981 | 0 | if (!ok) { |
982 | 0 | return false; |
983 | 0 | } |
984 | 0 | if (child) { |
985 | 0 | for (; child; child = child->getNextChild()) { |
986 | 0 | if (!child->write(writeFunc, stream)) { |
987 | 0 | return false; |
988 | 0 | } |
989 | 0 | } |
990 | 0 | s = new GString(); |
991 | 0 | s->append("</"); |
992 | 0 | s->append(type); |
993 | 0 | s->append(">"); |
994 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
995 | 0 | delete s; |
996 | 0 | if (!ok) { |
997 | 0 | return false; |
998 | 0 | } |
999 | 0 | } |
1000 | 0 | return true; |
1001 | 0 | } |
1002 | | |
1003 | 0 | void ZxElement::appendEscapedAttrValue(GString *out, GString *s) { |
1004 | 0 | char c; |
1005 | 0 | int i; |
1006 | |
|
1007 | 0 | for (i = 0; i < s->getLength(); ++i) { |
1008 | 0 | c = s->getChar(i); |
1009 | 0 | if (c == '<') { |
1010 | 0 | out->append("<"); |
1011 | 0 | } else if (c == '>') { |
1012 | 0 | out->append(">"); |
1013 | 0 | } else if (c == '&') { |
1014 | 0 | out->append("&"); |
1015 | 0 | } else if (c == '"') { |
1016 | 0 | out->append("""); |
1017 | 0 | } else { |
1018 | 0 | out->append(c); |
1019 | 0 | } |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | | //------------------------------------------------------------------------ |
1024 | | |
1025 | 765k | ZxAttr::ZxAttr(GString *nameA, GString *valueA) { |
1026 | 765k | name = nameA; |
1027 | 765k | value = valueA; |
1028 | 765k | parent = NULL; |
1029 | 765k | next = NULL; |
1030 | 765k | } |
1031 | | |
1032 | 765k | ZxAttr::~ZxAttr() { |
1033 | 765k | delete name; |
1034 | 765k | delete value; |
1035 | 765k | } |
1036 | | |
1037 | | //------------------------------------------------------------------------ |
1038 | | |
1039 | 77.9k | ZxCharData::ZxCharData(GString *dataA, bool parsedA) { |
1040 | 77.9k | data = dataA; |
1041 | 77.9k | parsed = parsedA; |
1042 | 77.9k | } |
1043 | | |
1044 | 77.9k | ZxCharData::~ZxCharData() { |
1045 | 77.9k | delete data; |
1046 | 77.9k | } |
1047 | | |
1048 | 0 | bool ZxCharData::write(ZxWriteFunc writeFunc, void *stream) { |
1049 | 0 | GString *s; |
1050 | 0 | char c; |
1051 | 0 | int i; |
1052 | 0 | bool ok; |
1053 | |
|
1054 | 0 | s = new GString(); |
1055 | 0 | if (parsed) { |
1056 | 0 | for (i = 0; i < data->getLength(); ++i) { |
1057 | 0 | c = data->getChar(i); |
1058 | 0 | if (c == '<') { |
1059 | 0 | s->append("<"); |
1060 | 0 | } else if (c == '>') { |
1061 | 0 | s->append(">"); |
1062 | 0 | } else if (c == '&') { |
1063 | 0 | s->append("&"); |
1064 | 0 | } else { |
1065 | 0 | s->append(c); |
1066 | 0 | } |
1067 | 0 | } |
1068 | 0 | } else { |
1069 | 0 | s->append("<![CDATA["); |
1070 | 0 | s->append(data); |
1071 | 0 | s->append("]]>"); |
1072 | 0 | } |
1073 | 0 | ok = (*writeFunc)(stream, s->getCString(), s->getLength()); |
1074 | 0 | delete s; |
1075 | 0 | return ok; |
1076 | 0 | } |