Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvisio/src/lib/VSDXMLParserBase.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libvisio project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "VSDXMLParserBase.h"
11
12
#include <string.h>
13
#include <libxml/xmlIO.h>
14
#include <libxml/xmlstring.h>
15
#include <librevenge-stream/librevenge-stream.h>
16
17
#include <boost/phoenix.hpp>
18
#include <boost/spirit/include/qi.hpp>
19
20
#include "libvisio_utils.h"
21
#include "libvisio_xml.h"
22
#include "VSDContentCollector.h"
23
#include "VSDStylesCollector.h"
24
#include "VSDXMLHelper.h"
25
#include "VSDXMLTokenMap.h"
26
27
using std::shared_ptr;
28
29
libvisio::VSDXMLParserBase::VSDXMLParserBase()
30
18.8k
  : m_collector(), m_stencils(), m_currentStencil(), m_shape(),
31
18.8k
    m_isStencilStarted(false), m_currentStencilID(MINUS_ONE),
32
18.8k
    m_extractStencils(false), m_isInStyles(false), m_currentLevel(0),
33
18.8k
    m_currentShapeLevel(0), m_colours(), m_fieldList(), m_shapeList(),
34
18.8k
    m_currentBinaryData(), m_shapeStack(), m_shapeLevelStack(),
35
18.8k
    m_isShapeStarted(false), m_isPageStarted(false), m_currentGeometryList(nullptr),
36
18.8k
    m_currentGeometryListIndex(MINUS_ONE), m_fonts(), m_currentTabSet(nullptr),
37
18.8k
    m_watcher(nullptr)
38
18.8k
{
39
18.8k
  initColours();
40
18.8k
}
41
42
libvisio::VSDXMLParserBase::~VSDXMLParserBase()
43
18.8k
{
44
18.8k
}
45
46
// Common functions
47
48
void libvisio::VSDXMLParserBase::readGeometry(xmlTextReaderPtr reader)
49
150k
{
50
150k
  int ret = 1;
51
150k
  int tokenId = XML_TOKEN_INVALID;
52
150k
  int tokenType = -1;
53
150k
  int level = getElementDepth(reader);
54
55
150k
  unsigned ix = getIX(reader);
56
57
150k
  m_currentGeometryList = &m_shape.m_geometries[ix];
58
59
150k
  if (xmlTextReaderIsEmptyElement(reader))
60
5.12k
  {
61
5.12k
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
62
5.12k
    if (delString)
63
0
    {
64
0
      if (xmlStringToBool(delString))
65
0
      {
66
0
        m_currentGeometryList->clear();
67
0
        m_shape.m_geometries.erase(ix);
68
0
        m_currentGeometryList = nullptr;
69
0
      }
70
0
    }
71
5.12k
    return;
72
5.12k
  }
73
74
145k
  std::optional<bool> noFill;
75
145k
  std::optional<bool> noLine;
76
145k
  std::optional<bool> noShow;
77
78
145k
  do
79
2.60M
  {
80
2.60M
    ret = xmlTextReaderRead(reader);
81
2.60M
    tokenId = getElementToken(reader);
82
2.60M
    if (XML_TOKEN_INVALID == tokenId)
83
1.49M
    {
84
1.49M
      VSD_DEBUG_MSG(("VSDXMLParserBase::readGeometry: unknown token %s\n", xmlTextReaderConstName(reader)));
85
1.49M
    }
86
2.60M
    tokenType = xmlTextReaderNodeType(reader);
87
88
2.60M
    switch (tokenId)
89
2.60M
    {
90
37.5k
    case XML_NOFILL:
91
37.5k
      if (XML_READER_TYPE_ELEMENT == tokenType)
92
37.3k
        ret = readBoolData(noFill, reader);
93
37.5k
      break;
94
22.2k
    case XML_NOLINE:
95
22.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
96
21.9k
        ret = readBoolData(noLine, reader);
97
22.2k
      break;
98
24.2k
    case XML_NOSHOW:
99
24.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
100
23.5k
        ret = readBoolData(noShow, reader);
101
24.2k
      break;
102
32.3k
    case XML_MOVETO:
103
32.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
104
27.2k
        readMoveTo(reader);
105
32.3k
      break;
106
172k
    case XML_LINETO:
107
172k
      if (XML_READER_TYPE_ELEMENT == tokenType)
108
168k
        readLineTo(reader);
109
172k
      break;
110
15.0k
    case XML_ARCTO:
111
15.0k
      if (XML_READER_TYPE_ELEMENT == tokenType)
112
13.5k
        readArcTo(reader);
113
15.0k
      break;
114
31.3k
    case XML_NURBSTO:
115
31.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
116
24.6k
        readNURBSTo(reader);
117
31.3k
      break;
118
24.1k
    case XML_POLYLINETO:
119
24.1k
      if (XML_READER_TYPE_ELEMENT == tokenType)
120
21.9k
        readPolylineTo(reader);
121
24.1k
      break;
122
5.23k
    case XML_INFINITELINE:
123
5.23k
      if (XML_READER_TYPE_ELEMENT == tokenType)
124
3.45k
        readInfiniteLine(reader);
125
5.23k
      break;
126
9.46k
    case XML_ELLIPTICALARCTO:
127
9.46k
      if (XML_READER_TYPE_ELEMENT == tokenType)
128
7.23k
        readEllipticalArcTo(reader);
129
9.46k
      break;
130
10.4k
    case XML_ELLIPSE:
131
10.4k
      if (XML_READER_TYPE_ELEMENT == tokenType)
132
6.87k
        readEllipse(reader);
133
10.4k
      break;
134
16.2k
    case XML_RELCUBBEZTO:
135
16.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
136
14.1k
        readRelCubBezTo(reader);
137
16.2k
      break;
138
17.4k
    case XML_RELELLIPTICALARCTO:
139
17.4k
      if (XML_READER_TYPE_ELEMENT == tokenType)
140
15.0k
        readRelEllipticalArcTo(reader);
141
17.4k
      break;
142
14.9k
    case XML_RELMOVETO:
143
14.9k
      if (XML_READER_TYPE_ELEMENT == tokenType)
144
13.1k
        readRelMoveTo(reader);
145
14.9k
      break;
146
24.5k
    case XML_RELLINETO:
147
24.5k
      if (XML_READER_TYPE_ELEMENT == tokenType)
148
22.5k
        readRelLineTo(reader);
149
24.5k
      break;
150
15.3k
    case XML_RELQUADBEZTO:
151
15.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
152
12.2k
        readRelQuadBezTo(reader);
153
15.3k
      break;
154
6.29k
    case XML_SPLINESTART:
155
6.29k
      if (XML_READER_TYPE_ELEMENT == tokenType)
156
5.36k
        readSplineStart(reader);
157
6.29k
      break;
158
4.39k
    case XML_SPLINEKNOT:
159
4.39k
      if (XML_READER_TYPE_ELEMENT == tokenType)
160
3.51k
        readSplineKnot(reader);
161
4.39k
      break;
162
2.11M
    default:
163
2.11M
      break;
164
2.60M
    }
165
2.60M
  }
166
2.60M
  while (((XML_GEOM != tokenId && XML_SECTION != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
167
144k
  if (ret == 1)
168
139k
    m_currentGeometryList->addGeometry(0, level+1, noFill, noLine, noShow);
169
144k
}
170
171
void libvisio::VSDXMLParserBase::readMoveTo(xmlTextReaderPtr reader)
172
27.2k
{
173
27.2k
  int ret = 1;
174
27.2k
  int tokenId = XML_TOKEN_INVALID;
175
27.2k
  int tokenType = -1;
176
27.2k
  int level = getElementDepth(reader);
177
178
27.2k
  unsigned ix = getIX(reader);
179
180
27.2k
  if (xmlTextReaderIsEmptyElement(reader))
181
159
  {
182
159
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
183
159
    if (delString)
184
0
    {
185
0
      if (xmlStringToBool(delString))
186
0
        m_currentGeometryList->addEmpty(ix, level);
187
0
    }
188
159
    return;
189
159
  }
190
191
27.0k
  std::optional<double> x;
192
27.0k
  std::optional<double> y;
193
194
27.0k
  do
195
98.1k
  {
196
98.1k
    ret = xmlTextReaderRead(reader);
197
98.1k
    tokenId = getElementToken(reader);
198
98.1k
    if (XML_TOKEN_INVALID == tokenId)
199
19.3k
    {
200
19.3k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readMoveTo: unknown token %s\n", xmlTextReaderConstName(reader)));
201
19.3k
    }
202
98.1k
    tokenType = xmlTextReaderNodeType(reader);
203
204
98.1k
    switch (tokenId)
205
98.1k
    {
206
23.1k
    case XML_X:
207
23.1k
      ret = readDoubleData(x, reader);
208
23.1k
      break;
209
19.5k
    case XML_Y:
210
19.5k
      ret = readDoubleData(y, reader);
211
19.5k
      break;
212
55.3k
    default:
213
55.3k
      break;
214
98.1k
    }
215
98.1k
  }
216
98.0k
  while (((XML_MOVETO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
217
27.0k
  if (ret == 1)
218
25.1k
    m_currentGeometryList->addMoveTo(ix, level, x, y);
219
27.0k
}
220
221
void libvisio::VSDXMLParserBase::readLineTo(xmlTextReaderPtr reader)
222
168k
{
223
168k
  int ret = 1;
224
168k
  int tokenId = XML_TOKEN_INVALID;
225
168k
  int tokenType = -1;
226
168k
  int level = getElementDepth(reader);
227
228
168k
  unsigned ix = getIX(reader);
229
230
168k
  if (xmlTextReaderIsEmptyElement(reader))
231
135
  {
232
135
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
233
135
    if (delString)
234
0
    {
235
0
      if (xmlStringToBool(delString))
236
0
        m_currentGeometryList->addEmpty(ix, level);
237
0
    }
238
135
    return;
239
135
  }
240
241
168k
  std::optional<double> x;
242
168k
  std::optional<double> y;
243
244
168k
  do
245
531k
  {
246
531k
    ret = xmlTextReaderRead(reader);
247
531k
    tokenId = getElementToken(reader);
248
531k
    if (XML_TOKEN_INVALID == tokenId)
249
25.0k
    {
250
25.0k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readLineTo: unknown token %s\n", xmlTextReaderConstName(reader)));
251
25.0k
    }
252
531k
    tokenType = xmlTextReaderNodeType(reader);
253
254
531k
    switch (tokenId)
255
531k
    {
256
165k
    case XML_X:
257
165k
      ret = readDoubleData(x, reader);
258
165k
      break;
259
163k
    case XML_Y:
260
163k
      ret = readDoubleData(y, reader);
261
163k
      break;
262
202k
    default:
263
202k
      break;
264
531k
    }
265
531k
  }
266
531k
  while (((XML_LINETO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
267
168k
  if (ret == 1)
268
165k
    m_currentGeometryList->addLineTo(ix, level, x, y);
269
168k
}
270
271
void libvisio::VSDXMLParserBase::readArcTo(xmlTextReaderPtr reader)
272
13.5k
{
273
13.5k
  int ret = 1;
274
13.5k
  int tokenId = XML_TOKEN_INVALID;
275
13.5k
  int tokenType = -1;
276
13.5k
  int level = getElementDepth(reader);
277
278
13.5k
  unsigned ix = getIX(reader);
279
280
13.5k
  if (xmlTextReaderIsEmptyElement(reader))
281
138
  {
282
138
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
283
138
    if (delString)
284
0
    {
285
0
      if (xmlStringToBool(delString))
286
0
        m_currentGeometryList->addEmpty(ix, level);
287
0
    }
288
138
    return;
289
138
  }
290
291
13.4k
  std::optional<double> x;
292
13.4k
  std::optional<double> y;
293
13.4k
  std::optional<double> a;
294
295
13.4k
  do
296
33.9k
  {
297
33.9k
    ret = xmlTextReaderRead(reader);
298
33.9k
    tokenId = getElementToken(reader);
299
33.9k
    if (XML_TOKEN_INVALID == tokenId)
300
13.3k
    {
301
13.3k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readArcTo: unknown token %s\n", xmlTextReaderConstName(reader)));
302
13.3k
    }
303
33.9k
    tokenType = xmlTextReaderNodeType(reader);
304
305
33.9k
    switch (tokenId)
306
33.9k
    {
307
1.11k
    case XML_X:
308
1.11k
      ret = readDoubleData(x, reader);
309
1.11k
      break;
310
1.24k
    case XML_Y:
311
1.24k
      ret = readDoubleData(y, reader);
312
1.24k
      break;
313
481
    case XML_A:
314
481
      ret = readDoubleData(a, reader);
315
481
      break;
316
31.1k
    default:
317
31.1k
      break;
318
33.9k
    }
319
33.9k
  }
320
33.9k
  while (((XML_ARCTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
321
13.4k
  if (ret == 1)
322
12.2k
    m_currentGeometryList->addArcTo(ix, level, x, y, a);
323
13.4k
}
324
325
void libvisio::VSDXMLParserBase::readEllipticalArcTo(xmlTextReaderPtr reader)
326
7.23k
{
327
7.23k
  int ret = 1;
328
7.23k
  int tokenId = XML_TOKEN_INVALID;
329
7.23k
  int tokenType = -1;
330
7.23k
  int level = getElementDepth(reader);
331
332
7.23k
  unsigned ix = getIX(reader);
333
334
7.23k
  if (xmlTextReaderIsEmptyElement(reader))
335
43
  {
336
43
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
337
43
    if (delString)
338
0
    {
339
0
      if (xmlStringToBool(delString))
340
0
        m_currentGeometryList->addEmpty(ix, level);
341
0
    }
342
43
    return;
343
43
  }
344
345
7.18k
  std::optional<double> x;
346
7.18k
  std::optional<double> y;
347
7.18k
  std::optional<double> a;
348
7.18k
  std::optional<double> b;
349
7.18k
  std::optional<double> c;
350
7.18k
  std::optional<double> d;
351
352
7.18k
  do
353
90.2k
  {
354
90.2k
    ret = xmlTextReaderRead(reader);
355
90.2k
    tokenId = getElementToken(reader);
356
90.2k
    if (XML_TOKEN_INVALID == tokenId)
357
48.6k
    {
358
48.6k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readEllipticalArcTo: unknown token %s\n", xmlTextReaderConstName(reader)));
359
48.6k
    }
360
90.2k
    tokenType = xmlTextReaderNodeType(reader);
361
362
90.2k
    switch (tokenId)
363
90.2k
    {
364
3.80k
    case XML_X:
365
3.80k
      ret = readDoubleData(x, reader);
366
3.80k
      break;
367
3.17k
    case XML_Y:
368
3.17k
      ret = readDoubleData(y, reader);
369
3.17k
      break;
370
3.39k
    case XML_A:
371
3.39k
      ret = readDoubleData(a, reader);
372
3.39k
      break;
373
3.32k
    case XML_B:
374
3.32k
      ret = readDoubleData(b, reader);
375
3.32k
      break;
376
3.76k
    case XML_C:
377
3.76k
      ret = readDoubleData(c, reader);
378
3.76k
      break;
379
2.71k
    case XML_D:
380
2.71k
      ret = readDoubleData(d, reader);
381
2.71k
      break;
382
70.0k
    default:
383
70.0k
      break;
384
90.2k
    }
385
90.2k
  }
386
90.2k
  while (((XML_ELLIPTICALARCTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
387
7.15k
  if (ret == 1)
388
6.17k
    m_currentGeometryList->addEllipticalArcTo(ix, level, x, y, a, b, c, d);
389
7.15k
}
390
391
void libvisio::VSDXMLParserBase::readEllipse(xmlTextReaderPtr reader)
392
6.87k
{
393
6.87k
  int ret = 1;
394
6.87k
  int tokenId = XML_TOKEN_INVALID;
395
6.87k
  int tokenType = -1;
396
6.87k
  int level = getElementDepth(reader);
397
398
6.87k
  unsigned ix = getIX(reader);
399
400
6.87k
  if (xmlTextReaderIsEmptyElement(reader))
401
760
  {
402
760
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
403
760
    if (delString)
404
0
    {
405
0
      if (xmlStringToBool(delString))
406
0
        m_currentGeometryList->addEmpty(ix, level);
407
0
    }
408
760
    return;
409
760
  }
410
411
6.11k
  std::optional<double> x;
412
6.11k
  std::optional<double> y;
413
6.11k
  std::optional<double> a;
414
6.11k
  std::optional<double> b;
415
6.11k
  std::optional<double> c;
416
6.11k
  std::optional<double> d;
417
418
6.11k
  do
419
72.4k
  {
420
72.4k
    ret = xmlTextReaderRead(reader);
421
72.4k
    tokenId = getElementToken(reader);
422
72.4k
    if (XML_TOKEN_INVALID == tokenId)
423
45.3k
    {
424
45.3k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readEllipse: unknown token %s\n", xmlTextReaderConstName(reader)));
425
45.3k
    }
426
72.4k
    tokenType = xmlTextReaderNodeType(reader);
427
428
72.4k
    switch (tokenId)
429
72.4k
    {
430
946
    case XML_X:
431
946
      ret = readDoubleData(x, reader);
432
946
      break;
433
1.38k
    case XML_Y:
434
1.38k
      ret = readDoubleData(y, reader);
435
1.38k
      break;
436
753
    case XML_A:
437
753
      ret = readDoubleData(a, reader);
438
753
      break;
439
1.56k
    case XML_B:
440
1.56k
      ret = readDoubleData(b, reader);
441
1.56k
      break;
442
643
    case XML_C:
443
643
      ret = readDoubleData(c, reader);
444
643
      break;
445
1.21k
    case XML_D:
446
1.21k
      ret = readDoubleData(d, reader);
447
1.21k
      break;
448
65.9k
    default:
449
65.9k
      break;
450
72.4k
    }
451
72.4k
  }
452
72.4k
  while (((XML_ELLIPSE != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
453
6.06k
  if (ret == 1)
454
4.70k
    m_currentGeometryList->addEllipse(ix, level, x, y, a, b, c, d);
455
6.06k
}
456
457
void libvisio::VSDXMLParserBase::readNURBSTo(xmlTextReaderPtr reader)
458
24.6k
{
459
24.6k
  int ret = 1;
460
24.6k
  int tokenId = XML_TOKEN_INVALID;
461
24.6k
  int tokenType = -1;
462
24.6k
  int level = getElementDepth(reader);
463
464
24.6k
  unsigned ix = getIX(reader);
465
466
24.6k
  if (xmlTextReaderIsEmptyElement(reader))
467
165
  {
468
165
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
469
165
    if (delString)
470
0
    {
471
0
      if (xmlStringToBool(delString))
472
0
        m_currentGeometryList->addEmpty(ix, level);
473
0
    }
474
165
    return;
475
165
  }
476
477
24.5k
  std::optional<double> x;
478
24.5k
  std::optional<double> y;
479
24.5k
  std::optional<double> knot; // Second last knot
480
24.5k
  std::optional<double> weight; // Last weight
481
24.5k
  std::optional<double> knotPrev; // First knot
482
24.5k
  std::optional<double> weightPrev ; // First weight
483
24.5k
  std::optional<NURBSData> nurbsData;
484
485
24.5k
  do
486
130k
  {
487
130k
    ret = xmlTextReaderRead(reader);
488
130k
    tokenId = getElementToken(reader);
489
130k
    if (XML_TOKEN_INVALID == tokenId)
490
82.0k
    {
491
82.0k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readNURBSTo: unknown token %s\n", xmlTextReaderConstName(reader)));
492
82.0k
    }
493
130k
    tokenType = xmlTextReaderNodeType(reader);
494
495
130k
    switch (tokenId)
496
130k
    {
497
1.74k
    case XML_X:
498
1.74k
      ret = readDoubleData(x, reader);
499
1.74k
      break;
500
2.32k
    case XML_Y:
501
2.32k
      ret = readDoubleData(y, reader);
502
2.32k
      break;
503
560
    case XML_A:
504
560
      ret = readDoubleData(knot, reader);
505
560
      break;
506
910
    case XML_B:
507
910
      ret = readDoubleData(weight, reader);
508
910
      break;
509
585
    case XML_C:
510
585
      ret = readDoubleData(knotPrev, reader);
511
585
      break;
512
765
    case XML_D:
513
765
      ret = readDoubleData(weightPrev, reader);
514
765
      break;
515
17.1k
    case XML_E:
516
17.1k
      ret = readNURBSData(nurbsData, reader);
517
17.1k
      break;
518
106k
    default:
519
106k
      break;
520
130k
    }
521
130k
  }
522
130k
  while (((XML_NURBSTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
523
524
24.3k
  if (ret == 1)
525
7.38k
    m_currentGeometryList->addNURBSTo(ix, level, x, y, knot, knotPrev, weight, weightPrev, nurbsData);
526
24.3k
}
527
528
void libvisio::VSDXMLParserBase::readPolylineTo(xmlTextReaderPtr reader)
529
21.9k
{
530
21.9k
  int ret = 1;
531
21.9k
  int tokenId = XML_TOKEN_INVALID;
532
21.9k
  int tokenType = -1;
533
21.9k
  int level = getElementDepth(reader);
534
535
21.9k
  unsigned ix = getIX(reader);
536
537
21.9k
  if (xmlTextReaderIsEmptyElement(reader))
538
310
  {
539
310
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
540
310
    if (delString)
541
0
    {
542
0
      if (xmlStringToBool(delString))
543
0
        m_currentGeometryList->addEmpty(ix, level);
544
0
    }
545
310
    return;
546
310
  }
547
548
21.6k
  std::optional<double> x;
549
21.6k
  std::optional<double> y;
550
21.6k
  std::optional<PolylineData> polyLineData;
551
552
21.6k
  do
553
145k
  {
554
145k
    ret = xmlTextReaderRead(reader);
555
145k
    tokenId = getElementToken(reader);
556
145k
    if (XML_TOKEN_INVALID == tokenId)
557
84.8k
    {
558
84.8k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readPolylineTo: unknown token %s\n", xmlTextReaderConstName(reader)));
559
84.8k
    }
560
145k
    tokenType = xmlTextReaderNodeType(reader);
561
562
145k
    switch (tokenId)
563
145k
    {
564
4.68k
    case XML_X:
565
4.68k
      ret = readDoubleData(x, reader);
566
4.68k
      break;
567
1.71k
    case XML_Y:
568
1.71k
      ret = readDoubleData(y, reader);
569
1.71k
      break;
570
1.67k
    case XML_A:
571
1.67k
      ret = readPolylineData(polyLineData, reader);
572
1.67k
      break;
573
137k
    default:
574
137k
      break;
575
145k
    }
576
145k
  }
577
145k
  while (((XML_POLYLINETO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
578
21.5k
  if (ret == 1)
579
19.5k
    m_currentGeometryList->addPolylineTo(ix, level, x, y, polyLineData);
580
21.5k
}
581
582
void libvisio::VSDXMLParserBase::readInfiniteLine(xmlTextReaderPtr reader)
583
3.45k
{
584
3.45k
  int ret = 1;
585
3.45k
  int tokenId = XML_TOKEN_INVALID;
586
3.45k
  int tokenType = -1;
587
3.45k
  int level = getElementDepth(reader);
588
589
3.45k
  unsigned ix = getIX(reader);
590
591
3.45k
  if (xmlTextReaderIsEmptyElement(reader))
592
89
  {
593
89
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
594
89
    if (delString)
595
0
    {
596
0
      if (xmlStringToBool(delString))
597
0
        m_currentGeometryList->addEmpty(ix, level);
598
0
    }
599
89
    return;
600
89
  }
601
602
3.36k
  std::optional<double> x;
603
3.36k
  std::optional<double> y;
604
3.36k
  std::optional<double> a;
605
3.36k
  std::optional<double> b;
606
607
3.36k
  do
608
35.6k
  {
609
35.6k
    ret = xmlTextReaderRead(reader);
610
35.6k
    tokenId = getElementToken(reader);
611
35.6k
    if (XML_TOKEN_INVALID == tokenId)
612
22.3k
    {
613
22.3k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readInfiniteLine: unknown token %s\n", xmlTextReaderConstName(reader)));
614
22.3k
    }
615
35.6k
    tokenType = xmlTextReaderNodeType(reader);
616
617
35.6k
    switch (tokenId)
618
35.6k
    {
619
1.05k
    case XML_X:
620
1.05k
      ret = readDoubleData(x, reader);
621
1.05k
      break;
622
1.24k
    case XML_Y:
623
1.24k
      ret = readDoubleData(y, reader);
624
1.24k
      break;
625
701
    case XML_A:
626
701
      ret = readDoubleData(a, reader);
627
701
      break;
628
432
    case XML_B:
629
432
      ret = readDoubleData(b, reader);
630
432
      break;
631
32.1k
    default:
632
32.1k
      break;
633
35.6k
    }
634
35.6k
  }
635
35.6k
  while (((XML_INFINITELINE != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
636
3.34k
  if (ret == 1)
637
2.09k
    m_currentGeometryList->addInfiniteLine(ix, level, x, y, a, b);
638
3.34k
}
639
640
void libvisio::VSDXMLParserBase::readRelEllipticalArcTo(xmlTextReaderPtr reader)
641
15.0k
{
642
15.0k
  int ret = 1;
643
15.0k
  int tokenId = XML_TOKEN_INVALID;
644
15.0k
  int tokenType = -1;
645
15.0k
  int level = getElementDepth(reader);
646
647
15.0k
  unsigned ix = getIX(reader);
648
649
15.0k
  if (xmlTextReaderIsEmptyElement(reader))
650
114
  {
651
114
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
652
114
    if (delString)
653
0
    {
654
0
      if (xmlStringToBool(delString))
655
0
        m_currentGeometryList->addEmpty(ix, level);
656
0
    }
657
114
    return;
658
114
  }
659
660
14.9k
  std::optional<double> x;
661
14.9k
  std::optional<double> y;
662
14.9k
  std::optional<double> a;
663
14.9k
  std::optional<double> b;
664
14.9k
  std::optional<double> c;
665
14.9k
  std::optional<double> d;
666
667
14.9k
  do
668
257k
  {
669
257k
    ret = xmlTextReaderRead(reader);
670
257k
    tokenId = getElementToken(reader);
671
257k
    if (XML_TOKEN_INVALID == tokenId)
672
186k
    {
673
186k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readRelEllipticalArcTo: unknown token %s\n", xmlTextReaderConstName(reader)));
674
186k
    }
675
257k
    tokenType = xmlTextReaderNodeType(reader);
676
677
257k
    switch (tokenId)
678
257k
    {
679
5.44k
    case XML_X:
680
5.44k
      ret = readDoubleData(x, reader);
681
5.44k
      break;
682
3.72k
    case XML_Y:
683
3.72k
      ret = readDoubleData(y, reader);
684
3.72k
      break;
685
1.79k
    case XML_A:
686
1.79k
      ret = readDoubleData(a, reader);
687
1.79k
      break;
688
6.73k
    case XML_B:
689
6.73k
      ret = readDoubleData(b, reader);
690
6.73k
      break;
691
4.16k
    case XML_C:
692
4.16k
      ret = readDoubleData(c, reader);
693
4.16k
      break;
694
1.81k
    case XML_D:
695
1.81k
      ret = readDoubleData(d, reader);
696
1.81k
      break;
697
233k
    default:
698
233k
      break;
699
257k
    }
700
257k
  }
701
257k
  while (((XML_RELELLIPTICALARCTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
702
14.9k
  if (ret == 1)
703
14.3k
    m_currentGeometryList->addRelEllipticalArcTo(ix, level, x, y, a, b, c, d);
704
14.9k
}
705
706
void libvisio::VSDXMLParserBase::readRelCubBezTo(xmlTextReaderPtr reader)
707
14.1k
{
708
14.1k
  int ret = 1;
709
14.1k
  int tokenId = XML_TOKEN_INVALID;
710
14.1k
  int tokenType = -1;
711
14.1k
  int level = getElementDepth(reader);
712
713
14.1k
  unsigned ix = getIX(reader);
714
715
14.1k
  if (xmlTextReaderIsEmptyElement(reader))
716
85
  {
717
85
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
718
85
    if (delString)
719
0
    {
720
0
      if (xmlStringToBool(delString))
721
0
        m_currentGeometryList->addEmpty(ix, level);
722
0
    }
723
85
    return;
724
85
  }
725
726
14.0k
  std::optional<double> x;
727
14.0k
  std::optional<double> y;
728
14.0k
  std::optional<double> a;
729
14.0k
  std::optional<double> b;
730
14.0k
  std::optional<double> c;
731
14.0k
  std::optional<double> d;
732
733
14.0k
  do
734
207k
  {
735
207k
    ret = xmlTextReaderRead(reader);
736
207k
    tokenId = getElementToken(reader);
737
207k
    if (XML_TOKEN_INVALID == tokenId)
738
144k
    {
739
144k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readRelCubBezTo: unknown token %s\n", xmlTextReaderConstName(reader)));
740
144k
    }
741
207k
    tokenType = xmlTextReaderNodeType(reader);
742
743
207k
    switch (tokenId)
744
207k
    {
745
3.96k
    case XML_X:
746
3.96k
      ret = readDoubleData(x, reader);
747
3.96k
      break;
748
3.14k
    case XML_Y:
749
3.14k
      ret = readDoubleData(y, reader);
750
3.14k
      break;
751
2.56k
    case XML_A:
752
2.56k
      ret = readDoubleData(a, reader);
753
2.56k
      break;
754
2.65k
    case XML_B:
755
2.65k
      ret = readDoubleData(b, reader);
756
2.65k
      break;
757
2.70k
    case XML_C:
758
2.70k
      ret = readDoubleData(c, reader);
759
2.70k
      break;
760
4.04k
    case XML_D:
761
4.04k
      ret = readDoubleData(d, reader);
762
4.04k
      break;
763
188k
    default:
764
188k
      break;
765
207k
    }
766
207k
  }
767
207k
  while (((XML_RELCUBBEZTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
768
13.9k
  if (ret == 1)
769
12.9k
    m_currentGeometryList->addRelCubBezTo(ix, level, x, y, a, b, c, d);
770
13.9k
}
771
772
void libvisio::VSDXMLParserBase::readRelLineTo(xmlTextReaderPtr reader)
773
22.5k
{
774
22.5k
  int ret = 1;
775
22.5k
  int tokenId = XML_TOKEN_INVALID;
776
22.5k
  int tokenType = -1;
777
22.5k
  int level = getElementDepth(reader);
778
779
22.5k
  unsigned ix = getIX(reader);
780
781
22.5k
  if (xmlTextReaderIsEmptyElement(reader))
782
286
  {
783
286
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
784
286
    if (delString)
785
0
    {
786
0
      if (xmlStringToBool(delString))
787
0
        m_currentGeometryList->addEmpty(ix, level);
788
0
    }
789
286
    return;
790
286
  }
791
792
22.2k
  std::optional<double> x;
793
22.2k
  std::optional<double> y;
794
795
22.2k
  do
796
82.7k
  {
797
82.7k
    ret = xmlTextReaderRead(reader);
798
82.7k
    tokenId = getElementToken(reader);
799
82.7k
    if (XML_TOKEN_INVALID == tokenId)
800
36.8k
    {
801
36.8k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readRelLineTo: unknown token %s\n", xmlTextReaderConstName(reader)));
802
36.8k
    }
803
82.7k
    tokenType = xmlTextReaderNodeType(reader);
804
805
82.7k
    switch (tokenId)
806
82.7k
    {
807
6.20k
    case XML_X:
808
6.20k
      ret = readDoubleData(x, reader);
809
6.20k
      break;
810
5.68k
    case XML_Y:
811
5.68k
      ret = readDoubleData(y, reader);
812
5.68k
      break;
813
70.8k
    default:
814
70.8k
      break;
815
82.7k
    }
816
82.7k
  }
817
82.6k
  while (((XML_RELLINETO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
818
22.2k
  if (ret == 1)
819
21.4k
    m_currentGeometryList->addRelLineTo(ix, level, x, y);
820
22.2k
}
821
822
void libvisio::VSDXMLParserBase::readRelMoveTo(xmlTextReaderPtr reader)
823
13.1k
{
824
13.1k
  int ret = 1;
825
13.1k
  int tokenId = XML_TOKEN_INVALID;
826
13.1k
  int tokenType = -1;
827
13.1k
  int level = getElementDepth(reader);
828
829
13.1k
  unsigned ix = getIX(reader);
830
831
13.1k
  if (xmlTextReaderIsEmptyElement(reader))
832
609
  {
833
609
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
834
609
    if (delString)
835
0
    {
836
0
      if (xmlStringToBool(delString))
837
0
        m_currentGeometryList->addEmpty(ix, level);
838
0
    }
839
609
    return;
840
609
  }
841
842
12.5k
  std::optional<double> x;
843
12.5k
  std::optional<double> y;
844
845
12.5k
  do
846
64.3k
  {
847
64.3k
    ret = xmlTextReaderRead(reader);
848
64.3k
    tokenId = getElementToken(reader);
849
64.3k
    if (XML_TOKEN_INVALID == tokenId)
850
33.9k
    {
851
33.9k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readRelMoveTo: unknown token %s\n", xmlTextReaderConstName(reader)));
852
33.9k
    }
853
64.3k
    tokenType = xmlTextReaderNodeType(reader);
854
855
64.3k
    switch (tokenId)
856
64.3k
    {
857
4.99k
    case XML_X:
858
4.99k
      ret = readDoubleData(x, reader);
859
4.99k
      break;
860
3.13k
    case XML_Y:
861
3.13k
      ret = readDoubleData(y, reader);
862
3.13k
      break;
863
56.2k
    default:
864
56.2k
      break;
865
64.3k
    }
866
64.3k
  }
867
64.3k
  while (((XML_RELMOVETO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
868
12.5k
  if (ret == 1)
869
11.2k
    m_currentGeometryList->addRelMoveTo(ix, level, x, y);
870
12.5k
}
871
872
void libvisio::VSDXMLParserBase::readRelQuadBezTo(xmlTextReaderPtr reader)
873
12.2k
{
874
12.2k
  int ret = 1;
875
12.2k
  int tokenId = XML_TOKEN_INVALID;
876
12.2k
  int tokenType = -1;
877
12.2k
  int level = getElementDepth(reader);
878
879
12.2k
  unsigned ix = getIX(reader);
880
881
12.2k
  if (xmlTextReaderIsEmptyElement(reader))
882
174
  {
883
174
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
884
174
    if (delString)
885
0
    {
886
0
      if (xmlStringToBool(delString))
887
0
        m_currentGeometryList->addEmpty(ix, level);
888
0
    }
889
174
    return;
890
174
  }
891
892
12.0k
  std::optional<double> x;
893
12.0k
  std::optional<double> y;
894
12.0k
  std::optional<double> a;
895
12.0k
  std::optional<double> b;
896
897
12.0k
  do
898
113k
  {
899
113k
    ret = xmlTextReaderRead(reader);
900
113k
    tokenId = getElementToken(reader);
901
113k
    if (XML_TOKEN_INVALID == tokenId)
902
67.5k
    {
903
67.5k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readRelQuadBezTo: unknown token %s\n", xmlTextReaderConstName(reader)));
904
67.5k
    }
905
113k
    tokenType = xmlTextReaderNodeType(reader);
906
907
113k
    switch (tokenId)
908
113k
    {
909
3.00k
    case XML_X:
910
3.00k
      ret = readDoubleData(x, reader);
911
3.00k
      break;
912
1.97k
    case XML_Y:
913
1.97k
      ret = readDoubleData(y, reader);
914
1.97k
      break;
915
1.37k
    case XML_A:
916
1.37k
      ret = readDoubleData(a, reader);
917
1.37k
      break;
918
2.04k
    case XML_B:
919
2.04k
      ret = readDoubleData(b, reader);
920
2.04k
      break;
921
105k
    default:
922
105k
      break;
923
113k
    }
924
113k
  }
925
113k
  while (((XML_RELQUADBEZTO != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
926
12.0k
  if (ret == 1)
927
11.4k
    m_currentGeometryList->addRelQuadBezTo(ix, level, x, y, a, b);
928
12.0k
}
929
930
void libvisio::VSDXMLParserBase::readShape(xmlTextReaderPtr reader)
931
341k
{
932
341k
  m_isShapeStarted = true;
933
341k
  m_currentShapeLevel = getElementDepth(reader);
934
935
341k
  const shared_ptr<xmlChar> idString(xmlTextReaderGetAttribute(reader, BAD_CAST("ID")), xmlFree);
936
341k
  const shared_ptr<xmlChar> masterPageString(xmlTextReaderGetAttribute(reader, BAD_CAST("Master")), xmlFree);
937
341k
  const shared_ptr<xmlChar> masterShapeString(xmlTextReaderGetAttribute(reader, BAD_CAST("MasterShape")), xmlFree);
938
341k
  const shared_ptr<xmlChar> lineStyleString(xmlTextReaderGetAttribute(reader, BAD_CAST("LineStyle")), xmlFree);
939
341k
  const shared_ptr<xmlChar> fillStyleString(xmlTextReaderGetAttribute(reader, BAD_CAST("FillStyle")), xmlFree);
940
341k
  const shared_ptr<xmlChar> textStyleString(xmlTextReaderGetAttribute(reader, BAD_CAST("TextStyle")), xmlFree);
941
942
341k
  shared_ptr<xmlChar> pShapeName(xmlTextReaderGetAttribute(reader, BAD_CAST("NameU")), xmlFree);
943
944
341k
  unsigned id = idString ? (unsigned)xmlStringToLong(idString) : MINUS_ONE;
945
341k
  unsigned masterPage = masterPageString ? (unsigned)xmlStringToLong(masterPageString) : MINUS_ONE;
946
341k
  unsigned masterShape = masterShapeString ? (unsigned)xmlStringToLong(masterShapeString) : MINUS_ONE;
947
341k
  unsigned lineStyle = lineStyleString ? (unsigned)xmlStringToLong(lineStyleString) : MINUS_ONE;
948
341k
  unsigned fillStyle =  fillStyleString ? (unsigned)xmlStringToLong(fillStyleString) : MINUS_ONE;
949
341k
  unsigned textStyle =  textStyleString ? (unsigned)xmlStringToLong(textStyleString) : MINUS_ONE;
950
951
341k
  if (masterPage != MINUS_ONE || masterShape != MINUS_ONE)
952
5.78k
  {
953
5.78k
    if (!m_shapeStack.empty())
954
917
      masterPage = m_shapeStack.top().m_masterPage;
955
5.78k
  }
956
957
341k
  m_shape.clear();
958
341k
  m_shape.m_textFormat = VSD_TEXT_UTF8;
959
960
341k
  if (m_isStencilStarted && m_currentStencil)
961
71.1k
    m_currentStencil->setFirstShape(id);
962
963
341k
  const VSDStencil *tmpStencil = m_stencils.getStencil(masterPage);
964
341k
  if (tmpStencil)
965
149k
  {
966
149k
    if (MINUS_ONE == masterShape)
967
149k
      masterShape = tmpStencil->m_firstShapeId;
968
149k
    const VSDShape *tmpShape = tmpStencil->getStencilShape(masterShape);
969
149k
    if (tmpShape)
970
85.2k
    {
971
85.2k
      if (tmpShape->m_foreign)
972
1.26k
        m_shape.m_foreign = std::make_unique<ForeignData>(*(tmpShape->m_foreign));
973
85.2k
      m_shape.m_xform = tmpShape->m_xform;
974
85.2k
      if (tmpShape->m_txtxform)
975
1.94k
        m_shape.m_txtxform = std::make_unique<XForm>(*(tmpShape->m_txtxform));
976
85.2k
      m_shape.m_geometries = tmpShape->m_geometries;
977
85.2k
      m_shape.m_charList = tmpShape->m_charList;
978
85.2k
      m_shape.m_paraList = tmpShape->m_paraList;
979
85.2k
      m_shape.m_tabSets = tmpShape->m_tabSets;
980
85.2k
      m_shape.m_text = tmpShape->m_text;
981
85.2k
      m_shape.m_textFormat = tmpShape->m_textFormat;
982
85.2k
      m_shape.m_misc = tmpShape->m_misc;
983
85.2k
    }
984
149k
  }
985
986
341k
  if (!m_shapeStack.empty())
987
101k
    m_shapeStack.top().m_shapeList.addShapeId(id);
988
240k
  else
989
240k
    m_shapeList.addShapeId(id);
990
991
341k
  m_shape.m_lineStyleId = lineStyle;
992
341k
  m_shape.m_fillStyleId = fillStyle;
993
341k
  m_shape.m_textStyleId = textStyle;
994
995
341k
  m_shape.m_parent = m_shapeStack.empty() ? MINUS_ONE : m_shapeStack.top().m_shapeId;
996
341k
  m_shape.m_masterPage = masterPage;
997
341k
  m_shape.m_masterShape = masterShape;
998
341k
  m_shape.m_shapeId = id;
999
341k
  if (pShapeName.get())
1000
38.8k
  {
1001
38.8k
      m_shape.m_aName = VSDName(
1002
38.8k
          librevenge::RVNGBinaryData(pShapeName.get(), xmlStrlen(pShapeName.get())),
1003
38.8k
                     VSD_TEXT_UTF8);
1004
38.8k
  }
1005
302k
  else if (MINUS_ONE != m_shape.m_parent && !m_shapeStack.top().m_aName.empty())
1006
2.88k
  {
1007
2.88k
      m_shape.m_aName = m_shapeStack.top().m_aName;
1008
2.88k
  }
1009
1010
341k
}
1011
1012
void libvisio::VSDXMLParserBase::initColours()
1013
55.6k
{
1014
55.6k
  m_colours.clear();
1015
55.6k
  m_colours[0] = Colour(0x00, 0x00, 0x00, 0);
1016
55.6k
  m_colours[1] = Colour(0xFF, 0xFF, 0xFF, 0);
1017
55.6k
  m_colours[2] = Colour(0xFF, 0x00, 0x00, 0);
1018
55.6k
  m_colours[3] = Colour(0x00, 0xFF, 0x00, 0);
1019
55.6k
  m_colours[4] = Colour(0x00, 0x00, 0xFF, 0);
1020
55.6k
  m_colours[5] = Colour(0xFF, 0xFF, 0x00, 0);
1021
55.6k
  m_colours[6] = Colour(0xFF, 0x00, 0xFF, 0);
1022
55.6k
  m_colours[7] = Colour(0x00, 0xFF, 0xFF, 0);
1023
55.6k
  m_colours[8] = Colour(0x80, 0x00, 0x00, 0);
1024
55.6k
  m_colours[9] = Colour(0x00, 0x80, 0x00, 0);
1025
55.6k
  m_colours[10] = Colour(0x00, 0x00, 0x80, 0);
1026
55.6k
  m_colours[11] = Colour(0x80, 0x80, 0x00, 0);
1027
55.6k
  m_colours[12] = Colour(0x80, 0x00, 0x80, 0);
1028
55.6k
  m_colours[13] = Colour(0x00, 0x80, 0x80, 0);
1029
55.6k
  m_colours[14] = Colour(0xC0, 0xC0, 0xC0, 0);
1030
55.6k
  m_colours[15] = Colour(0xE6, 0xE6, 0xE6, 0);
1031
55.6k
  m_colours[16] = Colour(0xCD, 0xCD, 0xCD, 0);
1032
55.6k
  m_colours[17] = Colour(0xB3, 0xB3, 0xB3, 0);
1033
55.6k
  m_colours[18] = Colour(0x9A, 0x9A, 0x9A, 0);
1034
55.6k
  m_colours[19] = Colour(0x80, 0x80, 0x80, 0);
1035
55.6k
  m_colours[20] = Colour(0x66, 0x66, 0x66, 0);
1036
55.6k
  m_colours[21] = Colour(0x4D, 0x4D, 0x4D, 0);
1037
55.6k
  m_colours[22] = Colour(0x33, 0x33, 0x33, 0);
1038
55.6k
  m_colours[23] = Colour(0x1A, 0x1A, 0x1A, 0);
1039
55.6k
}
1040
1041
void libvisio::VSDXMLParserBase::readColours(xmlTextReaderPtr reader)
1042
36.8k
{
1043
36.8k
  int ret = 1;
1044
36.8k
  int tokenId = XML_TOKEN_INVALID;
1045
36.8k
  int tokenType = -1;
1046
1047
36.8k
  initColours();
1048
1049
36.8k
  do
1050
516k
  {
1051
516k
    ret = xmlTextReaderRead(reader);
1052
516k
    tokenId = getElementToken(reader);
1053
516k
    if (XML_TOKEN_INVALID == tokenId)
1054
318k
    {
1055
318k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readColours: unknown token %s\n", xmlTextReaderConstName(reader)));
1056
318k
    }
1057
516k
    tokenType = xmlTextReaderNodeType(reader);
1058
1059
516k
    if (XML_COLORENTRY == tokenId)
1060
61.0k
    {
1061
61.0k
      unsigned idx = getIX(reader);
1062
61.0k
      const shared_ptr<xmlChar> rgb(xmlTextReaderGetAttribute(reader, BAD_CAST("RGB")), xmlFree);
1063
61.0k
      if (MINUS_ONE != idx && rgb)
1064
55.8k
      {
1065
55.8k
        Colour rgbColour = xmlStringToColour(rgb);
1066
55.8k
        m_colours[idx] = rgbColour;
1067
55.8k
      }
1068
61.0k
    }
1069
516k
  }
1070
516k
  while ((XML_COLORS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1071
36.8k
}
1072
1073
void libvisio::VSDXMLParserBase::readPage(xmlTextReaderPtr reader)
1074
33.0k
{
1075
33.0k
  m_shapeList.clear();
1076
33.0k
  const shared_ptr<xmlChar> id(xmlTextReaderGetAttribute(reader, BAD_CAST("ID")), xmlFree);
1077
33.0k
  const shared_ptr<xmlChar> bgndPage(xmlTextReaderGetAttribute(reader, BAD_CAST("BackPage")), xmlFree);
1078
33.0k
  const shared_ptr<xmlChar> background(xmlTextReaderGetAttribute(reader, BAD_CAST("Background")), xmlFree);
1079
33.0k
  shared_ptr<xmlChar> pageName(xmlTextReaderGetAttribute(reader, BAD_CAST("Name")), xmlFree);
1080
33.0k
  if (!pageName.get())
1081
21.8k
    pageName.reset(xmlTextReaderGetAttribute(reader, BAD_CAST("NameU")), xmlFree);
1082
33.0k
  if (id)
1083
27.0k
  {
1084
27.0k
    auto nId = (unsigned)xmlStringToLong(id);
1085
27.0k
    auto backgroundPageID = (unsigned)(bgndPage ? xmlStringToLong(bgndPage) : -1);
1086
27.0k
    bool isBackgroundPage = background ? xmlStringToBool(background) : false;
1087
27.0k
    m_isPageStarted = true;
1088
27.0k
    m_collector->startPage(nId);
1089
27.0k
    m_collector->collectPage(nId, (unsigned)getElementDepth(reader), backgroundPageID, isBackgroundPage, pageName ? VSDName(librevenge::RVNGBinaryData(pageName.get(), xmlStrlen(pageName.get())), VSD_TEXT_UTF8) : VSDName());
1090
27.0k
  }
1091
33.0k
}
1092
1093
void libvisio::VSDXMLParserBase::readText(xmlTextReaderPtr reader)
1094
67.0k
{
1095
67.0k
  if (xmlTextReaderIsEmptyElement(reader))
1096
591
    return;
1097
1098
66.4k
  unsigned cp = 0;
1099
66.4k
  unsigned pp = 0;
1100
66.4k
  unsigned tp = 0;
1101
66.4k
  m_shape.m_text.clear();
1102
66.4k
  m_shape.m_charList.resetCharCount();
1103
66.4k
  m_shape.m_paraList.resetCharCount();
1104
1105
66.4k
  int ret = 1;
1106
66.4k
  int tokenId = XML_TOKEN_INVALID;
1107
66.4k
  int tokenType = -1;
1108
1109
66.4k
  do
1110
821k
  {
1111
821k
    ret = xmlTextReaderRead(reader);
1112
821k
    tokenId = getElementToken(reader);
1113
821k
    if (XML_TOKEN_INVALID == tokenId)
1114
495k
    {
1115
495k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readText: unknown token %s\n", xmlTextReaderConstName(reader)));
1116
495k
    }
1117
821k
    tokenType = xmlTextReaderNodeType(reader);
1118
821k
    switch (tokenId)
1119
821k
    {
1120
11.7k
    case XML_CP:
1121
11.7k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1122
10.9k
        cp = getIX(reader);
1123
11.7k
      break;
1124
19.8k
    case XML_PP:
1125
19.8k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1126
14.3k
        pp = getIX(reader);
1127
19.8k
      break;
1128
358
    case XML_TP:
1129
358
      if (XML_READER_TYPE_ELEMENT == tokenType)
1130
179
        tp = getIX(reader);
1131
358
      break;
1132
789k
    default:
1133
789k
      if (XML_READER_TYPE_TEXT == tokenType || XML_READER_TYPE_SIGNIFICANT_WHITESPACE == tokenType)
1134
241k
      {
1135
241k
        librevenge::RVNGBinaryData tmpText;
1136
241k
        const unsigned char *tmpBuffer = xmlTextReaderConstValue(reader);
1137
241k
        int tmpLength = xmlStrlen(tmpBuffer);
1138
11.2M
        for (int i = 0; i < tmpLength && tmpBuffer[i]; ++i)
1139
10.9M
        {
1140
10.9M
          if (i < tmpLength-1 && 0xd == tmpBuffer[i] && 0xa == tmpBuffer[i+1])
1141
645
          {
1142
645
            tmpText.append((unsigned char)'\n');
1143
645
            ++i;
1144
645
          }
1145
          // utf-8 line separator 0xe2 0x80 0xa8 (0x2028) and paragraph separator 0xe2 0x80 0xa9 (0x2029)
1146
10.9M
          else if (i < tmpLength-2 && 0xe2 == tmpBuffer[i] && 0x80 == tmpBuffer[i+1] && (0xa8 == tmpBuffer[i+2] || 0xa9 == tmpBuffer[i+2]))
1147
300
          {
1148
300
            tmpText.append((unsigned char)'\n');
1149
300
            ++i;
1150
300
            ++i;
1151
300
          }
1152
10.9M
          else
1153
10.9M
            tmpText.append(tmpBuffer[i]);
1154
10.9M
        }
1155
241k
        unsigned charCount = m_shape.m_charList.getCharCount(cp);
1156
241k
        if (MINUS_ONE == charCount && !m_shape.m_charList.empty())
1157
          // fill non-existing character style with a legitimate default character style
1158
4.97k
          m_shape.m_charList.addCharIX(cp, m_shape.m_charList.getLevel(), m_shape.m_charStyle);
1159
241k
        if (!m_shape.m_charList.empty())
1160
50.8k
        {
1161
50.8k
          charCount += (unsigned)tmpText.size();
1162
50.8k
          m_shape.m_charList.setCharCount(cp, charCount);
1163
50.8k
        }
1164
1165
241k
        charCount = m_shape.m_paraList.getCharCount(pp);
1166
241k
        if (MINUS_ONE == charCount && !m_shape.m_paraList.empty())
1167
          // fill non-existing paragraph style with a legitimate default paragraph style
1168
4.57k
          m_shape.m_paraList.addParaIX(pp, m_shape.m_paraList.getLevel(), m_shape.m_paraStyle);
1169
241k
        if (!m_shape.m_paraList.empty())
1170
69.0k
        {
1171
69.0k
          charCount += (unsigned)tmpText.size();
1172
69.0k
          m_shape.m_paraList.setCharCount(pp, charCount);
1173
69.0k
        }
1174
1175
241k
        m_shape.m_tabSets[tp].m_numChars += (unsigned)tmpText.size();
1176
1177
241k
        m_shape.m_text.append(tmpText);
1178
241k
        m_shape.m_textFormat = VSD_TEXT_UTF8;
1179
241k
      }
1180
789k
      break;
1181
821k
    }
1182
821k
  }
1183
821k
  while ((XML_TEXT != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1184
66.4k
}
1185
1186
void libvisio::VSDXMLParserBase::readCharIX(xmlTextReaderPtr reader)
1187
62.9k
{
1188
62.9k
  if (xmlTextReaderIsEmptyElement(reader))
1189
233
    return;
1190
1191
62.7k
  unsigned ix = getIX(reader);
1192
1193
62.7k
  int ret = 1;
1194
62.7k
  int tokenId = XML_TOKEN_INVALID;
1195
62.7k
  int tokenType = -1;
1196
62.7k
  int level = getElementDepth(reader);
1197
1198
62.7k
  unsigned charCount = 0;
1199
62.7k
  std::optional<VSDName> font;
1200
62.7k
  std::optional<Colour> fontColour;
1201
1202
62.7k
  std::optional<bool> bold;
1203
62.7k
  std::optional<bool> italic;
1204
62.7k
  std::optional<bool> underline;
1205
62.7k
  std::optional<bool> doubleunderline;
1206
62.7k
  std::optional<bool> strikeout;
1207
62.7k
  std::optional<bool> doublestrikeout;
1208
62.7k
  std::optional<bool> allcaps;
1209
62.7k
  std::optional<bool> initcaps;
1210
62.7k
  std::optional<bool> smallcaps;
1211
62.7k
  std::optional<bool> superscript;
1212
62.7k
  std::optional<bool> subscript;
1213
62.7k
  std::optional<double> fontSize;
1214
62.7k
  std::optional<double> scaleWidth;
1215
1216
62.7k
  do
1217
876k
  {
1218
876k
    ret = xmlTextReaderRead(reader);
1219
876k
    tokenId = getElementToken(reader);
1220
876k
    if (XML_TOKEN_INVALID == tokenId)
1221
447k
    {
1222
447k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readCharIX: unknown token %s\n", xmlTextReaderConstName(reader)));
1223
447k
    }
1224
876k
    tokenType = xmlTextReaderNodeType(reader);
1225
876k
    switch (tokenId)
1226
876k
    {
1227
67.6k
    case XML_FONT:
1228
67.6k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1229
60.8k
      {
1230
60.8k
        const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
1231
60.8k
        if (stringValue && !xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
1232
53.0k
        {
1233
53.0k
          try
1234
53.0k
          {
1235
53.0k
            auto fontIndex = (unsigned)xmlStringToLong(stringValue);
1236
53.0k
            std::map<unsigned, VSDName>::const_iterator iter = m_fonts.find(fontIndex);
1237
53.0k
            if (iter != m_fonts.end())
1238
3.82k
              font = iter->second;
1239
49.2k
            else
1240
49.2k
              font = VSDName(librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get())), VSD_TEXT_UTF8);
1241
53.0k
          }
1242
53.0k
          catch (const XmlParserException &)
1243
53.0k
          {
1244
10.1k
            font = VSDName(librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get())), VSD_TEXT_UTF8);
1245
10.1k
          }
1246
53.0k
        }
1247
60.8k
      }
1248
67.6k
      break;
1249
67.6k
    case XML_COLOR:
1250
45.5k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1251
38.7k
        ret = readExtendedColourData(fontColour, reader);
1252
45.5k
      break;
1253
27.3k
    case XML_STYLE:
1254
27.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1255
24.7k
      {
1256
24.7k
        long value = 0;
1257
24.7k
        readLongData(value, reader);
1258
24.7k
        if (value &0x1)
1259
5.33k
          bold = true;
1260
19.4k
        else
1261
19.4k
          bold = false;
1262
24.7k
        if (value &0x2)
1263
1.33k
          italic = true;
1264
23.4k
        else
1265
23.4k
          italic = false;
1266
24.7k
        if (value &0x4)
1267
4.28k
          underline = true;
1268
20.4k
        else
1269
20.4k
          underline = false;
1270
24.7k
        if (value &0x8)
1271
82
          smallcaps = true;
1272
24.6k
        else
1273
24.6k
          smallcaps = false;
1274
24.7k
      }
1275
27.3k
      break;
1276
30.4k
    case XML_CASE:
1277
30.4k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1278
24.6k
      {
1279
24.6k
        long value = 0;
1280
24.6k
        readLongData(value, reader);
1281
24.6k
        switch (value)
1282
24.6k
        {
1283
1.59k
        case 1:
1284
1.59k
          allcaps = true;
1285
1.59k
          initcaps = false;
1286
1.59k
          break;
1287
1.39k
        case 2:
1288
1.39k
          allcaps = false;
1289
1.39k
          initcaps = true;
1290
1.39k
          break;
1291
21.6k
        default:
1292
21.6k
          allcaps = false;
1293
21.6k
          initcaps = false;
1294
21.6k
          break;
1295
24.6k
        }
1296
24.6k
      }
1297
30.4k
      break;
1298
30.4k
    case XML_POS:
1299
24.7k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1300
17.9k
      {
1301
17.9k
        long value = 0;
1302
17.9k
        readLongData(value, reader);
1303
17.9k
        switch (value)
1304
17.9k
        {
1305
5.73k
        case 1:
1306
5.73k
          superscript = true;
1307
5.73k
          subscript = false;
1308
5.73k
          break;
1309
929
        case 2:
1310
929
          subscript = true;
1311
929
          superscript = false;
1312
929
          break;
1313
11.2k
        default:
1314
11.2k
          subscript = false;
1315
11.2k
          superscript = false;
1316
11.2k
          break;
1317
17.9k
        }
1318
17.9k
      }
1319
24.7k
      break;
1320
24.7k
    case XML_FONTSCALE:
1321
18.6k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1322
16.9k
        ret = readDoubleData(scaleWidth, reader);
1323
18.6k
      break;
1324
20.3k
    case XML_SIZE:
1325
20.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1326
20.0k
        ret = readDoubleData(fontSize, reader);
1327
20.3k
      break;
1328
11.2k
    case XML_DBLUNDERLINE:
1329
11.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1330
9.10k
        readBoolData(doubleunderline, reader);
1331
11.2k
      break;
1332
10.5k
    case XML_OVERLINE:
1333
10.5k
      break;
1334
6.25k
    case XML_STRIKETHRU:
1335
6.25k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1336
6.07k
        readBoolData(strikeout, reader);
1337
6.25k
      break;
1338
4.27k
    case XML_HIGHLIGHT:
1339
4.27k
      break;
1340
4.64k
    case XML_DOUBLESTRIKETHROUGH:
1341
4.64k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1342
4.48k
        readBoolData(doublestrikeout, reader);
1343
4.64k
      break;
1344
605k
    default:
1345
605k
      break;
1346
876k
    }
1347
1348
876k
  }
1349
876k
  while (((XML_CHAR != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1350
1351
62.5k
  if (m_isInStyles)
1352
9.62k
    m_collector->collectCharIXStyle(ix, level, charCount, font, fontColour, fontSize, bold, italic,
1353
9.62k
                                    underline, doubleunderline, strikeout, doublestrikeout, allcaps,
1354
9.62k
                                    initcaps, smallcaps, superscript, subscript, scaleWidth);
1355
52.9k
  else
1356
52.9k
  {
1357
52.9k
    if (!ix || m_shape.m_charList.empty()) // character style 0 is the default character style
1358
40.5k
      m_shape.m_charStyle.override(VSDOptionalCharStyle(charCount, font, fontColour, fontSize, bold,
1359
40.5k
                                                        italic, underline, doubleunderline, strikeout, doublestrikeout,
1360
40.5k
                                                        allcaps, initcaps, smallcaps, superscript, subscript, scaleWidth));
1361
1362
52.9k
    m_shape.m_charList.addCharIX(ix, level, charCount, font, fontColour, fontSize, bold, italic,
1363
52.9k
                                 underline, doubleunderline, strikeout, doublestrikeout, allcaps,
1364
52.9k
                                 initcaps, smallcaps, superscript, subscript, scaleWidth);
1365
52.9k
  }
1366
62.5k
}
1367
1368
void libvisio::VSDXMLParserBase::readLayerIX(xmlTextReaderPtr reader)
1369
6.63k
{
1370
6.63k
  if (xmlTextReaderIsEmptyElement(reader))
1371
354
    return;
1372
1373
6.27k
  unsigned ix = getIX(reader);
1374
1375
6.27k
  int ret = 1;
1376
6.27k
  int tokenId = XML_TOKEN_INVALID;
1377
6.27k
  int tokenType = -1;
1378
6.27k
  int level = getElementDepth(reader);
1379
1380
6.27k
  VSDLayer layer;
1381
1382
6.27k
  do
1383
213k
  {
1384
213k
    ret = xmlTextReaderRead(reader);
1385
213k
    tokenId = getElementToken(reader);
1386
213k
    if (XML_TOKEN_INVALID == tokenId)
1387
146k
    {
1388
146k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readLayerIX: unknown token %s\n", xmlTextReaderConstName(reader)));
1389
146k
    }
1390
213k
    tokenType = xmlTextReaderNodeType(reader);
1391
1392
213k
    switch (tokenId)
1393
213k
    {
1394
3.31k
    case XML_COLOR:
1395
3.31k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1396
3.09k
      {
1397
3.09k
        Colour colour;
1398
3.09k
        long idx = -2;
1399
3.09k
        ret = readExtendedColourData(colour, idx, reader);
1400
3.09k
        if (idx != -1)
1401
2.03k
          layer.m_colour = colour;
1402
3.09k
      }
1403
3.31k
      break;
1404
870
    case XML_VISIBLE:
1405
870
      ret = readBoolData(layer.m_visible, reader);
1406
870
      break;
1407
1.69k
    case XML_PRINT:
1408
1.69k
      ret = readBoolData(layer.m_printable, reader);
1409
1.69k
      break;
1410
207k
    default:
1411
207k
      break;
1412
213k
    }
1413
213k
  }
1414
213k
  while (((XML_LAYER != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1415
1416
6.25k
  m_collector->collectLayer(ix, level, layer);
1417
6.25k
}
1418
1419
void libvisio::VSDXMLParserBase::readParaIX(xmlTextReaderPtr reader)
1420
76.2k
{
1421
76.2k
  if (xmlTextReaderIsEmptyElement(reader))
1422
138
    return;
1423
1424
76.0k
  unsigned ix = getIX(reader);
1425
1426
76.0k
  int ret = 1;
1427
76.0k
  int tokenId = XML_TOKEN_INVALID;
1428
76.0k
  int tokenType = -1;
1429
76.0k
  int level = getElementDepth(reader);
1430
1431
76.0k
  unsigned charCount = 0;
1432
76.0k
  std::optional<double> indFirst;
1433
76.0k
  std::optional<double> indLeft;
1434
76.0k
  std::optional<double> indRight;
1435
76.0k
  std::optional<double> spLine;
1436
76.0k
  std::optional<double> spBefore;
1437
76.0k
  std::optional<double> spAfter;
1438
76.0k
  std::optional<unsigned char> align;
1439
76.0k
  std::optional<unsigned char> bullet;
1440
76.0k
  std::optional<VSDName> bulletStr;
1441
76.0k
  std::optional<VSDName> bulletFont;
1442
76.0k
  std::optional<double> bulletFontSize;
1443
76.0k
  std::optional<double> textPosAfterBullet;
1444
76.0k
  std::optional<unsigned> flags;
1445
1446
76.0k
  do
1447
1.06M
  {
1448
1.06M
    ret = xmlTextReaderRead(reader);
1449
1.06M
    tokenId = getElementToken(reader);
1450
1.06M
    if (XML_TOKEN_INVALID == tokenId)
1451
621k
    {
1452
621k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readParaIX: unknown token %s\n", xmlTextReaderConstName(reader)));
1453
621k
    }
1454
1.06M
    tokenType = xmlTextReaderNodeType(reader);
1455
1456
1.06M
    switch (tokenId)
1457
1.06M
    {
1458
20.5k
    case XML_INDFIRST:
1459
20.5k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1460
19.7k
        ret = readDoubleData(indFirst, reader);
1461
20.5k
      break;
1462
22.2k
    case XML_INDLEFT:
1463
22.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1464
17.0k
        ret = readDoubleData(indLeft, reader);
1465
22.2k
      break;
1466
15.3k
    case XML_INDRIGHT:
1467
15.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1468
14.8k
        ret = readDoubleData(indRight, reader);
1469
15.3k
      break;
1470
16.4k
    case XML_SPLINE:
1471
16.4k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1472
15.7k
        ret = readDoubleData(spLine, reader);
1473
16.4k
      break;
1474
13.3k
    case XML_SPBEFORE:
1475
13.3k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1476
13.0k
        ret = readDoubleData(spBefore, reader);
1477
13.3k
      break;
1478
15.2k
    case XML_SPAFTER:
1479
15.2k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1480
14.5k
        ret = readDoubleData(spAfter, reader);
1481
15.2k
      break;
1482
19.8k
    case XML_HORZALIGN:
1483
19.8k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1484
18.0k
        ret = readByteData(align, reader);
1485
19.8k
      break;
1486
8.19k
    case XML_FLAGS:
1487
8.19k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1488
6.81k
        readUnsignedData(flags, reader);
1489
8.19k
      break;
1490
23.7k
    case XML_BULLET:
1491
23.7k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1492
23.0k
        ret = readByteData(bullet, reader);
1493
23.7k
      break;
1494
26.2k
    case XML_BULLETSTR:
1495
26.2k
      if (XML_READER_TYPE_ELEMENT == tokenType && !xmlTextReaderIsEmptyElement(reader))
1496
7.71k
      {
1497
7.71k
        const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
1498
7.71k
        if (stringValue && !xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
1499
6.00k
        {
1500
6.00k
          unsigned length = xmlStrlen(stringValue.get());
1501
6.00k
          const xmlChar *strV = stringValue.get();
1502
          // The character U+E000 is considered as empty string in VDX produced by Visio 2002
1503
6.00k
          if (3 != length || 0xee != strV[0] || 0x80 != strV[1] || 0x80 != strV[2])
1504
5.86k
            bulletStr = VSDName(librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get())), VSD_TEXT_UTF8);
1505
6.00k
        }
1506
7.71k
      }
1507
26.2k
      break;
1508
24.9k
    case XML_BULLETFONT:
1509
24.9k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1510
21.7k
      {
1511
21.7k
        const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
1512
21.7k
        if (stringValue && !xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
1513
19.8k
        {
1514
19.8k
          try
1515
19.8k
          {
1516
19.8k
            auto fontIndex = (unsigned)xmlStringToLong(stringValue);
1517
19.8k
            if (fontIndex)
1518
11.0k
            {
1519
11.0k
              std::map<unsigned, VSDName>::const_iterator iter = m_fonts.find(fontIndex);
1520
11.0k
              if (iter != m_fonts.end())
1521
7.30k
                bulletFont = iter->second;
1522
3.77k
              else
1523
3.77k
                bulletFont = VSDName(librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get())), VSD_TEXT_UTF8);
1524
11.0k
            }
1525
19.8k
          }
1526
19.8k
          catch (const XmlParserException &)
1527
19.8k
          {
1528
4.71k
            bulletFont = VSDName(librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get())), VSD_TEXT_UTF8);
1529
4.71k
          }
1530
19.8k
        }
1531
21.7k
      }
1532
24.9k
      break;
1533
24.9k
    case XML_BULLETFONTSIZE:
1534
10.5k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1535
10.3k
        ret = readDoubleData(bulletFontSize, reader);
1536
10.5k
      break;
1537
5.64k
    case XML_TEXTPOSAFTERBULLET:
1538
5.64k
      if (XML_READER_TYPE_ELEMENT == tokenType)
1539
5.53k
        ret = readDoubleData(textPosAfterBullet, reader);
1540
5.64k
      break;
1541
844k
    default:
1542
844k
      break;
1543
1.06M
    }
1544
1.06M
  }
1545
1.06M
  while (((XML_PARA != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1546
1547
75.8k
  if (m_isInStyles)
1548
9.85k
    m_collector->collectParaIXStyle(ix, level, charCount, indFirst, indLeft, indRight,
1549
9.85k
                                    spLine, spBefore, spAfter, align, bullet, bulletStr,
1550
9.85k
                                    bulletFont, bulletFontSize, textPosAfterBullet, flags);
1551
66.0k
  else
1552
66.0k
  {
1553
66.0k
    if (!ix || m_shape.m_paraList.empty()) // paragraph style 0 is the default paragraph style
1554
42.0k
      m_shape.m_paraStyle.override(VSDOptionalParaStyle(charCount, indFirst, indLeft, indRight,
1555
42.0k
                                                        spLine, spBefore, spAfter, align, bullet,
1556
42.0k
                                                        bulletStr, bulletFont, bulletFontSize,
1557
42.0k
                                                        textPosAfterBullet, flags));
1558
1559
66.0k
    m_shape.m_paraList.addParaIX(ix, level, charCount, indFirst, indLeft, indRight,
1560
66.0k
                                 spLine, spBefore, spAfter, align, bullet, bulletStr,
1561
66.0k
                                 bulletFont, bulletFontSize, textPosAfterBullet, flags);
1562
66.0k
  }
1563
75.8k
}
1564
1565
void libvisio::VSDXMLParserBase::readStyleSheet(xmlTextReaderPtr reader)
1566
36.6k
{
1567
36.6k
  const shared_ptr<xmlChar> id(xmlTextReaderGetAttribute(reader, BAD_CAST("ID")), xmlFree);
1568
36.6k
  const shared_ptr<xmlChar> lineStyle(xmlTextReaderGetAttribute(reader, BAD_CAST("LineStyle")), xmlFree);
1569
36.6k
  const shared_ptr<xmlChar> fillStyle(xmlTextReaderGetAttribute(reader, BAD_CAST("FillStyle")), xmlFree);
1570
36.6k
  const shared_ptr<xmlChar> textStyle(xmlTextReaderGetAttribute(reader, BAD_CAST("TextStyle")), xmlFree);
1571
36.6k
  if (id)
1572
33.7k
  {
1573
33.7k
    auto nId = (unsigned)xmlStringToLong(id);
1574
33.7k
    auto nLineStyle = (unsigned)(lineStyle ? xmlStringToLong(lineStyle) : -1);
1575
33.7k
    auto nFillStyle = (unsigned)(fillStyle ? xmlStringToLong(fillStyle) : -1);
1576
33.7k
    auto nTextStyle = (unsigned)(textStyle ? xmlStringToLong(textStyle) : -1);
1577
33.7k
    m_collector->collectStyleSheet(nId, (unsigned)getElementDepth(reader), nLineStyle, nFillStyle, nTextStyle);
1578
33.7k
  }
1579
36.6k
}
1580
1581
void libvisio::VSDXMLParserBase::readPageSheet(xmlTextReaderPtr reader)
1582
10.3k
{
1583
10.3k
  m_currentShapeLevel = (unsigned)getElementDepth(reader);
1584
10.3k
  m_collector->collectPageSheet(0, m_currentShapeLevel);
1585
10.3k
}
1586
1587
void libvisio::VSDXMLParserBase::readSplineStart(xmlTextReaderPtr reader)
1588
5.36k
{
1589
5.36k
  int ret = 1;
1590
5.36k
  int tokenId = XML_TOKEN_INVALID;
1591
5.36k
  int tokenType = -1;
1592
5.36k
  int level = getElementDepth(reader);
1593
1594
5.36k
  unsigned ix = getIX(reader);
1595
1596
5.36k
  if (xmlTextReaderIsEmptyElement(reader))
1597
137
  {
1598
137
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
1599
137
    if (delString)
1600
0
    {
1601
0
      if (xmlStringToBool(delString))
1602
0
        m_currentGeometryList->addEmpty(ix, level);
1603
0
    }
1604
137
    return;
1605
137
  }
1606
1607
5.23k
  std::optional<double> x;
1608
5.23k
  std::optional<double> y;
1609
5.23k
  std::optional<double> a;
1610
5.23k
  std::optional<double> b;
1611
5.23k
  std::optional<double> c;
1612
5.23k
  std::optional<unsigned> d;
1613
1614
5.23k
  do
1615
79.4k
  {
1616
79.4k
    ret = xmlTextReaderRead(reader);
1617
79.4k
    tokenId = getElementToken(reader);
1618
79.4k
    if (XML_TOKEN_INVALID == tokenId)
1619
59.8k
    {
1620
59.8k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readSplineStart: unknown token %s\n", xmlTextReaderConstName(reader)));
1621
59.8k
    }
1622
79.4k
    tokenType = xmlTextReaderNodeType(reader);
1623
1624
79.4k
    switch (tokenId)
1625
79.4k
    {
1626
1.16k
    case XML_X:
1627
1.16k
      ret = readDoubleData(x, reader);
1628
1.16k
      break;
1629
545
    case XML_Y:
1630
545
      ret = readDoubleData(y, reader);
1631
545
      break;
1632
273
    case XML_A:
1633
273
      ret = readDoubleData(a, reader);
1634
273
      break;
1635
184
    case XML_B:
1636
184
      ret = readDoubleData(b, reader);
1637
184
      break;
1638
532
    case XML_C:
1639
532
      ret = readDoubleData(c, reader);
1640
532
      break;
1641
1.56k
    case XML_D:
1642
1.56k
      ret = readUnsignedData(d, reader);
1643
1.56k
      break;
1644
75.1k
    default:
1645
75.1k
      break;
1646
79.4k
    }
1647
79.4k
  }
1648
79.3k
  while (((XML_SPLINESTART != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1649
5.19k
  if (ret == 1)
1650
3.70k
    m_currentGeometryList->addSplineStart(ix, level, x, y, a, b, c, d);
1651
5.19k
}
1652
1653
void libvisio::VSDXMLParserBase::readSplineKnot(xmlTextReaderPtr reader)
1654
3.51k
{
1655
3.51k
  int ret = 1;
1656
3.51k
  int tokenId = XML_TOKEN_INVALID;
1657
3.51k
  int tokenType = -1;
1658
3.51k
  int level = getElementDepth(reader);
1659
1660
3.51k
  unsigned ix = getIX(reader);
1661
1662
3.51k
  if (xmlTextReaderIsEmptyElement(reader))
1663
471
  {
1664
471
    const shared_ptr<xmlChar> delString(xmlTextReaderGetAttribute(reader, BAD_CAST("Del")), xmlFree);
1665
471
    if (delString)
1666
0
    {
1667
0
      if (xmlStringToBool(delString))
1668
0
        m_currentGeometryList->addEmpty(ix, level);
1669
0
    }
1670
471
    return;
1671
471
  }
1672
1673
3.04k
  std::optional<double> x;
1674
3.04k
  std::optional<double> y;
1675
3.04k
  std::optional<double> a;
1676
1677
3.04k
  do
1678
31.8k
  {
1679
31.8k
    ret = xmlTextReaderRead(reader);
1680
31.8k
    tokenId = getElementToken(reader);
1681
31.8k
    if (XML_TOKEN_INVALID == tokenId)
1682
20.6k
    {
1683
20.6k
      VSD_DEBUG_MSG(("VSDXMLParserBase::readSplineKnot: unknown token %s\n", xmlTextReaderConstName(reader)));
1684
20.6k
    }
1685
31.8k
    tokenType = xmlTextReaderNodeType(reader);
1686
1687
31.8k
    switch (tokenId)
1688
31.8k
    {
1689
963
    case XML_X:
1690
963
      ret = readDoubleData(x, reader);
1691
963
      break;
1692
589
    case XML_Y:
1693
589
      ret = readDoubleData(y, reader);
1694
589
      break;
1695
445
    case XML_A:
1696
445
      ret = readDoubleData(a, reader);
1697
445
      break;
1698
29.8k
    default:
1699
29.8k
      break;
1700
31.8k
    }
1701
31.8k
  }
1702
31.8k
  while (((XML_SPLINEKNOT != tokenId && XML_ROW != tokenId) || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret && (!m_watcher || !m_watcher->isError()));
1703
3.02k
  if (ret == 1)
1704
2.39k
    m_currentGeometryList->addSplineKnot(ix, level, x, y, a);
1705
3.02k
}
1706
1707
void libvisio::VSDXMLParserBase::readStencil(xmlTextReaderPtr reader)
1708
34.3k
{
1709
34.3k
  const shared_ptr<xmlChar> id(xmlTextReaderGetAttribute(reader, BAD_CAST("ID")), xmlFree);
1710
34.3k
  if (id)
1711
2.66k
  {
1712
2.66k
    auto nId = (unsigned)xmlStringToLong(id);
1713
2.66k
    m_currentStencilID = nId;
1714
2.66k
  }
1715
31.6k
  else
1716
31.6k
    m_currentStencilID = MINUS_ONE;
1717
34.3k
  m_currentStencil.reset(new VSDStencil());
1718
34.3k
}
1719
1720
void libvisio::VSDXMLParserBase::readForeignData(xmlTextReaderPtr reader)
1721
7.37k
{
1722
7.37k
  VSD_DEBUG_MSG(("VSDXMLParser::readForeignData\n"));
1723
7.37k
  if (!m_shape.m_foreign)
1724
2.16k
    m_shape.m_foreign = std::make_unique<ForeignData>();
1725
1726
7.37k
  const shared_ptr<xmlChar> foreignTypeString(xmlTextReaderGetAttribute(reader, BAD_CAST("ForeignType")), xmlFree);
1727
7.37k
  if (foreignTypeString)
1728
3.03k
  {
1729
3.03k
    if (xmlStrEqual(foreignTypeString.get(), BAD_CAST("Bitmap")))
1730
1.00k
      m_shape.m_foreign->type = 1;
1731
2.03k
    else if (xmlStrEqual(foreignTypeString.get(), BAD_CAST("Object")))
1732
0
      m_shape.m_foreign->type = 2;
1733
2.03k
    else if (xmlStrEqual(foreignTypeString.get(), BAD_CAST("EnhMetaFile")))
1734
1.40k
      m_shape.m_foreign->type = 4;
1735
632
    else if (xmlStrEqual(foreignTypeString.get(), BAD_CAST("MetaFile")))
1736
10
      m_shape.m_foreign->type = 0;
1737
3.03k
  }
1738
7.37k
  const shared_ptr<xmlChar> foreignFormatString(xmlTextReaderGetAttribute(reader, BAD_CAST("CompressionType")), xmlFree);
1739
7.37k
  if (foreignFormatString)
1740
947
  {
1741
947
    if (xmlStrEqual(foreignFormatString.get(), BAD_CAST("JPEG")))
1742
0
      m_shape.m_foreign->format = 1;
1743
947
    else if (xmlStrEqual(foreignFormatString.get(), BAD_CAST("GIF")))
1744
0
      m_shape.m_foreign->format = 2;
1745
947
    else if (xmlStrEqual(foreignFormatString.get(), BAD_CAST("TIFF")))
1746
0
      m_shape.m_foreign->format = 3;
1747
947
    else if (xmlStrEqual(foreignFormatString.get(), BAD_CAST("PNG")))
1748
333
      m_shape.m_foreign->format = 4;
1749
614
    else
1750
614
      m_shape.m_foreign->format = 0;
1751
947
  }
1752
6.42k
  else
1753
6.42k
    m_shape.m_foreign->format = 255;
1754
1755
7.37k
  getBinaryData(reader);
1756
7.37k
}
1757
1758
void libvisio::VSDXMLParserBase::_flushShape()
1759
292k
{
1760
292k
  if (!m_isShapeStarted)
1761
43.9k
    return;
1762
1763
248k
  m_collector->collectShape(m_shape.m_shapeId, m_currentShapeLevel, m_shape.m_parent,
1764
248k
                            m_shape.m_masterPage, m_shape.m_masterShape, m_shape.m_lineStyleId,
1765
248k
                            m_shape.m_fillStyleId, m_shape.m_textStyleId, m_shape.m_aName);
1766
1767
248k
  m_collector->collectShapesOrder(0, m_currentShapeLevel+2, m_shape.m_shapeList.getShapesOrder());
1768
1769
248k
  m_collector->collectXFormData(m_currentShapeLevel+2, m_shape.m_xform);
1770
1771
248k
  m_collector->collectLayerMem(m_currentShapeLevel+2, m_shape.m_layerMem);
1772
1773
248k
  m_collector->collectMisc(m_currentShapeLevel+2, m_shape.m_misc);
1774
1775
248k
  if (m_shape.m_txtxform)
1776
6.05k
    m_collector->collectTxtXForm(m_currentShapeLevel+2, *(m_shape.m_txtxform));
1777
1778
248k
  m_collector->collectLine(m_currentShapeLevel+2, m_shape.m_lineStyle.width, m_shape.m_lineStyle.colour, m_shape.m_lineStyle.pattern,
1779
248k
                           m_shape.m_lineStyle.startMarker, m_shape.m_lineStyle.endMarker, m_shape.m_lineStyle.cap, m_shape.m_lineStyle.rounding,
1780
248k
                           m_shape.m_lineStyle.qsLineColour, m_shape.m_lineStyle.qsLineMatrix);
1781
1782
248k
  m_collector->collectFillAndShadow(m_currentShapeLevel+2, m_shape.m_fillStyle.fgColour, m_shape.m_fillStyle.bgColour, m_shape.m_fillStyle.pattern,
1783
248k
                                    m_shape.m_fillStyle.fgTransparency, m_shape.m_fillStyle.bgTransparency, m_shape.m_fillStyle.shadowPattern,
1784
248k
                                    m_shape.m_fillStyle.shadowFgColour, m_shape.m_fillStyle.shadowOffsetX, m_shape.m_fillStyle.shadowOffsetY,
1785
248k
                                    m_shape.m_fillStyle.qsFillColour, m_shape.m_fillStyle.qsShadowColour, m_shape.m_fillStyle.qsFillMatrix);
1786
1787
248k
  m_collector->collectTextBlock(m_currentShapeLevel+2, m_shape.m_textBlockStyle.leftMargin, m_shape.m_textBlockStyle.rightMargin,
1788
248k
                                m_shape.m_textBlockStyle.topMargin, m_shape.m_textBlockStyle.bottomMargin, m_shape.m_textBlockStyle.verticalAlign,
1789
248k
                                m_shape.m_textBlockStyle.isTextBkgndFilled, m_shape.m_textBlockStyle.textBkgndColour,
1790
248k
                                m_shape.m_textBlockStyle.defaultTabStop, m_shape.m_textBlockStyle.textDirection);
1791
1792
248k
  if (m_shape.m_foreign)
1793
6.80k
    m_collector->collectForeignDataType(m_currentShapeLevel+2, m_shape.m_foreign->type, m_shape.m_foreign->format,
1794
6.80k
                                        m_shape.m_foreign->offsetX, m_shape.m_foreign->offsetY, m_shape.m_foreign->width, m_shape.m_foreign->height);
1795
1796
248k
  for (std::map<unsigned, NURBSData>::const_iterator iterNurbs = m_shape.m_nurbsData.begin(); iterNurbs != m_shape.m_nurbsData.end(); ++iterNurbs)
1797
0
    m_collector->collectShapeData(iterNurbs->first, m_currentShapeLevel+2, iterNurbs->second.xType, iterNurbs->second.yType,
1798
0
                                  iterNurbs->second.degree, iterNurbs->second.lastKnot, iterNurbs->second.points,
1799
0
                                  iterNurbs->second.knots, iterNurbs->second.weights);
1800
1801
248k
  for (std::map<unsigned, PolylineData>::const_iterator iterPoly = m_shape.m_polylineData.begin(); iterPoly != m_shape.m_polylineData.end(); ++iterPoly)
1802
0
    m_collector->collectShapeData(iterPoly->first, m_currentShapeLevel+2, iterPoly->second.xType, iterPoly->second.yType, iterPoly->second.points);
1803
1804
248k
  for (std::map<unsigned, VSDName>::const_iterator iterName = m_shape.m_names.begin(); iterName != m_shape.m_names.end(); ++iterName)
1805
0
    m_collector->collectName(iterName->first, m_currentShapeLevel+2, iterName->second.m_data, iterName->second.m_format);
1806
1807
248k
  if (!m_shape.m_geometries.empty())
1808
45.8k
  {
1809
45.8k
    for (auto &geometry : m_shape.m_geometries)
1810
77.9k
      geometry.second.resetLevel(m_currentShapeLevel+2);
1811
45.8k
    std::vector<unsigned> tmpVector;
1812
123k
    for (std::map<unsigned, VSDGeometryList>::const_iterator iterGeom = m_shape.m_geometries.begin(); iterGeom != m_shape.m_geometries.end(); ++iterGeom)
1813
77.9k
      tmpVector.push_back(iterGeom->first);
1814
45.8k
    std::sort(tmpVector.begin(), tmpVector.end());
1815
1816
45.8k
    for (unsigned int i : tmpVector)
1817
77.9k
    {
1818
77.9k
      std::map<unsigned, VSDGeometryList>::const_iterator iter = m_shape.m_geometries.find(i);
1819
77.9k
      if (iter != m_shape.m_geometries.end())
1820
77.9k
      {
1821
77.9k
        iter->second.handle(m_collector);
1822
77.9k
        m_collector->collectUnhandledChunk(0, m_currentShapeLevel+1);
1823
77.9k
      }
1824
77.9k
    }
1825
45.8k
  }
1826
1827
248k
  if (m_shape.m_foreign && m_shape.m_foreign->data.size())
1828
1.70k
    m_collector->collectForeignData(m_currentShapeLevel+1, m_shape.m_foreign->data);
1829
1830
248k
  m_collector->collectTabsDataList(m_currentShapeLevel+1, m_shape.m_tabSets);
1831
1832
248k
  if (!m_shape.m_fields.empty())
1833
0
    m_shape.m_fields.handle(m_collector);
1834
1835
248k
  if (m_shape.m_text.size())
1836
26.9k
    m_collector->collectText(m_currentShapeLevel+1, m_shape.m_text, m_shape.m_textFormat);
1837
1838
248k
  m_collector->collectDefaultCharStyle(m_shape.m_charStyle.charCount, m_shape.m_charStyle.font, m_shape.m_charStyle.colour,
1839
248k
                                       m_shape.m_charStyle.size, m_shape.m_charStyle.bold, m_shape.m_charStyle.italic, m_shape.m_charStyle.underline,
1840
248k
                                       m_shape.m_charStyle.doubleunderline, m_shape.m_charStyle.strikeout, m_shape.m_charStyle.doublestrikeout,
1841
248k
                                       m_shape.m_charStyle.allcaps, m_shape.m_charStyle.initcaps, m_shape.m_charStyle.smallcaps,
1842
248k
                                       m_shape.m_charStyle.superscript, m_shape.m_charStyle.subscript, m_shape.m_charStyle.scaleWidth);
1843
1844
248k
  m_shape.m_charList.handle(m_collector);
1845
1846
248k
  m_collector->collectDefaultParaStyle(m_shape.m_paraStyle.charCount, m_shape.m_paraStyle.indFirst, m_shape.m_paraStyle.indLeft,
1847
248k
                                       m_shape.m_paraStyle.indRight, m_shape.m_paraStyle.spLine, m_shape.m_paraStyle.spBefore,
1848
248k
                                       m_shape.m_paraStyle.spAfter, m_shape.m_paraStyle.align, m_shape.m_paraStyle.bullet,
1849
248k
                                       m_shape.m_paraStyle.bulletStr, m_shape.m_paraStyle.bulletFont, m_shape.m_paraStyle.bulletFontSize,
1850
248k
                                       m_shape.m_paraStyle.textPosAfterBullet, m_shape.m_paraStyle.flags);
1851
1852
248k
  m_shape.m_paraList.handle(m_collector);
1853
1854
248k
  m_collector->collectUnhandledChunk(0, m_currentShapeLevel);
1855
248k
}
1856
1857
void libvisio::VSDXMLParserBase::_handleLevelChange(unsigned level)
1858
11.2M
{
1859
11.2M
  m_currentLevel = level;
1860
11.2M
  m_collector->collectUnhandledChunk(0, m_currentLevel);
1861
11.2M
}
1862
1863
void libvisio::VSDXMLParserBase::handlePagesStart(xmlTextReaderPtr reader)
1864
31.2k
{
1865
31.2k
  m_isShapeStarted = false;
1866
31.2k
  m_isStencilStarted = false;
1867
31.2k
  if (m_extractStencils)
1868
0
    skipPages(reader);
1869
31.2k
}
1870
1871
void libvisio::VSDXMLParserBase::handlePagesEnd(xmlTextReaderPtr /* reader */)
1872
38.2k
{
1873
38.2k
  m_isShapeStarted = false;
1874
38.2k
  if (!m_extractStencils)
1875
38.2k
    m_collector->endPages();
1876
38.2k
}
1877
1878
void libvisio::VSDXMLParserBase::handlePageStart(xmlTextReaderPtr reader)
1879
33.0k
{
1880
33.0k
  m_isShapeStarted = false;
1881
33.0k
  if (!m_extractStencils)
1882
33.0k
    readPage(reader);
1883
33.0k
}
1884
1885
void libvisio::VSDXMLParserBase::handlePageEnd(xmlTextReaderPtr /* reader */)
1886
37.4k
{
1887
37.4k
  m_isShapeStarted = false;
1888
37.4k
  if (!m_extractStencils)
1889
37.4k
  {
1890
37.4k
    m_collector->collectShapesOrder(0, 2, m_shapeList.getShapesOrder());
1891
37.4k
    _handleLevelChange(0);
1892
37.4k
    m_shapeList.clear();
1893
37.4k
    m_isPageStarted = false;
1894
37.4k
    m_collector->endPage();
1895
37.4k
  }
1896
37.4k
}
1897
1898
void libvisio::VSDXMLParserBase::handleMastersStart(xmlTextReaderPtr reader)
1899
16.3k
{
1900
16.3k
  m_isShapeStarted = false;
1901
16.3k
  if (m_stencils.count())
1902
5.63k
    skipMasters(reader);
1903
10.6k
  else
1904
10.6k
  {
1905
10.6k
    if (m_extractStencils)
1906
0
      m_isStencilStarted = false;
1907
10.6k
    else
1908
10.6k
      m_isStencilStarted = true;
1909
10.6k
  }
1910
16.3k
}
1911
1912
void libvisio::VSDXMLParserBase::handleMastersEnd(xmlTextReaderPtr /* reader */)
1913
19.5k
{
1914
19.5k
  m_isShapeStarted = false;
1915
19.5k
  if (m_extractStencils)
1916
0
    m_collector->endPages();
1917
19.5k
  else
1918
19.5k
    m_isStencilStarted = false;
1919
19.5k
}
1920
1921
void libvisio::VSDXMLParserBase::handleMasterStart(xmlTextReaderPtr reader)
1922
34.3k
{
1923
34.3k
  m_isShapeStarted = false;
1924
34.3k
  if (m_extractStencils)
1925
0
    readPage(reader);
1926
34.3k
  else
1927
34.3k
    readStencil(reader);
1928
34.3k
}
1929
1930
void libvisio::VSDXMLParserBase::handleMasterEnd(xmlTextReaderPtr /* reader */)
1931
41.3k
{
1932
41.3k
  m_isShapeStarted = false;
1933
41.3k
  m_isPageStarted = false;
1934
41.3k
  if (m_extractStencils)
1935
0
  {
1936
0
    m_collector->collectShapesOrder(0, 2, m_shapeList.getShapesOrder());
1937
0
    _handleLevelChange(0);
1938
0
    m_shapeList.clear();
1939
0
    m_isPageStarted = false;
1940
0
    m_collector->endPage();
1941
0
  }
1942
41.3k
  else
1943
41.3k
  {
1944
41.3k
    if (m_currentStencil)
1945
26.1k
      m_stencils.addStencil(m_currentStencilID, *m_currentStencil);
1946
41.3k
    m_currentStencil.reset();
1947
41.3k
    m_currentStencilID = MINUS_ONE;
1948
41.3k
  }
1949
41.3k
}
1950
1951
void libvisio::VSDXMLParserBase::skipMasters(xmlTextReaderPtr reader)
1952
5.63k
{
1953
5.63k
  int ret = 1;
1954
5.63k
  int tokenId = XML_TOKEN_INVALID;
1955
5.63k
  int tokenType = -1;
1956
5.63k
  do
1957
675k
  {
1958
675k
    ret = xmlTextReaderRead(reader);
1959
675k
    tokenId = getElementToken(reader);
1960
675k
    tokenType = xmlTextReaderNodeType(reader);
1961
675k
  }
1962
675k
  while ((XML_MASTERS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
1963
5.63k
}
1964
1965
void libvisio::VSDXMLParserBase::skipPages(xmlTextReaderPtr reader)
1966
0
{
1967
0
  int ret = 1;
1968
0
  int tokenId = XML_TOKEN_INVALID;
1969
0
  int tokenType = -1;
1970
0
  do
1971
0
  {
1972
0
    ret = xmlTextReaderRead(reader);
1973
0
    tokenId = getElementToken(reader);
1974
0
    tokenType = xmlTextReaderNodeType(reader);
1975
0
  }
1976
0
  while ((XML_PAGES != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
1977
0
}
1978
1979
int libvisio::VSDXMLParserBase::readNURBSData(std::optional<NURBSData> &data, xmlTextReaderPtr reader)
1980
17.1k
{
1981
17.1k
  NURBSData tmpData;
1982
1983
17.1k
  bool bRes = false;
1984
17.1k
  const shared_ptr<xmlChar> formula(readStringData(reader), xmlFree);
1985
1986
17.1k
  if (formula)
1987
16.2k
  {
1988
16.2k
    std::pair<double, double> point;
1989
1990
16.2k
    using namespace boost::spirit::qi;
1991
16.2k
    namespace phx = boost::phoenix;
1992
16.2k
    using phx::push_back;
1993
16.2k
    using phx::ref;
1994
1995
16.2k
    auto first = reinterpret_cast<const char *>(formula.get());
1996
16.2k
    const auto last = first + strlen(first);
1997
16.2k
    bRes = phrase_parse(first, last,
1998
                        //  Begin grammar
1999
16.2k
                        (
2000
16.2k
                          lit("NURBS")
2001
16.2k
                          >> '('
2002
16.2k
                          >> double_[ref(tmpData.lastKnot) = _1] >> -lit(',')
2003
16.2k
                          >> int_[ref(tmpData.degree) = _1] >> -lit(',')
2004
16.2k
                          >> int_[ref(tmpData.xType) = _1] >> -lit(',')
2005
16.2k
                          >> int_[ref(tmpData.yType) = _1] >> -lit(',')
2006
16.2k
                          >> // array of points, weights and knots
2007
16.2k
                          (
2008
16.2k
                            (
2009
16.2k
                              (double_[ref(point.first) = _1] >> -lit(',') >>
2010
16.2k
                               double_[ref(point.second) = _1]
2011
16.2k
                              )[push_back(phx::ref(tmpData.points), phx::cref(point))]
2012
16.2k
                              >> -lit(',') >>
2013
16.2k
                              double_[push_back(phx::ref(tmpData.knots),
2014
16.2k
                                                _1)] >> -lit(',') >>
2015
16.2k
                              double_[push_back(phx::ref(tmpData.weights), _1)]
2016
16.2k
                            )
2017
16.2k
                            % -lit(',')
2018
16.2k
                          )
2019
16.2k
                          >> ')'
2020
16.2k
                        ),
2021
                        //  End grammar
2022
16.2k
                        space)
2023
1.04k
           && first == last;
2024
16.2k
  }
2025
2026
17.1k
  if (!bRes)
2027
16.3k
    return -1;
2028
822
  data = tmpData;
2029
822
  return 1;
2030
17.1k
}
2031
2032
int libvisio::VSDXMLParserBase::readPolylineData(std::optional<PolylineData> &data, xmlTextReaderPtr reader)
2033
1.67k
{
2034
1.67k
  PolylineData tmpData;
2035
2036
1.67k
  bool bRes = false;
2037
1.67k
  const shared_ptr<xmlChar> formula(readStringData(reader), xmlFree);
2038
2039
1.67k
  if (formula)
2040
1.06k
  {
2041
1.06k
    std::pair<double, double> point;
2042
2043
1.06k
    using namespace boost::spirit::qi;
2044
1.06k
    namespace phx = boost::phoenix;
2045
1.06k
    using phx::push_back;
2046
1.06k
    using phx::ref;
2047
2048
1.06k
    auto first = reinterpret_cast<const char *>(formula.get());
2049
1.06k
    const auto last = first + strlen(first);
2050
1.06k
    bRes = phrase_parse(first, last,
2051
1.06k
                        (
2052
1.06k
                          lit("POLYLINE")
2053
1.06k
                          >> '('
2054
1.06k
                          >> int_[ref(tmpData.xType) = _1] >> -lit(',')
2055
1.06k
                          >> int_[ref(tmpData.yType) = _1] >> -lit(',')
2056
1.06k
                          >> // array of points
2057
1.06k
                          (
2058
1.06k
                            (
2059
1.06k
                              double_[ref(point.first) = _1] >> -lit(',')
2060
1.06k
                              >> double_[ref(point.second) = _1]
2061
1.06k
                            )[push_back(phx::ref(tmpData.points), phx::cref(point))] % -lit(',')
2062
1.06k
                          )
2063
1.06k
                          >> ')'
2064
1.06k
                        ),
2065
1.06k
                        space)
2066
0
           && first == last;
2067
1.06k
  }
2068
2069
1.67k
  if (!bRes)
2070
1.67k
    return -1;
2071
0
  data = tmpData;
2072
0
  return 1;
2073
1.67k
}
2074
2075
2076
int libvisio::VSDXMLParserBase::readDoubleData(double &value, xmlTextReaderPtr reader)
2077
422k
{
2078
422k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2079
422k
  if (stringValue)
2080
393k
  {
2081
393k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readDoubleData stringValue %s\n", (const char *)stringValue.get()));
2082
393k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2083
393k
      value = xmlStringToDouble(stringValue);
2084
393k
    return 1;
2085
393k
  }
2086
29.1k
  return -1;
2087
422k
}
2088
2089
int libvisio::VSDXMLParserBase::readStringData(libvisio::VSDName &text, xmlTextReaderPtr reader)
2090
4.63k
{
2091
4.63k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2092
4.63k
  if (stringValue)
2093
2.07k
  {
2094
2.07k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readStringData stringValue %s\n", (const char *)stringValue.get()));
2095
2.07k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2096
2.07k
    {
2097
2.07k
      text.m_data = librevenge::RVNGBinaryData(stringValue.get(), xmlStrlen(stringValue.get()));
2098
2.07k
      text.m_format = VSD_TEXT_UTF8;
2099
2.07k
    }
2100
2.07k
    return 1;
2101
2.07k
  }
2102
2.55k
  return -1;
2103
4.63k
}
2104
2105
int libvisio::VSDXMLParserBase::readDoubleData(std::optional<double> &value, xmlTextReaderPtr reader)
2106
772k
{
2107
772k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2108
772k
  if (stringValue)
2109
751k
  {
2110
751k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readDoubleData stringValue %s\n", (const char *)stringValue.get()));
2111
751k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2112
734k
      value = xmlStringToDouble(stringValue);
2113
751k
    return 1;
2114
751k
  }
2115
20.9k
  return -1;
2116
772k
}
2117
2118
int libvisio::VSDXMLParserBase::readLongData(long &value, xmlTextReaderPtr reader)
2119
87.9k
{
2120
87.9k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2121
87.9k
  if (stringValue)
2122
74.9k
  {
2123
74.9k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readLongData stringValue %s\n", (const char *)stringValue.get()));
2124
74.9k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2125
73.9k
      value = xmlStringToLong(stringValue);
2126
74.9k
    return 1;
2127
74.9k
  }
2128
12.9k
  return -1;
2129
87.9k
}
2130
2131
int libvisio::VSDXMLParserBase::readLongData(std::optional<long> &value, xmlTextReaderPtr reader)
2132
210k
{
2133
210k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2134
210k
  if (stringValue)
2135
205k
  {
2136
205k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readLongData stringValue %s\n", (const char *)stringValue.get()));
2137
205k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2138
196k
      value = xmlStringToLong(stringValue);
2139
205k
    return 1;
2140
205k
  }
2141
5.33k
  return -1;
2142
210k
}
2143
2144
int libvisio::VSDXMLParserBase::readBoolData(bool &value, xmlTextReaderPtr reader)
2145
40.2k
{
2146
40.2k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2147
40.2k
  if (stringValue)
2148
38.9k
  {
2149
38.9k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readBoolData stringValue %s\n", (const char *)stringValue.get()));
2150
38.9k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2151
38.9k
      value = xmlStringToBool(stringValue);
2152
38.9k
    return 1;
2153
38.9k
  }
2154
1.27k
  return -1;
2155
40.2k
}
2156
2157
int libvisio::VSDXMLParserBase::readBoolData(std::optional<bool> &value, xmlTextReaderPtr reader)
2158
102k
{
2159
102k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2160
102k
  if (stringValue)
2161
98.8k
  {
2162
98.8k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readBoolData stringValue %s\n", (const char *)stringValue.get()));
2163
98.8k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2164
98.8k
      value = xmlStringToBool(stringValue);
2165
98.8k
    return 1;
2166
98.8k
  }
2167
3.59k
  return -1;
2168
102k
}
2169
2170
int libvisio::VSDXMLParserBase::readUnsignedData(std::optional<unsigned> &value, xmlTextReaderPtr reader)
2171
8.42k
{
2172
8.42k
  std::optional<long> tmpValue;
2173
8.42k
  int ret = readLongData(tmpValue, reader);
2174
8.42k
  if (!!tmpValue)
2175
6.87k
    value = (unsigned)tmpValue.value();
2176
8.42k
  return ret;
2177
8.42k
}
2178
2179
int libvisio::VSDXMLParserBase::readByteData(unsigned char &value, xmlTextReaderPtr reader)
2180
20.6k
{
2181
20.6k
  long longValue = 0;
2182
20.6k
  int ret = readLongData(longValue, reader);
2183
20.6k
  value = (unsigned char) longValue;
2184
20.6k
  return ret;
2185
20.6k
}
2186
2187
int libvisio::VSDXMLParserBase::readByteData(std::optional<unsigned char> &value, xmlTextReaderPtr reader)
2188
186k
{
2189
186k
  std::optional<long> tmpValue;
2190
186k
  int ret = readLongData(tmpValue, reader);
2191
186k
  if (!!tmpValue)
2192
174k
    value = (unsigned char) tmpValue.value();
2193
186k
  return ret;
2194
186k
}
2195
2196
int libvisio::VSDXMLParserBase::readExtendedColourData(Colour &value, long &idx, xmlTextReaderPtr reader)
2197
223k
{
2198
223k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2199
223k
  if (stringValue)
2200
210k
  {
2201
210k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readColourData stringValue %s\n", (const char *)stringValue.get()));
2202
210k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2203
199k
    {
2204
199k
      try
2205
199k
      {
2206
199k
        value = xmlStringToColour(stringValue);
2207
199k
      }
2208
199k
      catch (const XmlParserException &)
2209
199k
      {
2210
157k
        idx = xmlStringToLong(stringValue);
2211
157k
      }
2212
199k
      if (idx >= 0)
2213
154k
      {
2214
154k
        std::map<unsigned, Colour>::const_iterator iter = m_colours.find((unsigned)idx);
2215
154k
        if (iter != m_colours.end())
2216
145k
          value = iter->second;
2217
8.94k
        else
2218
8.94k
          idx = -1;
2219
154k
      }
2220
199k
    }
2221
11.0k
    else
2222
11.0k
      return -1000;
2223
199k
    return 1;
2224
210k
  }
2225
12.7k
  return -1;
2226
223k
}
2227
2228
int libvisio::VSDXMLParserBase::readExtendedColourData(std::optional<Colour> &value, xmlTextReaderPtr reader)
2229
204k
{
2230
204k
  Colour tmpValue;
2231
204k
  int ret = readExtendedColourData(tmpValue, reader);
2232
204k
  if (ret != -1000)
2233
193k
    value = tmpValue;
2234
11.1k
  else
2235
11.1k
    ret = 1;
2236
204k
  return ret;
2237
204k
}
2238
2239
/* Currently this method is used only for VSDX import, to avoid regression.
2240
 * TODO align usage with other file type importers (VSD), and cover it with test cases
2241
 */
2242
bool libvisio::VSDXMLParserBase::readColourOrColourIndex(Colour &value, long &idx, xmlTextReaderPtr reader)
2243
4.10k
{
2244
4.10k
  const shared_ptr<xmlChar> stringValue(readStringData(reader), xmlFree);
2245
4.10k
  if (stringValue)
2246
4.06k
  {
2247
4.06k
    VSD_DEBUG_MSG(("VSDXMLParserBase::readExtendedColourData stringValue %s\n", (const char *)stringValue.get()));
2248
4.06k
    if (!xmlStrEqual(stringValue.get(), BAD_CAST("Themed")))
2249
4.05k
    {
2250
4.05k
      try
2251
4.05k
      {
2252
4.05k
        value = xmlStringToColour(stringValue);
2253
4.05k
        return true;
2254
4.05k
      }
2255
4.05k
      catch (const XmlParserException &)
2256
4.05k
      {
2257
3.85k
        idx = xmlStringToLong(stringValue);
2258
3.85k
      }
2259
4.05k
    }
2260
4.06k
  }
2261
3.90k
  return false;
2262
4.10k
}
2263
2264
int libvisio::VSDXMLParserBase::readExtendedColourData(Colour &value, xmlTextReaderPtr reader)
2265
204k
{
2266
204k
  long idx = -1;
2267
204k
  return readExtendedColourData(value, idx, reader);
2268
204k
}
2269
2270
unsigned libvisio::VSDXMLParserBase::getIX(xmlTextReaderPtr reader)
2271
814k
{
2272
814k
  auto ix = MINUS_ONE;
2273
814k
  const std::shared_ptr<xmlChar> ixString(xmlTextReaderGetAttribute(reader, BAD_CAST("IX")), xmlFree);
2274
814k
  if (ixString)
2275
517k
    ix = (unsigned)xmlStringToLong(ixString.get());
2276
814k
  return ix;
2277
814k
}
2278
2279
void libvisio::VSDXMLParserBase::readTriggerId(unsigned &id, xmlTextReaderPtr reader)
2280
9.66k
{
2281
9.66k
  using namespace boost::spirit::qi;
2282
2283
9.66k
  auto triggerId = MINUS_ONE;
2284
9.66k
  const std::shared_ptr<xmlChar> triggerString(xmlTextReaderGetAttribute(reader, BAD_CAST("F")), xmlFree);
2285
9.66k
  if (triggerString)
2286
8.34k
  {
2287
8.34k
    auto first = reinterpret_cast<const char *>(triggerString.get());
2288
8.34k
    const auto last = first + strlen(first);
2289
8.34k
    if (phrase_parse(first, last,
2290
8.34k
                     (
2291
8.34k
                       lit("_XFTRIGGER")
2292
8.34k
                       >> '(' >> omit[+alnum] >> '.'
2293
8.34k
                       >> int_ >> '!' >> lit("EventXFMod")
2294
8.34k
                       >> ')'
2295
8.34k
                     ),
2296
8.34k
                     space, triggerId) && first == last)
2297
0
      id = triggerId;
2298
8.34k
  }
2299
9.66k
}
2300
2301
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */