/src/xpdf-4.06/xpdf/Zoox.cc
Line | Count | Source |
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 | 4.84M | ZxNode::ZxNode() { |
65 | 4.84M | next = NULL; |
66 | 4.84M | parent = NULL; |
67 | 4.84M | firstChild = lastChild = NULL; |
68 | 4.84M | } |
69 | | |
70 | 4.84M | ZxNode::~ZxNode() { |
71 | 4.84M | ZxNode *child; |
72 | | |
73 | 9.67M | while (firstChild) { |
74 | 4.83M | child = firstChild; |
75 | 4.83M | firstChild = firstChild->next; |
76 | 4.83M | delete child; |
77 | 4.83M | } |
78 | 4.84M | } |
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 | 523k | ZxElement *ZxNode::findFirstChildElement(const char *type) { |
144 | 523k | ZxNode *child; |
145 | | |
146 | 1.85M | for (child = firstChild; child; child = child->next) { |
147 | 1.35M | if (child->isElement(type)) { |
148 | 20.7k | return (ZxElement *)child; |
149 | 20.7k | } |
150 | 1.35M | } |
151 | 502k | return NULL; |
152 | 523k | } |
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 | 4.83M | void ZxNode::addChild(ZxNode *child) { |
187 | 4.83M | if (lastChild) { |
188 | 3.16M | lastChild->next = child; |
189 | 3.16M | lastChild = child; |
190 | 3.16M | } else { |
191 | 1.66M | firstChild = lastChild = child; |
192 | 1.66M | } |
193 | 4.83M | child->parent = this; |
194 | 4.83M | child->next = NULL; |
195 | 4.83M | } |
196 | | |
197 | | //------------------------------------------------------------------------ |
198 | | |
199 | 9.62k | ZxDoc::ZxDoc() { |
200 | 9.62k | xmlDecl = NULL; |
201 | 9.62k | docTypeDecl = NULL; |
202 | 9.62k | root = NULL; |
203 | 9.62k | } |
204 | | |
205 | 5.84k | ZxDoc *ZxDoc::loadMem(const char *data, Guint dataLen) { |
206 | 5.84k | ZxDoc *doc; |
207 | | |
208 | 5.84k | doc = new ZxDoc(); |
209 | 5.84k | if (!doc->parse(data, dataLen)) { |
210 | 1.88k | delete doc; |
211 | 1.88k | return NULL; |
212 | 1.88k | } |
213 | 3.95k | return doc; |
214 | 5.84k | } |
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 | 8.64k | void ZxDoc::addChild(ZxNode *node) { |
263 | 8.64k | if (node->isXMLDecl() && !xmlDecl) { |
264 | 1.61k | xmlDecl = (ZxXMLDecl *)node; |
265 | 7.02k | } else if (node->isDocTypeDecl() && !docTypeDecl) { |
266 | 413 | docTypeDecl = (ZxDocTypeDecl *)node; |
267 | 6.61k | } else if (node->isElement() && !root) { |
268 | 3.95k | root = (ZxElement *)node; |
269 | 3.95k | } |
270 | 8.64k | ZxNode::addChild(node); |
271 | 8.64k | } |
272 | | |
273 | 5.84k | bool ZxDoc::parse(const char *data, Guint dataLen) { |
274 | 5.84k | parsePtr = data; |
275 | 5.84k | parseEnd = data + dataLen; |
276 | | |
277 | 5.84k | parseSpace(); |
278 | 5.84k | parseBOM(); |
279 | 5.84k | parseSpace(); |
280 | 5.84k | parseXMLDecl(this); |
281 | 5.84k | parseMisc(this); |
282 | 5.84k | parseDocTypeDecl(this); |
283 | 5.84k | parseMisc(this); |
284 | 5.84k | if (match("<")) { |
285 | 3.95k | parseElement(this); |
286 | 3.95k | } |
287 | 5.84k | parseMisc(this); |
288 | 5.84k | return root != NULL; |
289 | 5.84k | } |
290 | | |
291 | 5.84k | void ZxDoc::parseXMLDecl(ZxNode *par) { |
292 | 5.84k | GString *version, *encoding, *s; |
293 | 5.84k | bool standalone; |
294 | | |
295 | 5.84k | if (!match("<?xml")) { |
296 | 4.22k | return; |
297 | 4.22k | } |
298 | 1.61k | parsePtr += 5; |
299 | 1.61k | parseSpace(); |
300 | | |
301 | | // version |
302 | 1.61k | version = NULL; |
303 | 1.61k | if (match("version")) { |
304 | 986 | parsePtr += 7; |
305 | 986 | parseSpace(); |
306 | 986 | if (match("=")) { |
307 | 894 | ++parsePtr; |
308 | 894 | parseSpace(); |
309 | 894 | version = parseQuotedString(); |
310 | 894 | } |
311 | 986 | } |
312 | 1.61k | if (!version) { |
313 | 721 | version = new GString("1.0"); |
314 | 721 | } |
315 | 1.61k | parseSpace(); |
316 | | |
317 | | // encoding |
318 | 1.61k | encoding = NULL; |
319 | 1.61k | if (match("encoding")) { |
320 | 818 | parsePtr += 8; |
321 | 818 | parseSpace(); |
322 | 818 | if (match("=")) { |
323 | 730 | ++parsePtr; |
324 | 730 | parseSpace(); |
325 | 730 | encoding = parseQuotedString(); |
326 | 730 | } |
327 | 818 | } |
328 | 1.61k | parseSpace(); |
329 | | |
330 | | // standalone |
331 | 1.61k | standalone = false; |
332 | 1.61k | if (match("standalone")) { |
333 | 267 | parsePtr += 10; |
334 | 267 | parseSpace(); |
335 | 267 | if (match("=")) { |
336 | 181 | ++parsePtr; |
337 | 181 | parseSpace(); |
338 | 181 | s = parseQuotedString(); |
339 | 181 | standalone = !s->cmp("yes"); |
340 | 181 | delete s; |
341 | 181 | } |
342 | 267 | } |
343 | 1.61k | parseSpace(); |
344 | | |
345 | 1.61k | if (match("?>")) { |
346 | 556 | parsePtr += 2; |
347 | 556 | } |
348 | | |
349 | 1.61k | par->addChild(new ZxXMLDecl(version, encoding, standalone)); |
350 | 1.61k | } |
351 | | |
352 | | //~ this just skips everything after the name |
353 | 5.84k | void ZxDoc::parseDocTypeDecl(ZxNode *par) { |
354 | 5.84k | GString *name; |
355 | 5.84k | int state; |
356 | 5.84k | char c, quote; |
357 | | |
358 | 5.84k | if (!match("<!DOCTYPE")) { |
359 | 5.43k | return; |
360 | 5.43k | } |
361 | 413 | parsePtr += 9; |
362 | 413 | parseSpace(); |
363 | | |
364 | 413 | name = parseName(); |
365 | 413 | parseSpace(); |
366 | | |
367 | 413 | state = 0; |
368 | 413 | quote = '\0'; |
369 | 376k | while (parsePtr < parseEnd && state < 4) { |
370 | 376k | c = *parsePtr++; |
371 | 376k | switch (state) { |
372 | 40.4k | case 0: // not in square brackets; not in quotes |
373 | 40.4k | if (c == '>') { |
374 | 76 | state = 4; |
375 | 40.3k | } else if (c == '"' || c == '\'') { |
376 | 1.02k | state = 1; |
377 | 39.3k | } else if (c == '[') { |
378 | 1.00k | state = 2; |
379 | 1.00k | } |
380 | 40.4k | break; |
381 | 17.8k | case 1: // not in square brackets; in quotes |
382 | 17.8k | if (c == quote) { |
383 | 971 | state = 0; |
384 | 971 | } |
385 | 17.8k | break; |
386 | 247k | case 2: // in square brackets; not in quotes |
387 | 247k | if (c == ']') { |
388 | 876 | state = 0; |
389 | 246k | } else if (c == '"' || c == '\'') { |
390 | 1.91k | state = 3; |
391 | 1.91k | } |
392 | 247k | break; |
393 | 70.7k | case 3: // in square brackets; in quotes |
394 | 70.7k | if (c == quote) { |
395 | 1.86k | state = 2; |
396 | 1.86k | } |
397 | 70.7k | break; |
398 | 376k | } |
399 | 376k | } |
400 | | |
401 | 413 | par->addChild(new ZxDocTypeDecl(name)); |
402 | 413 | } |
403 | | |
404 | | // assumes match("<") |
405 | 3.31M | void ZxDoc::parseElement(ZxNode *par) { |
406 | 3.31M | GString *type; |
407 | 3.31M | ZxElement *elem; |
408 | 3.31M | ZxAttr *attr; |
409 | | |
410 | 3.31M | ++parsePtr; |
411 | 3.31M | type = parseName(); |
412 | 3.31M | elem = new ZxElement(type); |
413 | 3.31M | parseSpace(); |
414 | 4.46M | while ((attr = parseAttr())) { |
415 | 1.15M | elem->addAttr(attr); |
416 | 1.15M | parseSpace(); |
417 | 1.15M | } |
418 | 3.31M | if (match("/>")) { |
419 | 85.2k | parsePtr += 2; |
420 | 3.22M | } else if (match(">")) { |
421 | 1.66M | ++parsePtr; |
422 | 1.66M | parseContent(elem); |
423 | 1.66M | } |
424 | 3.31M | par->addChild(elem); |
425 | 3.31M | } |
426 | | |
427 | 4.46M | ZxAttr *ZxDoc::parseAttr() { |
428 | 4.46M | GString *name, *value; |
429 | 4.46M | const char *start; |
430 | 4.46M | char quote, c; |
431 | 4.46M | unsigned int x; |
432 | 4.46M | int n; |
433 | | |
434 | 4.46M | name = parseName(); |
435 | 4.46M | parseSpace(); |
436 | 4.46M | if (!match("=")) { |
437 | 3.27M | delete name; |
438 | 3.27M | return NULL; |
439 | 3.27M | } |
440 | 1.19M | ++parsePtr; |
441 | 1.19M | parseSpace(); |
442 | 1.19M | if (!(parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\''))) { |
443 | 40.1k | delete name; |
444 | 40.1k | return NULL; |
445 | 40.1k | } |
446 | 1.15M | quote = *parsePtr++; |
447 | 1.15M | value = new GString(); |
448 | 1.80M | while (parsePtr < parseEnd && *parsePtr != quote) { |
449 | 651k | if (*parsePtr == '&') { |
450 | 277k | ++parsePtr; |
451 | 277k | if (parsePtr < parseEnd && *parsePtr == '#') { |
452 | 51.3k | ++parsePtr; |
453 | 51.3k | if (parsePtr < parseEnd && *parsePtr == 'x') { |
454 | 21.5k | ++parsePtr; |
455 | 21.5k | x = 0; |
456 | 80.0k | while (parsePtr < parseEnd) { |
457 | 79.9k | c = *parsePtr; |
458 | 79.9k | if (c >= '0' && c <= '9') { |
459 | 11.0k | x = (x << 4) + (c - '0'); |
460 | 68.9k | } else if (c >= 'a' && c <= 'f') { |
461 | 20.0k | x = (x << 4) + (10 + c - 'a'); |
462 | 48.9k | } else if (c >= 'A' && c <= 'F') { |
463 | 27.4k | x = (x << 4) + (10 + c - 'A'); |
464 | 27.4k | } else { |
465 | 21.5k | break; |
466 | 21.5k | } |
467 | 58.4k | ++parsePtr; |
468 | 58.4k | } |
469 | 21.5k | if (parsePtr < parseEnd && *parsePtr == ';') { |
470 | 3.01k | ++parsePtr; |
471 | 3.01k | } |
472 | 21.5k | appendUTF8(value, x); |
473 | 29.7k | } else { |
474 | 29.7k | x = 0; |
475 | 86.4k | while (parsePtr < parseEnd) { |
476 | 86.4k | c = *parsePtr; |
477 | 86.4k | if (c >= '0' && c <= '9') { |
478 | 56.7k | x = x * 10 + (c - '0'); |
479 | 56.7k | } else { |
480 | 29.7k | break; |
481 | 29.7k | } |
482 | 56.7k | ++parsePtr; |
483 | 56.7k | } |
484 | 29.7k | if (parsePtr < parseEnd && *parsePtr == ';') { |
485 | 1.96k | ++parsePtr; |
486 | 1.96k | } |
487 | 29.7k | appendUTF8(value, x); |
488 | 29.7k | } |
489 | 226k | } else { |
490 | 226k | start = parsePtr; |
491 | 226k | for (++parsePtr; |
492 | 27.4M | parsePtr < parseEnd && *parsePtr != ';' && |
493 | 27.4M | *parsePtr != quote && *parsePtr != '&'; |
494 | 27.2M | ++parsePtr) ; |
495 | 226k | n = (int)(parsePtr - start); |
496 | 226k | if (parsePtr < parseEnd && *parsePtr == ';') { |
497 | 3.26k | ++parsePtr; |
498 | 3.26k | } |
499 | 226k | if (n == 2 && !strncmp(start, "lt", 2)) { |
500 | 1.46k | value->append('<'); |
501 | 224k | } else if (n == 2 && !strncmp(start, "gt", 2)) { |
502 | 15.1k | value->append('>'); |
503 | 209k | } else if (n == 3 && !strncmp(start, "amp", 3)) { |
504 | 14.6k | value->append('&'); |
505 | 195k | } else if (n == 4 && !strncmp(start, "apos", 4)) { |
506 | 1.18k | value->append('\''); |
507 | 193k | } else if (n == 4 && !strncmp(start, "quot", 4)) { |
508 | 3.18k | value->append('"'); |
509 | 190k | } else { |
510 | 190k | value->append(start - 1, (int)(parsePtr - start) + 1); |
511 | 190k | } |
512 | 226k | } |
513 | 373k | } else { |
514 | 373k | start = parsePtr; |
515 | 373k | for (++parsePtr; |
516 | 22.8M | parsePtr < parseEnd && *parsePtr != quote && *parsePtr != '&'; |
517 | 22.4M | ++parsePtr) ; |
518 | 373k | value->append(start, (int)(parsePtr - start)); |
519 | 373k | } |
520 | 651k | } |
521 | 1.15M | if (parsePtr < parseEnd && *parsePtr == quote) { |
522 | 1.15M | ++parsePtr; |
523 | 1.15M | } |
524 | 1.15M | return new ZxAttr(name, value); |
525 | 1.19M | } |
526 | | |
527 | | // this consumes the end tag |
528 | 1.66M | void ZxDoc::parseContent(ZxElement *par) { |
529 | 1.66M | GString *endType; |
530 | | |
531 | 1.66M | endType = (new GString("</"))->append(par->getType()); |
532 | | |
533 | 6.48M | while (parsePtr < parseEnd) { |
534 | 4.94M | if (match(endType->getCString())) { |
535 | 125k | parsePtr += endType->getLength(); |
536 | 125k | parseSpace(); |
537 | 125k | if (match(">")) { |
538 | 84.0k | ++parsePtr; |
539 | 84.0k | } |
540 | 125k | break; |
541 | 4.82M | } else if (match("<?")) { |
542 | 50.2k | parsePI(par); |
543 | 4.77M | } else if (match("<![CDATA[")) { |
544 | 4.16k | parseCDSect(par); |
545 | 4.76M | } else if (match("<!--")) { |
546 | 4.27k | parseComment(par); |
547 | 4.76M | } else if (match("<")) { |
548 | 3.30M | parseElement(par); |
549 | 3.30M | } else { |
550 | 1.45M | parseCharData(par); |
551 | 1.45M | } |
552 | 4.94M | } |
553 | | |
554 | 1.66M | delete endType; |
555 | 1.66M | } |
556 | | |
557 | 1.45M | void ZxDoc::parseCharData(ZxElement *par) { |
558 | 1.45M | GString *data; |
559 | 1.45M | const char *start; |
560 | 1.45M | char c; |
561 | 1.45M | unsigned int x; |
562 | 1.45M | int n; |
563 | | |
564 | 1.45M | data = new GString(); |
565 | 4.26M | while (parsePtr < parseEnd && *parsePtr != '<') { |
566 | 2.81M | if (*parsePtr == '&') { |
567 | 1.34M | ++parsePtr; |
568 | 1.34M | if (parsePtr < parseEnd && *parsePtr == '#') { |
569 | 120k | ++parsePtr; |
570 | 120k | if (parsePtr < parseEnd && *parsePtr == 'x') { |
571 | 36.7k | ++parsePtr; |
572 | 36.7k | x = 0; |
573 | 170k | while (parsePtr < parseEnd) { |
574 | 170k | c = *parsePtr; |
575 | 170k | if (c >= '0' && c <= '9') { |
576 | 45.8k | x = (x << 4) + (c - '0'); |
577 | 124k | } else if (c >= 'a' && c <= 'f') { |
578 | 36.9k | x = (x << 4) + (10 + c - 'a'); |
579 | 87.5k | } else if (c >= 'A' && c <= 'F') { |
580 | 51.0k | x = (x << 4) + (10 + c - 'A'); |
581 | 51.0k | } else { |
582 | 36.5k | break; |
583 | 36.5k | } |
584 | 133k | ++parsePtr; |
585 | 133k | } |
586 | 36.7k | if (parsePtr < parseEnd && *parsePtr == ';') { |
587 | 6.74k | ++parsePtr; |
588 | 6.74k | } |
589 | 36.7k | appendUTF8(data, x); |
590 | 84.1k | } else { |
591 | 84.1k | x = 0; |
592 | 341k | while (parsePtr < parseEnd) { |
593 | 341k | c = *parsePtr; |
594 | 341k | if (c >= '0' && c <= '9') { |
595 | 257k | x = x * 10 + (c - '0'); |
596 | 257k | } else { |
597 | 84.0k | break; |
598 | 84.0k | } |
599 | 257k | ++parsePtr; |
600 | 257k | } |
601 | 84.1k | if (parsePtr < parseEnd && *parsePtr == ';') { |
602 | 12.0k | ++parsePtr; |
603 | 12.0k | } |
604 | 84.1k | appendUTF8(data, x); |
605 | 84.1k | } |
606 | 1.22M | } else { |
607 | 1.22M | start = parsePtr; |
608 | 1.22M | for (++parsePtr; |
609 | 52.0M | parsePtr < parseEnd && *parsePtr != ';' && |
610 | 52.0M | *parsePtr != '<' && *parsePtr != '&'; |
611 | 50.7M | ++parsePtr) ; |
612 | 1.22M | n = (int)(parsePtr - start); |
613 | 1.22M | if (parsePtr < parseEnd && *parsePtr == ';') { |
614 | 7.81k | ++parsePtr; |
615 | 7.81k | } |
616 | 1.22M | if (n == 2 && !strncmp(start, "lt", 2)) { |
617 | 4.09k | data->append('<'); |
618 | 1.22M | } else if (n == 2 && !strncmp(start, "gt", 2)) { |
619 | 95.7k | data->append('>'); |
620 | 1.12M | } else if (n == 3 && !strncmp(start, "amp", 3)) { |
621 | 33.8k | data->append('&'); |
622 | 1.09M | } else if (n == 4 && !strncmp(start, "apos", 4)) { |
623 | 1.38k | data->append('\''); |
624 | 1.09M | } else if (n == 4 && !strncmp(start, "quot", 4)) { |
625 | 18.7k | data->append('"'); |
626 | 1.07M | } else { |
627 | 1.07M | data->append(start - 1, (int)(parsePtr - start) + 1); |
628 | 1.07M | } |
629 | 1.22M | } |
630 | 1.46M | } else { |
631 | 1.46M | start = parsePtr; |
632 | 1.46M | for (++parsePtr; |
633 | 64.0M | parsePtr < parseEnd && *parsePtr != '<' && *parsePtr != '&'; |
634 | 62.6M | ++parsePtr) ; |
635 | 1.46M | data->append(start, (int)(parsePtr - start)); |
636 | 1.46M | } |
637 | 2.81M | } |
638 | 1.45M | par->addChild(new ZxCharData(data, true)); |
639 | 1.45M | } |
640 | | |
641 | 172k | void ZxDoc::appendUTF8(GString *s, unsigned int c) { |
642 | 172k | if (c <= 0x7f) { |
643 | 99.7k | s->append((char)c); |
644 | 99.7k | } else if (c <= 0x7ff) { |
645 | 10.1k | s->append((char)(0xc0 + (c >> 6))); |
646 | 10.1k | s->append((char)(0x80 + (c & 0x3f))); |
647 | 62.3k | } else if (c <= 0xffff) { |
648 | 15.8k | s->append((char)(0xe0 + (c >> 12))); |
649 | 15.8k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
650 | 15.8k | s->append((char)(0x80 + (c & 0x3f))); |
651 | 46.4k | } else if (c <= 0x1fffff) { |
652 | 16.0k | s->append((char)(0xf0 + (c >> 18))); |
653 | 16.0k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
654 | 16.0k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
655 | 16.0k | s->append((char)(0x80 + (c & 0x3f))); |
656 | 30.4k | } else if (c <= 0x3ffffff) { |
657 | 6.91k | s->append((char)(0xf8 + (c >> 24))); |
658 | 6.91k | s->append((char)(0x80 + ((c >> 18) & 0x3f))); |
659 | 6.91k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
660 | 6.91k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
661 | 6.91k | s->append((char)(0x80 + (c & 0x3f))); |
662 | 23.5k | } else if (c <= 0x7fffffff) { |
663 | 16.5k | s->append((char)(0xfc + (c >> 30))); |
664 | 16.5k | s->append((char)(0x80 + ((c >> 24) & 0x3f))); |
665 | 16.5k | s->append((char)(0x80 + ((c >> 18) & 0x3f))); |
666 | 16.5k | s->append((char)(0x80 + ((c >> 12) & 0x3f))); |
667 | 16.5k | s->append((char)(0x80 + ((c >> 6) & 0x3f))); |
668 | 16.5k | s->append((char)(0x80 + (c & 0x3f))); |
669 | 16.5k | } |
670 | 172k | } |
671 | | |
672 | | // assumes match("<![CDATA[") |
673 | 4.16k | void ZxDoc::parseCDSect(ZxNode *par) { |
674 | 4.16k | const char *start; |
675 | | |
676 | 4.16k | parsePtr += 9; |
677 | 4.16k | start = parsePtr; |
678 | 665k | while (parsePtr < parseEnd - 3) { |
679 | 665k | if (!strncmp(parsePtr, "]]>", 3)) { |
680 | 4.10k | par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)), |
681 | 4.10k | false)); |
682 | 4.10k | parsePtr += 3; |
683 | 4.10k | return; |
684 | 4.10k | } |
685 | 660k | ++parsePtr; |
686 | 660k | } |
687 | 64 | parsePtr = parseEnd; |
688 | 64 | par->addChild(new ZxCharData(new GString(start, (int)(parsePtr - start)), |
689 | 64 | false)); |
690 | 64 | } |
691 | | |
692 | 17.5k | void ZxDoc::parseMisc(ZxNode *par) { |
693 | 38.2k | while (1) { |
694 | 38.2k | if (match("<!--")) { |
695 | 1.25k | parseComment(par); |
696 | 36.9k | } else if (match("<?")) { |
697 | 1.46k | parsePI(par); |
698 | 35.5k | } else if (parsePtr < parseEnd && (*parsePtr == '\x20' || |
699 | 24.3k | *parsePtr == '\x09' || |
700 | 15.0k | *parsePtr == '\x0d' || |
701 | 18.0k | *parsePtr == '\x0a')) { |
702 | 18.0k | ++parsePtr; |
703 | 18.0k | } else { |
704 | 17.5k | break; |
705 | 17.5k | } |
706 | 38.2k | } |
707 | 17.5k | } |
708 | | |
709 | | // assumes match("<!--") |
710 | 5.53k | void ZxDoc::parseComment(ZxNode *par) { |
711 | 5.53k | const char *start; |
712 | | |
713 | 5.53k | parsePtr += 4; |
714 | 5.53k | start = parsePtr; |
715 | 1.70M | while (parsePtr <= parseEnd - 3) { |
716 | 1.70M | if (!strncmp(parsePtr, "-->", 3)) { |
717 | 5.44k | par->addChild(new ZxComment(new GString(start, (int)(parsePtr - start)))); |
718 | 5.44k | parsePtr += 3; |
719 | 5.44k | return; |
720 | 5.44k | } |
721 | 1.70M | ++parsePtr; |
722 | 1.70M | } |
723 | 93 | parsePtr = parseEnd; |
724 | 93 | } |
725 | | |
726 | | // assumes match("<?") |
727 | 51.7k | void ZxDoc::parsePI(ZxNode *par) { |
728 | 51.7k | GString *target; |
729 | 51.7k | const char *start; |
730 | | |
731 | 51.7k | parsePtr += 2; |
732 | 51.7k | target = parseName(); |
733 | 51.7k | parseSpace(); |
734 | 51.7k | start = parsePtr; |
735 | 11.4M | while (parsePtr <= parseEnd - 2) { |
736 | 11.4M | if (!strncmp(parsePtr, "?>", 2)) { |
737 | 51.3k | par->addChild(new ZxPI(target, new GString(start, |
738 | 51.3k | (int)(parsePtr - start)))); |
739 | 51.3k | parsePtr += 2; |
740 | 51.3k | return; |
741 | 51.3k | } |
742 | 11.3M | ++parsePtr; |
743 | 11.3M | } |
744 | 370 | parsePtr = parseEnd; |
745 | 370 | par->addChild(new ZxPI(target, new GString(start, (int)(parsePtr - start)))); |
746 | 370 | } |
747 | | |
748 | | //~ this accepts all chars >= 0x80 |
749 | | //~ this doesn't check for properly-formed UTF-8 |
750 | 7.83M | GString *ZxDoc::parseName() { |
751 | 7.83M | GString *name; |
752 | | |
753 | 7.83M | name = new GString(); |
754 | 7.83M | if (parsePtr < parseEnd && nameStartChar[*parsePtr & 0xff]) { |
755 | 2.23M | name->append(*parsePtr++); |
756 | 20.5M | while (parsePtr < parseEnd && nameChar[*parsePtr & 0xff]) { |
757 | 18.3M | name->append(*parsePtr++); |
758 | 18.3M | } |
759 | 2.23M | } |
760 | 7.83M | return name; |
761 | 7.83M | } |
762 | | |
763 | 1.80k | GString *ZxDoc::parseQuotedString() { |
764 | 1.80k | GString *s; |
765 | 1.80k | const char *start; |
766 | 1.80k | char quote; |
767 | | |
768 | 1.80k | if (parsePtr < parseEnd && (*parsePtr == '"' || *parsePtr == '\'')) { |
769 | 1.52k | quote = *parsePtr++; |
770 | 1.52k | start = parsePtr; |
771 | 41.4k | while (parsePtr < parseEnd && *parsePtr != quote) { |
772 | 39.9k | ++parsePtr; |
773 | 39.9k | } |
774 | 1.52k | s = new GString(start, (int)(parsePtr - start)); |
775 | 1.52k | if (parsePtr < parseEnd && *parsePtr == quote) { |
776 | 1.47k | ++parsePtr; |
777 | 1.47k | } |
778 | 1.52k | } else { |
779 | 281 | s = new GString(); |
780 | 281 | } |
781 | 1.80k | return s; |
782 | 1.80k | } |
783 | | |
784 | 5.84k | void ZxDoc::parseBOM() { |
785 | 5.84k | if (match("\xef\xbb\xbf")) { |
786 | 59 | parsePtr += 3; |
787 | 59 | } |
788 | 5.84k | } |
789 | | |
790 | 10.3M | void ZxDoc::parseSpace() { |
791 | 12.8M | while (parsePtr < parseEnd && (*parsePtr == '\x20' || |
792 | 10.9M | *parsePtr == '\x09' || |
793 | 10.8M | *parsePtr == '\x0d' || |
794 | 10.7M | *parsePtr == '\x0a')) { |
795 | 2.54M | ++parsePtr; |
796 | 2.54M | } |
797 | 10.3M | } |
798 | | |
799 | 35.3M | bool ZxDoc::match(const char *s) { |
800 | 35.3M | int n; |
801 | | |
802 | 35.3M | n = (int)strlen(s); |
803 | 35.3M | return parseEnd - parsePtr >= n && !strncmp(parsePtr, s, n); |
804 | 35.3M | } |
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 | 1.61k | ZxXMLDecl::ZxXMLDecl(GString *versionA, GString *encodingA, bool standaloneA) { |
823 | 1.61k | version = versionA; |
824 | 1.61k | encoding = encodingA; |
825 | 1.61k | standalone = standaloneA; |
826 | 1.61k | } |
827 | | |
828 | 1.61k | ZxXMLDecl::~ZxXMLDecl() { |
829 | 1.61k | delete version; |
830 | 1.61k | if (encoding) { |
831 | 730 | delete encoding; |
832 | 730 | } |
833 | 1.61k | } |
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 | 413 | ZxDocTypeDecl::ZxDocTypeDecl(GString *nameA) { |
859 | 413 | name = nameA; |
860 | 413 | } |
861 | | |
862 | 413 | ZxDocTypeDecl::~ZxDocTypeDecl() { |
863 | 413 | delete name; |
864 | 413 | } |
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 | 5.44k | ZxComment::ZxComment(GString *textA) { |
881 | 5.44k | text = textA; |
882 | 5.44k | } |
883 | | |
884 | 5.44k | ZxComment::~ZxComment() { |
885 | 5.44k | delete text; |
886 | 5.44k | } |
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 | 51.7k | ZxPI::ZxPI(GString *targetA, GString *textA) { |
903 | 51.7k | target = targetA; |
904 | 51.7k | text = textA; |
905 | 51.7k | } |
906 | | |
907 | 51.7k | ZxPI::~ZxPI() { |
908 | 51.7k | delete target; |
909 | 51.7k | delete text; |
910 | 51.7k | } |
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 | 3.31M | ZxElement::ZxElement(GString *typeA) { |
929 | 3.31M | type = typeA; |
930 | 3.31M | attrs = new GHash(); |
931 | 3.31M | firstAttr = lastAttr = NULL; |
932 | 3.31M | } |
933 | | |
934 | 3.31M | ZxElement::~ZxElement() { |
935 | 3.31M | delete type; |
936 | 3.31M | deleteGHash(attrs, ZxAttr); |
937 | 3.31M | } |
938 | | |
939 | 4.24M | bool ZxElement::isElement(const char *typeA) { |
940 | 4.24M | return !type->cmp(typeA); |
941 | 4.24M | } |
942 | | |
943 | 880k | ZxAttr *ZxElement::findAttr(const char *attrName) { |
944 | 880k | return (ZxAttr *)attrs->lookup(attrName); |
945 | 880k | } |
946 | | |
947 | 1.15M | void ZxElement::addAttr(ZxAttr *attr) { |
948 | 1.15M | attrs->add(attr->getName(), attr); |
949 | 1.15M | if (lastAttr) { |
950 | 951k | lastAttr->next = attr; |
951 | 951k | lastAttr= attr; |
952 | 951k | } else { |
953 | 204k | firstAttr = lastAttr = attr; |
954 | 204k | } |
955 | 1.15M | attr->parent = this; |
956 | 1.15M | attr->next = NULL; |
957 | 1.15M | } |
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 | 1.15M | ZxAttr::ZxAttr(GString *nameA, GString *valueA) { |
1026 | 1.15M | name = nameA; |
1027 | 1.15M | value = valueA; |
1028 | 1.15M | parent = NULL; |
1029 | 1.15M | next = NULL; |
1030 | 1.15M | } |
1031 | | |
1032 | 1.15M | ZxAttr::~ZxAttr() { |
1033 | 1.15M | delete name; |
1034 | 1.15M | delete value; |
1035 | 1.15M | } |
1036 | | |
1037 | | //------------------------------------------------------------------------ |
1038 | | |
1039 | 1.45M | ZxCharData::ZxCharData(GString *dataA, bool parsedA) { |
1040 | 1.45M | data = dataA; |
1041 | 1.45M | parsed = parsedA; |
1042 | 1.45M | } |
1043 | | |
1044 | 1.45M | ZxCharData::~ZxCharData() { |
1045 | 1.45M | delete data; |
1046 | 1.45M | } |
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 | } |