Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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("&lt;");
1011
0
    } else if (c == '>') {
1012
0
      out->append("&gt;");
1013
0
    } else if (c == '&') {
1014
0
      out->append("&amp;");
1015
0
    } else if (c == '"') {
1016
0
      out->append("&quot;");
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("&lt;");
1060
0
      } else if (c == '>') {
1061
0
  s->append("&gt;");
1062
0
      } else if (c == '&') {
1063
0
  s->append("&amp;");
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
}