Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libetonyek/src/lib/KEY1Parser.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 libetonyek 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 <boost/spirit/include/qi.hpp>
11
12
#include <glm/glm.hpp>
13
#include <memory>
14
15
#include "KEY1Parser.h"
16
17
#include "libetonyek_xml.h"
18
19
#include "IWORKDiscardContext.h"
20
#include "IWORKProperties.h"
21
#include "IWORKRecorder.h"
22
#include "IWORKText.h"
23
#include "IWORKTokenizer.h"
24
#include "KEYCollector.h"
25
#include "KEYEnum.h"
26
#include "KEY1ContentElement.h"
27
#include "KEY1Dictionary.h"
28
#include "KEY1DivElement.h"
29
#include "KEY1FillElement.h"
30
#include "KEY1ParserState.h"
31
#include "KEY1SpanElement.h"
32
#include "KEY1StringConverter.h"
33
#include "KEY1StylesContext.h"
34
#include "KEY1TableElement.h"
35
#include "KEY1Token.h"
36
#include "KEY1XMLContextBase.h"
37
38
using boost::optional;
39
40
namespace libetonyek
41
{
42
43
namespace
44
{
45
46
class MetadataElement : public KEY1XMLElementContextBase
47
{
48
public:
49
  explicit MetadataElement(KEY1ParserState &state);
50
51
protected:
52
  IWORKXMLContextPtr_t element(int name) override;
53
  void endOfElement() override;
54
55
private:
56
  boost::optional<std::string> m_author;
57
  boost::optional<std::string> m_title;
58
  boost::optional<std::string> m_keywords;
59
  boost::optional<std::string> m_comment;
60
};
61
62
MetadataElement::MetadataElement(KEY1ParserState &state)
63
0
  : KEY1XMLElementContextBase(state)
64
0
  , m_author()
65
0
  , m_title()
66
0
  , m_keywords()
67
0
  , m_comment()
68
0
{
69
0
}
70
71
IWORKXMLContextPtr_t MetadataElement::element(const int name)
72
0
{
73
0
  switch (name)
74
0
  {
75
  // find application-name, application-version, time-stamp
76
0
  default:
77
0
    break;
78
0
  }
79
80
0
  return IWORKXMLContextPtr_t();
81
0
}
82
83
void MetadataElement::endOfElement()
84
0
{
85
0
  IWORKMetadata metadata;
86
87
0
  if (m_author)
88
0
    metadata.m_author = get(m_author);
89
0
  if (m_title)
90
0
    metadata.m_title = get(m_title);
91
0
  if (m_keywords)
92
0
    metadata.m_keywords = get(m_keywords);
93
0
  if (m_comment)
94
0
    metadata.m_comment = get(m_comment);
95
96
0
  if (isCollector())
97
0
    getCollector().collectMetadata(metadata);
98
0
}
99
100
}
101
102
namespace
103
{
104
105
class CDATAElement : public KEY1XMLElementContextBase
106
{
107
public:
108
  explicit CDATAElement(KEY1ParserState &state, boost::optional<std::string> &description);
109
110
private:
111
  IWORKXMLContextPtr_t element(int name) override;
112
  void CDATA(const char *value) override;
113
114
private:
115
  boost::optional<std::string> &m_description;
116
};
117
118
CDATAElement::CDATAElement(KEY1ParserState &state, boost::optional<std::string> &description)
119
0
  : KEY1XMLElementContextBase(state)
120
0
  , m_description(description)
121
0
{
122
0
}
123
124
void CDATAElement::CDATA(const char *value)
125
0
{
126
0
  m_description=value;
127
0
}
128
129
130
IWORKXMLContextPtr_t CDATAElement::element(const int /*name*/)
131
0
{
132
0
  ETONYEK_DEBUG_MSG(("CDATAElement::element[KEY1Parser.cpp]: unknown element\n"));
133
134
0
  return IWORKXMLContextPtr_t();
135
0
}
136
137
}
138
139
namespace
140
{
141
142
class TransitionStyleElement : public KEY1XMLElementContextBase
143
{
144
public:
145
  explicit TransitionStyleElement(KEY1ParserState &state);
146
147
private:
148
  void attribute(int name, const char *value) override;
149
  IWORKXMLContextPtr_t element(int name) override;
150
151
private:
152
  KEYTransition m_transitionStyle;
153
};
154
155
TransitionStyleElement::TransitionStyleElement(KEY1ParserState &state)
156
0
  : KEY1XMLElementContextBase(state)
157
0
  , m_transitionStyle()
158
0
{
159
0
}
160
161
void TransitionStyleElement::attribute(const int name, const char *const value)
162
0
{
163
0
  switch (name)
164
0
  {
165
0
  case KEY1Token::duration :
166
0
    m_transitionStyle.m_duration=try_double_cast(value);
167
0
    break;
168
0
  case KEY1Token::type :
169
0
    switch (getState().getTokenizer().getId(value))
170
0
    {
171
0
    case KEY1Token::none :
172
0
      m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_NONE;
173
0
      break;
174
0
    case KEY1Token::inherited :
175
0
      m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_INHERITED;
176
0
      break;
177
0
    default :
178
0
    {
179
0
      m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_NAMED;
180
0
      m_transitionStyle.m_name=value;
181
0
      static bool first=true;
182
0
      if (first)
183
0
      {
184
0
        first=false;
185
0
        ETONYEK_DEBUG_MSG(("TransitionStyleElement::attribute[KEY1Parser.cpp]: find some unexpected type=%s\n", value));
186
0
      }
187
0
      break;
188
0
    }
189
0
    }
190
0
    break;
191
0
  default :
192
0
    ETONYEK_DEBUG_MSG(("TransitionStyleElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
193
0
    break;
194
0
  }
195
0
}
196
197
IWORKXMLContextPtr_t TransitionStyleElement::element(const int /*name*/)
198
0
{
199
0
  ETONYEK_DEBUG_MSG(("TransitionStyleElement::element[KEY1Parser.cpp]: unknown element\n"));
200
0
  return IWORKXMLContextPtr_t();
201
0
}
202
}
203
204
namespace
205
{
206
struct BulletStyle
207
{
208
  BulletStyle()
209
0
    : m_relative(true)
210
0
    , m_size()
211
0
  {
212
0
  }
213
  bool m_relative;
214
  boost::optional<double> m_size;
215
};
216
}
217
218
namespace
219
{
220
221
class BulletCharacterStyleElement : public KEY1XMLElementContextBase
222
{
223
public:
224
  explicit BulletCharacterStyleElement(KEY1ParserState &state);
225
226
private:
227
  void attribute(int name, const char *value) override;
228
  IWORKXMLContextPtr_t element(int name) override;
229
230
private:
231
  BulletStyle m_bulletStyle;
232
};
233
234
BulletCharacterStyleElement::BulletCharacterStyleElement(KEY1ParserState &state)
235
0
  : KEY1XMLElementContextBase(state)
236
0
  , m_bulletStyle()
237
0
{
238
0
}
239
240
void BulletCharacterStyleElement::attribute(const int name, const char *const value)
241
0
{
242
0
  switch (name)
243
0
  {
244
0
  case KEY1Token::size_technique :
245
0
    switch (getState().getTokenizer().getId(value))
246
0
    {
247
0
    case KEY1Token::relative :
248
0
      m_bulletStyle.m_relative=true;
249
0
      break;
250
0
    default :
251
0
      ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::attribute[KEY1Parser.cpp]: unexpected size technique %s\n", value));
252
0
      break;
253
0
    }
254
0
    break;
255
0
  case KEY1Token::size :
256
0
    m_bulletStyle.m_size=try_double_cast(value);
257
0
    break;
258
0
  default :
259
0
    ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
260
0
    break;
261
0
  }
262
0
}
263
264
IWORKXMLContextPtr_t BulletCharacterStyleElement::element(const int name)
265
0
{
266
0
  switch (name)
267
0
  {
268
0
  case +KEY1Token::bullet_characters | KEY1Token::NS_URI_KEY : // README
269
0
    break;
270
0
  default :
271
0
    ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::element[KEY1Parser.cpp]: unknown element\n"));
272
0
    break;
273
0
  }
274
275
0
  return IWORKXMLContextPtr_t();
276
0
}
277
}
278
279
namespace
280
{
281
282
class BulletElement : public KEY1XMLElementContextBase
283
{
284
public:
285
  explicit BulletElement(KEY1ParserState &state);
286
287
private:
288
  void attribute(int name, const char *value) override;
289
  IWORKXMLContextPtr_t element(int name) override;
290
  void endOfElement() override;
291
292
  void ensureOpened();
293
294
private:
295
  KEY1Bullet m_bullet;
296
  bool m_opened;
297
};
298
299
BulletElement::BulletElement(KEY1ParserState &state)
300
0
  : KEY1XMLElementContextBase(state)
301
0
  , m_bullet()
302
0
  , m_opened(false)
303
0
{
304
0
}
305
306
void BulletElement::attribute(const int name, const char *const value)
307
0
{
308
0
  switch (name)
309
0
  {
310
0
  case KEY1Token::level :
311
0
    m_bullet.m_level=try_int_cast(value);
312
0
    break;
313
0
  case KEY1Token::marker_type :
314
0
    switch (getState().getTokenizer().getId(value))
315
0
    {
316
0
    case KEY1Token::none :
317
0
      m_bullet.m_type=KEY1_BULLETTYPE_NONE;
318
0
      break;
319
0
    case KEY1Token::character :
320
0
      m_bullet.m_type=KEY1_BULLETTYPE_CHARACTER;
321
0
      break;
322
0
    case KEY1Token::image :
323
0
      m_bullet.m_type=KEY1_BULLETTYPE_IMAGE;
324
0
      break;
325
0
    case KEY1Token::inherited :
326
0
      m_bullet.m_type=KEY1_BULLETTYPE_INHERITED;
327
0
      break;
328
0
    case KEY1Token::sequence :
329
0
      m_bullet.m_type=KEY1_BULLETTYPE_SEQUENCE;
330
0
      break;
331
0
    default :
332
0
      ETONYEK_DEBUG_MSG(("BulletElement::attribute[KEY1Parser.cpp]: unexpected type %s\n", value));
333
0
      break;
334
0
    }
335
0
    break;
336
0
  case KEY1Token::spacing :
337
0
    m_bullet.m_spacing=try_double_cast(value);
338
0
    break;
339
0
  default :
340
0
    ETONYEK_DEBUG_MSG(("BulletElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
341
0
    break;
342
0
  }
343
0
}
344
345
IWORKXMLContextPtr_t BulletElement::element(const int name)
346
0
{
347
0
  ensureOpened();
348
0
  switch (name)
349
0
  {
350
0
  case +KEY1Token::character_bullet_style | KEY1Token::NS_URI_KEY :
351
0
    return std::make_shared<BulletCharacterStyleElement>(getState());
352
0
  case +KEY1Token::image_bullet_style | KEY1Token::NS_URI_KEY : // README
353
0
  case +KEY1Token::sequence_bullet_style | KEY1Token::NS_URI_KEY : // README
354
0
    break;
355
0
  case +KEY1Token::content | KEY1Token::NS_URI_KEY :
356
0
    return std::make_shared<KEY1ContentElement>(getState());
357
0
  default :
358
0
    ETONYEK_DEBUG_MSG(("BulletElement::element[KEY1Parser.cpp]: unknown element\n"));
359
0
    break;
360
0
  }
361
362
0
  return IWORKXMLContextPtr_t();
363
0
}
364
365
void BulletElement::endOfElement()
366
0
{
367
0
  if (!m_opened) return;
368
0
  getState().closeBullet();
369
0
  m_opened=false;
370
0
}
371
372
void BulletElement::ensureOpened()
373
0
{
374
0
  if (m_opened) return;
375
0
  getState().openBullet(m_bullet);
376
0
  m_opened=true;
377
0
}
378
379
}
380
381
namespace
382
{
383
384
class BulletsElement : public KEY1XMLElementContextBase
385
{
386
public:
387
  explicit BulletsElement(KEY1ParserState &state, bool prototype);
388
389
private:
390
  void startOfElement() override;
391
  IWORKXMLContextPtr_t element(int name) override;
392
  void endOfElement() override;
393
394
private:
395
  bool m_prototype;
396
};
397
398
BulletsElement::BulletsElement(KEY1ParserState &state, bool prototype)
399
0
  : KEY1XMLElementContextBase(state)
400
0
  , m_prototype(prototype)
401
0
{
402
0
}
403
404
void BulletsElement::startOfElement()
405
0
{
406
0
  getState().pushIsPrototype(m_prototype);
407
0
  getState().openBullets();
408
0
}
409
410
IWORKXMLContextPtr_t BulletsElement::element(const int name)
411
0
{
412
0
  switch (name)
413
0
  {
414
0
  case +KEY1Token::bullet | KEY1Token::NS_URI_KEY :
415
0
    return std::make_shared<BulletElement>(getState());
416
0
  default :
417
0
    ETONYEK_DEBUG_MSG(("BulletsElement::element[KEY1Parser.cpp]: unknown element\n"));
418
0
    break;
419
0
  }
420
421
0
  return IWORKXMLContextPtr_t();
422
0
}
423
424
void BulletsElement::endOfElement()
425
0
{
426
0
  getState().closeBullets();
427
0
  getState().popIsPrototype();
428
0
}
429
430
}
431
432
namespace
433
{
434
435
class BasicShapeElement : public KEY1XMLElementContextBase
436
{
437
public:
438
  explicit BasicShapeElement(KEY1ParserState &state);
439
440
protected:
441
  void attribute(int name, const char *value) override;
442
  void startOfElement() override;
443
  IWORKXMLContextPtr_t element(int name) override;
444
  void endOfElement() override;
445
446
  IWORKStylePtr_t getStyle() const
447
0
  {
448
0
    return m_style;
449
0
  }
450
private:
451
  IWORKStylePtr_t m_style;
452
  boost::optional<IWORKColor> m_strokeColor;
453
  boost::optional<double> m_strokeWidth;
454
  boost::optional<double> m_opacity;
455
};
456
457
BasicShapeElement::BasicShapeElement(KEY1ParserState &state)
458
0
  : KEY1XMLElementContextBase(state)
459
0
  , m_style()
460
0
  , m_strokeColor()
461
0
  , m_strokeWidth()
462
0
  , m_opacity()
463
0
{
464
0
}
465
466
void BasicShapeElement::attribute(const int name, const char *const value)
467
0
{
468
0
  switch (name)
469
0
  {
470
0
  case KEY1Token::id :
471
0
    setId(value);
472
0
    break;
473
0
  case KEY1Token::opacity :
474
0
    m_opacity=try_double_cast(value);
475
0
    break;
476
0
  case KEY1Token::stroke_color :
477
0
    m_strokeColor=KEY1StringConverter<IWORKColor>::convert(value);
478
0
    break;
479
0
  case KEY1Token::stroke_width :
480
0
    m_strokeWidth=try_double_cast(value);
481
0
    break;
482
0
  default :
483
0
    ETONYEK_DEBUG_MSG(("BasicShapeElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
484
0
    break;
485
0
  }
486
0
}
487
488
void BasicShapeElement::startOfElement()
489
0
{
490
0
}
491
492
IWORKXMLContextPtr_t BasicShapeElement::element(const int name)
493
0
{
494
0
  switch (name)
495
0
  {
496
0
  case +KEY1Token::styles | KEY1Token::NS_URI_KEY :
497
0
    return std::make_shared<KEY1StylesContext>(getState(), m_style, IWORKStylePtr_t());
498
0
  default :
499
0
    ETONYEK_DEBUG_MSG(("BasicShapeElement::element[KEY1Parser.cpp]: unknown element\n"));
500
0
    break;
501
0
  }
502
0
  return IWORKXMLContextPtr_t();
503
0
}
504
505
void BasicShapeElement::endOfElement()
506
0
{
507
0
  if (getState().m_isPrototype&& (!m_strokeColor && !m_strokeWidth && !m_opacity))
508
0
    return;
509
0
  if (!m_style)
510
0
    m_style = std::make_shared<IWORKStyle>(IWORKPropertyMap(), boost::none, IWORKStylePtr_t());
511
0
  if (m_opacity)
512
0
    m_style->getPropertyMap().put<property::Opacity>(get(m_opacity));
513
0
  if (m_strokeColor || m_strokeWidth)
514
0
  {
515
0
    IWORKStroke stroke;
516
0
    if (m_style->has<property::Stroke>())
517
0
      stroke=m_style->get<property::Stroke>();
518
0
    else
519
0
      stroke.m_pattern.m_type = IWORK_STROKE_TYPE_SOLID;
520
0
    if (m_strokeColor) stroke.m_color=get(m_strokeColor);
521
0
    if (m_strokeWidth) stroke.m_width=get(m_strokeWidth);
522
0
    m_style->getPropertyMap().put<property::Stroke>(stroke);
523
0
  }
524
0
}
525
526
}
527
528
namespace
529
{
530
531
class ImageElement : public BasicShapeElement
532
{
533
public:
534
  explicit ImageElement(KEY1ParserState &state);
535
536
private:
537
  void attribute(int name, const char *value) override;
538
  void startOfElement() override;
539
  void endOfElement() override;
540
private:
541
  boost::optional<std::string> m_displayName;
542
  boost::optional<std::string> m_imageName;
543
  bool m_lockAspectRatio;
544
  bool m_locked;
545
  boost::optional<IWORKSize> m_naturalSize;
546
  boost::optional<glm::dmat3> m_transformation;
547
};
548
549
ImageElement::ImageElement(KEY1ParserState &state)
550
0
  : BasicShapeElement(state)
551
0
  , m_displayName()
552
0
  , m_imageName()
553
0
  , m_lockAspectRatio(false)
554
0
  , m_locked(false)
555
0
  , m_naturalSize()
556
0
  , m_transformation()
557
0
{
558
0
}
559
560
void ImageElement::attribute(const int name, const char *const value)
561
0
{
562
0
  switch (name)
563
0
  {
564
0
  case KEY1Token::display_name :
565
0
    m_displayName=value;
566
0
    break;
567
0
  case KEY1Token::image_data :
568
0
    m_imageName=value;
569
0
    break;
570
0
  case KEY1Token::locked :
571
0
    m_locked = bool_cast(value);
572
0
    break;
573
0
  case KEY1Token::lock_aspect_ratio :
574
0
    m_lockAspectRatio = bool_cast(value);
575
0
    break;
576
0
  case KEY1Token::natural_size :
577
0
    m_naturalSize = KEY1StringConverter<IWORKSize>::convert(value);
578
0
    break;
579
0
  case KEY1Token::transformation :
580
0
    m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
581
0
    break;
582
0
  case KEY1Token::byte_size : // the image size
583
0
    break;
584
0
  default :
585
0
    BasicShapeElement::attribute(name,value);
586
0
    break;
587
0
  }
588
0
}
589
590
void ImageElement::startOfElement()
591
0
{
592
0
  BasicShapeElement::startOfElement();
593
0
  if (!getState().m_isPrototype&& isCollector())
594
0
    getCollector().startLevel();
595
0
}
596
597
void ImageElement::endOfElement()
598
0
{
599
0
  BasicShapeElement::endOfElement();
600
0
  IWORKMediaContentPtr_t content;
601
602
0
  if (m_imageName)
603
0
  {
604
0
    content = std::make_shared<IWORKMediaContent>();
605
0
    content->m_data = std::make_shared<IWORKData>();
606
0
    content->m_data->m_stream.reset(getState().getParser().getPackage()->getSubStreamByName(get(m_imageName).c_str()));
607
0
    content->m_size=m_naturalSize;
608
0
  }
609
0
  IWORKGeometryPtr_t geometry;
610
0
  if (m_transformation && m_naturalSize)
611
0
  {
612
0
    geometry = std::make_shared<IWORKGeometry>();
613
0
    glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
614
0
    geometry->m_position=IWORKPosition(pos[0],pos[1]);
615
0
    glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_naturalSize).m_width,get(m_naturalSize).m_height,0);
616
0
    geometry->m_size=IWORKSize(dim[0],dim[1]);
617
0
  }
618
0
  if (getId() && content)
619
0
    getState().getDictionary().m_images[get(getId())]=content;
620
621
0
  IWORKStylePtr_t style=getStyle();
622
0
  getState().getDictionary().storeImageStyle(style, getState().m_isPrototype);
623
0
  if (!getState().m_isPrototype&& isCollector())
624
0
  {
625
0
    if (geometry && content)
626
0
    {
627
0
      getCollector().collectGeometry(geometry);
628
0
      getCollector().setGraphicStyle(style);
629
0
      getCollector().collectImage(content, IWORKGeometryPtr_t(), boost::none, m_locked);
630
0
    }
631
0
    getCollector().endLevel();
632
0
  }
633
0
}
634
}
635
636
namespace
637
{
638
639
class LineElement : public BasicShapeElement
640
{
641
public:
642
  explicit LineElement(KEY1ParserState &state);
643
644
private:
645
  void attribute(int name, const char *value) override;
646
  void startOfElement() override;
647
  void endOfElement() override;
648
private:
649
  boost::optional<IWORKPosition> m_head;
650
  boost::optional<IWORKPosition> m_tail;
651
};
652
653
LineElement::LineElement(KEY1ParserState &state)
654
0
  : BasicShapeElement(state)
655
0
  , m_head()
656
0
  , m_tail()
657
0
{
658
0
}
659
660
void LineElement::attribute(const int name, const char *const value)
661
0
{
662
0
  switch (name)
663
0
  {
664
0
  case KEY1Token::head :
665
0
    m_head=KEY1StringConverter<IWORKPosition>::convert(value);
666
0
    break;
667
0
  case KEY1Token::tail :
668
0
    m_tail=KEY1StringConverter<IWORKPosition>::convert(value);
669
0
    break;
670
0
  default :
671
0
    BasicShapeElement::attribute(name,value);
672
0
    break;
673
0
  }
674
0
}
675
676
void LineElement::startOfElement()
677
0
{
678
0
  BasicShapeElement::startOfElement();
679
0
  if (!getState().m_isPrototype&& isCollector())
680
0
    getCollector().startLevel();
681
0
}
682
683
void LineElement::endOfElement()
684
0
{
685
0
  BasicShapeElement::endOfElement();
686
0
  IWORKLinePtr_t line(new IWORKLine());
687
0
  if (m_tail)
688
0
  {
689
0
    line->m_x1 = get(m_tail).m_x;
690
0
    line->m_y1 = get(m_tail).m_y;
691
0
  }
692
0
  if (m_head)
693
0
  {
694
0
    line->m_x2 = get(m_head).m_x;
695
0
    line->m_y2 = get(m_head).m_y;
696
0
  }
697
0
  IWORKStylePtr_t style=getStyle();
698
0
  getState().getDictionary().storeLineStyle(style, getState().m_isPrototype);
699
0
  if (!getState().m_isPrototype&& isCollector())
700
0
  {
701
0
    getCollector().setGraphicStyle(style);
702
0
    getCollector().collectLine(line);
703
0
    getCollector().endLevel();
704
0
  }
705
0
}
706
}
707
708
namespace
709
{
710
711
class ShapeElement : public BasicShapeElement
712
{
713
public:
714
  explicit ShapeElement(KEY1ParserState &state);
715
716
private:
717
  void attribute(int name, const char *value) override;
718
  void startOfElement() override;
719
  void endOfElement() override;
720
private:
721
  IWORKPathPtr_t m_path;
722
  boost::optional<glm::dmat3> m_transformation;
723
};
724
725
ShapeElement::ShapeElement(KEY1ParserState &state)
726
0
  : BasicShapeElement(state)
727
0
  , m_path()
728
0
  , m_transformation()
729
0
{
730
0
}
731
732
void ShapeElement::attribute(const int name, const char *const value)
733
0
{
734
0
  switch (name)
735
0
  {
736
0
  case KEY1Token::path :
737
0
    try
738
0
    {
739
0
      m_path = std::make_shared<IWORKPath>(value);
740
0
    }
741
0
    catch (const IWORKPath::InvalidException &)
742
0
    {
743
0
      ETONYEK_DEBUG_MSG(("ShapeElement::attribute[KEY1Parser.cpp]: '%s' is not a valid path\n", value));
744
0
    }
745
0
    break;
746
0
  case KEY1Token::transformation :
747
0
    m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
748
0
    break;
749
0
  default :
750
0
    BasicShapeElement::attribute(name, value);
751
0
    break;
752
0
  }
753
0
}
754
755
void ShapeElement::startOfElement()
756
0
{
757
0
  BasicShapeElement::startOfElement();
758
0
  if (!getState().m_isPrototype&& isCollector())
759
0
    getCollector().startLevel();
760
0
}
761
762
void ShapeElement::endOfElement()
763
0
{
764
0
  BasicShapeElement::endOfElement();
765
0
  IWORKStylePtr_t style=getStyle();
766
0
  getState().getDictionary().storeShapeStyle(style, getState().m_isPrototype);
767
0
  if (!getState().m_isPrototype&& isCollector())
768
0
  {
769
0
    if (m_path)
770
0
    {
771
0
      getCollector().setGraphicStyle(style);
772
0
      if (m_transformation)
773
0
        *m_path *= get(m_transformation);
774
0
      getCollector().collectBezier(m_path);
775
0
      getCollector().collectShape();
776
0
    }
777
0
    getCollector().endLevel();
778
0
  }
779
0
}
780
}
781
782
namespace
783
{
784
class TextAttributesElement : public KEY1XMLElementContextBase
785
{
786
public:
787
  TextAttributesElement(KEY1ParserState &state, IWORKStylePtr_t &spanStyle, IWORKStylePtr_t &divStyle);
788
789
protected:
790
  void attribute(int name, const char *value) override;
791
  IWORKXMLContextPtr_t element(int name) override;
792
  void endOfElement() override;
793
794
private:
795
  KEY1DivStyle m_divStyle;
796
  KEY1SpanStyle m_spanStyle;
797
798
  IWORKStylePtr_t &m_divStylePtr;
799
  IWORKStylePtr_t &m_spanStylePtr;
800
};
801
802
TextAttributesElement::TextAttributesElement(KEY1ParserState &state, IWORKStylePtr_t &spanStyle, IWORKStylePtr_t &divStyle)
803
0
  : KEY1XMLElementContextBase(state)
804
0
  , m_divStyle(state, IWORKStylePtr_t())
805
0
  , m_spanStyle(state, IWORKStylePtr_t())
806
0
  , m_divStylePtr(divStyle)
807
0
  , m_spanStylePtr(spanStyle)
808
0
{
809
0
}
810
811
void TextAttributesElement::attribute(const int name, const char *const value)
812
0
{
813
0
  if (m_divStyle.readAttribute(name, value) ||
814
0
      m_spanStyle.readAttribute(name, value))
815
0
    return;
816
0
  switch (name)
817
0
  {
818
0
  case KEY1Token::id :
819
0
    setId(value);
820
0
    break;
821
0
  default:
822
0
    ETONYEK_DEBUG_MSG(("TextAttributesElement::attribute[KEY1Parser.cpp] attribute with value=%s\n", value));
823
0
  }
824
0
}
825
826
IWORKXMLContextPtr_t TextAttributesElement::element(const int name)
827
0
{
828
0
  switch (name)
829
0
  {
830
0
  default:
831
0
    ETONYEK_DEBUG_MSG(("TextAttributesElement::element[KEY1Parser.cpp]: unknown element\n"));
832
0
  }
833
0
  return IWORKXMLContextPtr_t();
834
0
}
835
836
void TextAttributesElement::endOfElement()
837
0
{
838
0
  m_divStylePtr = m_divStyle.getStyle();
839
0
  m_spanStylePtr = m_spanStyle.getStyle();
840
0
}
841
842
}
843
844
namespace
845
{
846
class PlaceholderElement : public BasicShapeElement
847
{
848
public:
849
  explicit PlaceholderElement(KEY1ParserState &state);
850
851
  KEYPlaceholderPtr_t getPlaceholder();
852
853
protected:
854
  void attribute(int name, const char *value) override;
855
  IWORKXMLContextPtr_t element(int name) override;
856
857
private:
858
  boost::optional<IWORKPosition> m_location;
859
  boost::optional<IWORKSize> m_size;
860
  IWORKStylePtr_t m_paragraphStyle;
861
  IWORKStylePtr_t m_spanStyle;
862
  boost::optional<IWORKVerticalAlignment> m_verticalAlignment;
863
  boost::optional<bool> m_visible;
864
};
865
866
PlaceholderElement::PlaceholderElement(KEY1ParserState &state)
867
0
  : BasicShapeElement(state)
868
0
  , m_location()
869
0
  , m_size()
870
0
  , m_paragraphStyle()
871
0
  , m_spanStyle()
872
0
  , m_verticalAlignment()
873
0
  , m_visible()
874
0
{
875
0
}
876
877
void PlaceholderElement::attribute(const int name, const char *const value)
878
0
{
879
0
  switch (name)
880
0
  {
881
0
  case KEY1Token::location :
882
0
    m_location=KEY1StringConverter<IWORKPosition>::convert(value);
883
0
    break;
884
0
  case KEY1Token::size :
885
0
    m_size=KEY1StringConverter<IWORKSize>::convert(value);
886
0
    break;
887
0
  case KEY1Token::vertical_alignment :
888
0
    switch (getState().getTokenizer().getId(value))
889
0
    {
890
0
    case KEY1Token::bottom :
891
0
      m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_BOTTOM;
892
0
      break;
893
0
    case KEY1Token::middle :
894
0
      m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_MIDDLE;
895
0
      break;
896
0
    case KEY1Token::top :
897
0
      m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_TOP;
898
0
      break;
899
0
    case KEY1Token::tracks_master :
900
0
      break;
901
0
    default :
902
0
      ETONYEK_DEBUG_MSG(("PlaceHolderElement::attribute[KEY1Parser.cpp]: unexpected vertical align %s\n", value));
903
0
      break;
904
0
    }
905
0
    break;
906
0
  case KEY1Token::visibility :
907
0
    switch (getState().getTokenizer().getId(value))
908
0
    {
909
0
    case KEY1Token::hidden :
910
0
      m_visible = false;
911
0
      break;
912
0
    case KEY1Token::visible :
913
0
      m_visible = true;
914
0
      break;
915
0
    case KEY1Token::tracks_master :
916
0
      break;
917
0
    default :
918
0
      ETONYEK_DEBUG_MSG(("PlaceHolderElement::attribute[KEY1Parser.cpp]: unexpected visibily align %s\n", value));
919
0
      break;
920
0
    }
921
0
    break;
922
0
  default :
923
0
    BasicShapeElement::attribute(name, value);
924
0
    break;
925
0
  }
926
0
}
927
928
IWORKXMLContextPtr_t PlaceholderElement::element(const int name)
929
0
{
930
0
  switch (name)
931
0
  {
932
0
  case +KEY1Token::text_attributes | KEY1Token::NS_URI_KEY :
933
0
    return std::make_shared<TextAttributesElement>(getState(), m_spanStyle, m_paragraphStyle);
934
0
  default:
935
0
    break;
936
0
  }
937
0
  return BasicShapeElement::element(name);
938
0
}
939
940
KEYPlaceholderPtr_t PlaceholderElement::getPlaceholder()
941
0
{
942
0
  KEYPlaceholderPtr_t res(new KEYPlaceholder);
943
0
  res->m_style = getStyle();
944
0
  res->m_paragraphStyle = m_paragraphStyle;
945
0
  res->m_spanStyle = m_spanStyle;
946
0
  if (m_location && m_size)
947
0
  {
948
0
    IWORKGeometryPtr_t geometry(new IWORKGeometry);
949
0
    geometry->m_position=get(m_location);
950
0
    geometry->m_naturalSize=geometry->m_size=get(m_size);
951
0
    res->m_geometry=geometry;
952
0
  }
953
0
  res->m_visible=m_visible;
954
955
0
  return res;
956
0
}
957
958
}
959
960
namespace
961
{
962
class BodyElement : public PlaceholderElement
963
{
964
public:
965
  explicit BodyElement(KEY1ParserState &state);
966
967
private:
968
  void attribute(int name, const char *value) override;
969
  void endOfElement() override;
970
private:
971
  std::deque<double> m_indents;
972
};
973
974
BodyElement::BodyElement(KEY1ParserState &state)
975
0
  : PlaceholderElement(state)
976
0
  , m_indents()
977
0
{
978
0
}
979
980
void BodyElement::attribute(const int name, const char *const value)
981
0
{
982
0
  switch (name)
983
0
  {
984
0
  case KEY1Token::bullet_indentation :
985
0
  {
986
0
    std::string val(value);
987
0
    std::string::const_iterator it(val.begin()), end(val.end());
988
989
0
    namespace ascii = boost::spirit::ascii;
990
0
    namespace qi =  boost::spirit::qi;
991
0
    if (qi::phrase_parse(it, end, qi::double_ >> *(qi::double_), ascii::space, m_indents) && it==end)
992
0
      ;
993
0
    else
994
0
    {
995
0
      ETONYEK_DEBUG_MSG(("BodyElement::attribute[KEY1Parser.cpp]: unexpected bullet indentation %s\n", value));
996
0
    }
997
0
    break;
998
0
  }
999
0
  default :
1000
0
    PlaceholderElement::attribute(name, value);
1001
0
  }
1002
0
}
1003
1004
void BodyElement::endOfElement()
1005
0
{
1006
0
  KEYPlaceholderPtr_t placeHolder=getPlaceholder();
1007
0
  if (!placeHolder) return;
1008
0
  placeHolder->m_bulletIndentations=m_indents;
1009
0
  getState().getDictionary().storeBodyPlaceholder(placeHolder);
1010
0
}
1011
}
1012
1013
namespace
1014
{
1015
class PageNumberElement : public PlaceholderElement
1016
{
1017
public:
1018
  explicit PageNumberElement(KEY1ParserState &state);
1019
1020
private:
1021
  void endOfElement() override;
1022
private:
1023
};
1024
1025
PageNumberElement::PageNumberElement(KEY1ParserState &state)
1026
0
  : PlaceholderElement(state)
1027
0
{
1028
0
}
1029
1030
void PageNumberElement::endOfElement()
1031
0
{
1032
0
  getState().getDictionary().storePageNumberPlaceholder(getPlaceholder());
1033
0
}
1034
}
1035
1036
namespace
1037
{
1038
class TitleElement : public PlaceholderElement
1039
{
1040
public:
1041
  explicit TitleElement(KEY1ParserState &state);
1042
1043
private:
1044
  void endOfElement() override;
1045
private:
1046
};
1047
1048
TitleElement::TitleElement(KEY1ParserState &state)
1049
0
  : PlaceholderElement(state)
1050
0
{
1051
0
}
1052
1053
void TitleElement::endOfElement()
1054
0
{
1055
0
  getState().getDictionary().storeTitlePlaceholder(getPlaceholder());
1056
0
}
1057
}
1058
1059
namespace
1060
{
1061
1062
class TextboxElement : public BasicShapeElement
1063
{
1064
public:
1065
  explicit TextboxElement(KEY1ParserState &state);
1066
1067
private:
1068
  void attribute(int name, const char *value) override;
1069
  void startOfElement() override;
1070
  IWORKXMLContextPtr_t element(int name) override;
1071
  void endOfElement() override;
1072
private:
1073
  boost::optional<IWORKSize> m_size;
1074
  boost::optional<glm::dmat3> m_transformation;
1075
  boost::optional<bool> m_growHorizontally;
1076
};
1077
1078
TextboxElement::TextboxElement(KEY1ParserState &state)
1079
0
  : BasicShapeElement(state)
1080
0
  , m_size()
1081
0
  , m_transformation()
1082
0
  , m_growHorizontally()
1083
0
{
1084
0
}
1085
1086
void TextboxElement::attribute(const int name, const char *const value)
1087
0
{
1088
0
  switch (name)
1089
0
  {
1090
0
  case KEY1Token::grow_horizontally :
1091
0
    m_growHorizontally = try_bool_cast(value);
1092
0
    break;
1093
0
  case KEY1Token::size :
1094
0
    m_size=KEY1StringConverter<IWORKSize>::convert(value);
1095
0
    break;
1096
0
  case KEY1Token::transformation :
1097
0
    m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1098
0
    break;
1099
0
  default :
1100
0
    BasicShapeElement::attribute(name, value);
1101
0
    break;
1102
0
  }
1103
0
}
1104
1105
void TextboxElement::startOfElement()
1106
0
{
1107
0
  BasicShapeElement::startOfElement();
1108
0
  if (!getState().m_isPrototype&& isCollector())
1109
0
  {
1110
0
    getCollector().startLevel();
1111
0
    assert(!getState().m_currentText);
1112
0
    getState().m_currentText = getCollector().createText(getState().m_langManager);
1113
0
  }
1114
0
}
1115
1116
IWORKXMLContextPtr_t TextboxElement::element(const int name)
1117
0
{
1118
0
  switch (name)
1119
0
  {
1120
0
  case +KEY1Token::content | KEY1Token::NS_URI_KEY :
1121
0
    return std::make_shared<KEY1ContentElement>(getState());
1122
0
  default:
1123
0
    break;
1124
0
  }
1125
0
  return BasicShapeElement::element(name);
1126
0
}
1127
1128
void TextboxElement::endOfElement()
1129
0
{
1130
0
  BasicShapeElement::endOfElement();
1131
0
  IWORKStylePtr_t style=getStyle();
1132
0
  getState().getDictionary().storeTextboxStyle(style, getState().m_isPrototype);
1133
0
  if (!getState().m_isPrototype && isCollector())
1134
0
  {
1135
0
    getCollector().setGraphicStyle(style);
1136
0
    if (m_transformation && m_size)
1137
0
    {
1138
0
      IWORKGeometryPtr_t geometry(new IWORKGeometry);
1139
0
      glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
1140
0
      geometry->m_position=IWORKPosition(pos[0],pos[1]);
1141
0
      glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_size).m_width,get(m_size).m_height,0);
1142
0
      geometry->m_naturalSize=geometry->m_size=IWORKSize(dim[0],dim[1]);
1143
0
      getCollector().collectGeometry(geometry);
1144
0
    }
1145
0
    IWORKPathPtr_t path=makeRoundedRectanglePath(/*m_size ? get(m_size) : */IWORKSize(1,1), 0);
1146
0
    getCollector().collectBezier(path);
1147
0
    if (bool(getState().m_currentText) && !getState().m_currentText->empty())
1148
0
      getCollector().collectText(getState().m_currentText);
1149
0
    getState().m_currentText.reset();
1150
0
    getCollector().collectShape();
1151
1152
0
    getCollector().endLevel();
1153
0
  }
1154
0
}
1155
}
1156
1157
namespace
1158
{
1159
1160
class PluginDataElement : public KEY1XMLElementContextBase
1161
{
1162
public:
1163
  PluginDataElement(KEY1ParserState &state, boost::optional<IWORKSize> &size, bool prototype);
1164
1165
protected:
1166
  void attribute(int name, const char *value) override;
1167
  void startOfElement() override;
1168
  IWORKXMLContextPtr_t element(int name) override;
1169
  void endOfElement() override;
1170
1171
private:
1172
  bool m_prototype;
1173
  boost::optional<IWORKSize> &m_size;
1174
};
1175
1176
PluginDataElement::PluginDataElement(KEY1ParserState &state, boost::optional<IWORKSize> &size, bool prototype)
1177
0
  : KEY1XMLElementContextBase(state)
1178
0
  , m_prototype(prototype)
1179
0
  , m_size(size)
1180
0
{
1181
0
}
1182
1183
#ifndef DEBUG
1184
void PluginDataElement::attribute(const int name, const char *const)
1185
#else
1186
void PluginDataElement::attribute(const int name, const char *const value)
1187
#endif
1188
0
{
1189
0
  switch (name)
1190
0
  {
1191
0
  default:
1192
0
    ETONYEK_DEBUG_MSG(("PluginDataElement::attribute[KEY1Parser.cpp]: unknown attribute with value=%s\n", value));
1193
0
  }
1194
0
}
1195
1196
void PluginDataElement::startOfElement()
1197
0
{
1198
0
  getState().pushIsPrototype(m_prototype);
1199
0
}
1200
1201
IWORKXMLContextPtr_t PluginDataElement::element(const int name)
1202
0
{
1203
0
  switch (name)
1204
0
  {
1205
0
  case +KEY1Token::array  | KEY1Token::NS_URI_KEY : // with list of number
1206
0
  case +KEY1Token::chart_prototype  | KEY1Token::NS_URI_KEY :
1207
0
  case +KEY1Token::color  | KEY1Token::NS_URI_KEY :
1208
0
  case +KEY1Token::content  | KEY1Token::NS_URI_KEY :
1209
0
  case +KEY1Token::dict  | KEY1Token::NS_URI_KEY : // with child size, rect, ...
1210
0
  case +KEY1Token::dash_style  | KEY1Token::NS_URI_KEY :
1211
0
  case +KEY1Token::fill_style  | KEY1Token::NS_URI_KEY :
1212
0
  case +KEY1Token::number  | KEY1Token::NS_URI_KEY :
1213
0
  case +KEY1Token::reference  | KEY1Token::NS_URI_KEY : // style reference
1214
0
  case +KEY1Token::string  | KEY1Token::NS_URI_KEY : // with value dictionary, root
1215
0
    break;
1216
0
  case +KEY1Token::table  | KEY1Token::NS_URI_KEY :
1217
0
    return std::make_shared<KEY1TableElement>(getState(), m_size);
1218
0
  default:
1219
0
    ETONYEK_DEBUG_MSG(("PluginDataElement::element[KEY1Parser.cpp]: unknown element\n"));
1220
0
  }
1221
0
  return IWORKXMLContextPtr_t();
1222
0
}
1223
1224
void PluginDataElement::endOfElement()
1225
0
{
1226
0
  getState().popIsPrototype();
1227
0
}
1228
1229
}
1230
1231
namespace
1232
{
1233
1234
class PluginElement : public BasicShapeElement
1235
{
1236
public:
1237
  explicit PluginElement(KEY1ParserState &state);
1238
1239
protected:
1240
  void attribute(int name, const char *value) override;
1241
  IWORKXMLContextPtr_t element(int name) override;
1242
  void endOfElement() override;
1243
1244
private:
1245
  boost::optional<std::string> m_key;
1246
  boost::optional<glm::dmat3> m_transformation;
1247
  boost::optional<IWORKSize> m_size;
1248
};
1249
1250
PluginElement::PluginElement(KEY1ParserState &state)
1251
0
  : BasicShapeElement(state)
1252
0
  , m_key()
1253
0
  , m_transformation()
1254
0
  , m_size()
1255
0
{
1256
0
}
1257
1258
void PluginElement::attribute(const int name, const char *const value)
1259
0
{
1260
0
  switch (name)
1261
0
  {
1262
0
  case KEY1Token::key :
1263
0
    m_key = value;
1264
0
    break;
1265
0
  case KEY1Token::transformation :
1266
0
    m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1267
0
    break;
1268
0
  default :
1269
0
    BasicShapeElement::attribute(name,value);
1270
0
    break;
1271
0
  }
1272
0
}
1273
1274
IWORKXMLContextPtr_t PluginElement::element(const int name)
1275
0
{
1276
0
  switch (name)
1277
0
  {
1278
0
  case +KEY1Token::plugin_data  | KEY1Token::NS_URI_KEY :
1279
0
    return std::make_shared<PluginDataElement>(getState(), m_size, false);
1280
0
  case +KEY1Token::prototype_data  | KEY1Token::NS_URI_KEY :
1281
0
    return std::make_shared<PluginDataElement>(getState(), m_size, true);
1282
0
  default :
1283
0
    return BasicShapeElement::element(name);
1284
0
  }
1285
0
}
1286
1287
void PluginElement::endOfElement()
1288
0
{
1289
0
  if (!isCollector())
1290
0
    return;
1291
0
  IWORKStylePtr_t style=getStyle();
1292
  // CHANGEME: check the plugin-data has created a table, if so, send it
1293
0
  if (getState().m_currentTable)
1294
0
  {
1295
0
    getCollector().setGraphicStyle(style);
1296
0
    if (m_transformation && m_size)
1297
0
    {
1298
0
      IWORKGeometryPtr_t geometry(new IWORKGeometry);
1299
0
      glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
1300
0
      geometry->m_position=IWORKPosition(pos[0],pos[1]);
1301
0
      glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_size).m_width,get(m_size).m_height,0);
1302
0
      geometry->m_naturalSize=geometry->m_size=IWORKSize(dim[0],dim[1]);
1303
0
      getCollector().collectGeometry(geometry);
1304
0
    }
1305
0
    getCollector().collectTable(getState().m_currentTable);
1306
0
    getState().m_currentTable.reset();
1307
0
  }
1308
0
}
1309
1310
}
1311
1312
namespace
1313
{
1314
1315
class GroupElement : public BasicShapeElement
1316
{
1317
public:
1318
  explicit GroupElement(KEY1ParserState &state);
1319
1320
protected:
1321
  void attribute(int name, const char *value) override;
1322
  IWORKXMLContextPtr_t element(int name) override;
1323
1324
private:
1325
  boost::optional<glm::dmat3> m_transformation;
1326
};
1327
1328
GroupElement::GroupElement(KEY1ParserState &state)
1329
0
  : BasicShapeElement(state)
1330
0
  , m_transformation()
1331
0
{
1332
0
}
1333
1334
void GroupElement::attribute(const int name, const char *const value)
1335
0
{
1336
0
  switch (name)
1337
0
  {
1338
0
  case KEY1Token::transformation :
1339
0
    m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1340
0
    break;
1341
0
  default :
1342
0
    BasicShapeElement::attribute(name,value);
1343
0
    break;
1344
0
  }
1345
0
}
1346
1347
IWORKXMLContextPtr_t GroupElement::element(const int name)
1348
0
{
1349
0
  switch (name)
1350
0
  {
1351
0
  case +KEY1Token::g | KEY1Token::NS_URI_KEY :
1352
0
    return std::make_shared<GroupElement>(getState());
1353
0
  case +KEY1Token::image | KEY1Token::NS_URI_KEY :
1354
0
    return std::make_shared<ImageElement>(getState());
1355
0
  case +KEY1Token::line | KEY1Token::NS_URI_KEY :
1356
0
    return std::make_shared<LineElement>(getState());
1357
0
  case +KEY1Token::page_number | KEY1Token::NS_URI_KEY :
1358
0
    return std::make_shared<PageNumberElement>(getState());
1359
0
  case +KEY1Token::plugin | KEY1Token::NS_URI_KEY :
1360
0
    return std::make_shared<PluginElement>(getState());
1361
0
  case +KEY1Token::shape | KEY1Token::NS_URI_KEY :
1362
0
    return std::make_shared<ShapeElement>(getState());
1363
0
  case +KEY1Token::textbox | KEY1Token::NS_URI_KEY :
1364
0
    return std::make_shared<TextboxElement>(getState());
1365
0
  default :
1366
0
    return BasicShapeElement::element(name);
1367
0
  }
1368
0
}
1369
1370
}
1371
1372
namespace
1373
{
1374
1375
class DrawablesElement : public KEY1XMLElementContextBase
1376
{
1377
public:
1378
  explicit DrawablesElement(KEY1ParserState &state, bool prototype);
1379
1380
private:
1381
  void startOfElement() override;
1382
  IWORKXMLContextPtr_t element(int name) override;
1383
  void endOfElement() override;
1384
1385
private:
1386
  bool m_prototype;
1387
};
1388
1389
DrawablesElement::DrawablesElement(KEY1ParserState &state, bool prototype)
1390
0
  : KEY1XMLElementContextBase(state)
1391
0
  , m_prototype(prototype)
1392
0
{
1393
0
}
1394
1395
void DrawablesElement::startOfElement()
1396
0
{
1397
0
  getState().pushIsPrototype(m_prototype);
1398
0
  if (isCollector())
1399
0
    getCollector().startLevel();
1400
0
}
1401
1402
IWORKXMLContextPtr_t DrawablesElement::element(const int name)
1403
0
{
1404
0
  switch (name)
1405
0
  {
1406
0
  case +KEY1Token::body | KEY1Token::NS_URI_KEY :
1407
0
    return std::make_shared<BodyElement>(getState());
1408
0
  case +KEY1Token::g | KEY1Token::NS_URI_KEY :
1409
0
    return std::make_shared<GroupElement>(getState());
1410
0
  case +KEY1Token::image | KEY1Token::NS_URI_KEY :
1411
0
    return std::make_shared<ImageElement>(getState());
1412
0
  case +KEY1Token::line | KEY1Token::NS_URI_KEY :
1413
0
    return std::make_shared<LineElement>(getState());
1414
0
  case +KEY1Token::page_number | KEY1Token::NS_URI_KEY :
1415
0
    return std::make_shared<PageNumberElement>(getState());
1416
0
  case +KEY1Token::plugin | KEY1Token::NS_URI_KEY :
1417
0
    return std::make_shared<PluginElement>(getState());
1418
0
  case +KEY1Token::shape | KEY1Token::NS_URI_KEY :
1419
0
    return std::make_shared<ShapeElement>(getState());
1420
0
  case +KEY1Token::textbox | KEY1Token::NS_URI_KEY :
1421
0
    return std::make_shared<TextboxElement>(getState());
1422
0
  case +KEY1Token::title | KEY1Token::NS_URI_KEY :
1423
0
    return std::make_shared<TitleElement>(getState());
1424
0
  default :
1425
0
    ETONYEK_DEBUG_MSG(("DrawablesElement::element[KEY1Parser.cpp]: unknown element\n"));
1426
0
    break;
1427
0
  }
1428
1429
0
  return IWORKXMLContextPtr_t();
1430
0
}
1431
1432
void DrawablesElement::endOfElement()
1433
0
{
1434
0
  if (isCollector())
1435
0
    getCollector().endLevel();
1436
0
  getState().popIsPrototype();
1437
0
}
1438
1439
}
1440
1441
namespace
1442
{
1443
1444
class PluginsElement : public KEY1XMLElementContextBase
1445
{
1446
public:
1447
  explicit PluginsElement(KEY1ParserState &state, bool prototype);
1448
1449
private:
1450
  void startOfElement() override;
1451
  IWORKXMLContextPtr_t element(int name) override;
1452
  void endOfElement() override;
1453
1454
private:
1455
  bool m_prototype;
1456
};
1457
1458
PluginsElement::PluginsElement(KEY1ParserState &state, bool prototype)
1459
0
  : KEY1XMLElementContextBase(state)
1460
0
  , m_prototype(prototype)
1461
0
{
1462
0
}
1463
1464
void PluginsElement::startOfElement()
1465
0
{
1466
0
  getState().pushIsPrototype(m_prototype);
1467
0
}
1468
1469
IWORKXMLContextPtr_t PluginsElement::element(const int name)
1470
0
{
1471
0
  switch (name)
1472
0
  {
1473
0
  case +KEY1Token::prototype_plugin | KEY1Token::NS_URI_KEY :
1474
0
    return std::make_shared<PluginElement>(getState());
1475
0
  default :
1476
0
    ETONYEK_DEBUG_MSG(("PluginsElement::element[KEY1Parser.cpp]: unknown element\n"));
1477
0
    break;
1478
0
  }
1479
1480
0
  return IWORKXMLContextPtr_t();
1481
0
}
1482
1483
void PluginsElement::endOfElement()
1484
0
{
1485
0
  getState().popIsPrototype();
1486
0
}
1487
}
1488
1489
namespace
1490
{
1491
1492
class SlideElement : public KEY1XMLElementContextBase
1493
{
1494
public:
1495
  explicit SlideElement(KEY1ParserState &state, bool isMasterSlide);
1496
1497
private:
1498
  void attribute(int name, const char *value) override;
1499
  void startOfElement() override;
1500
  IWORKXMLContextPtr_t element(int name) override;
1501
  void endOfElement() override;
1502
1503
private:
1504
  bool m_isMasterSlide;
1505
  optional<ID_t> m_styleRef;
1506
  optional<ID_t> m_masterRef;
1507
1508
  boost::optional<std::string> m_name; // master name
1509
  boost::optional<IWORKFill> m_background;
1510
1511
  // we need to record the layer as the main style are not read
1512
  std::shared_ptr<IWORKRecorder> m_recorder;
1513
  boost::optional<std::string> m_notes;
1514
};
1515
1516
SlideElement::SlideElement(KEY1ParserState &state, bool isMasterSlide)
1517
0
  : KEY1XMLElementContextBase(state)
1518
0
  , m_isMasterSlide(isMasterSlide)
1519
0
  , m_styleRef()
1520
0
  , m_masterRef()
1521
0
  , m_name()
1522
0
  , m_background()
1523
0
  , m_recorder()
1524
0
  , m_notes()
1525
0
{
1526
0
}
1527
1528
1529
void SlideElement::attribute(int name, const char *value)
1530
0
{
1531
0
  switch (name)
1532
0
  {
1533
0
  case KEY1Token::name :
1534
0
    m_name=value;
1535
0
    break;
1536
0
  case KEY1Token::id :
1537
0
    setId(value);
1538
0
    break;
1539
0
  case KEY1Token::master_slide_id :
1540
0
    m_masterRef=value;
1541
0
    break;
1542
0
  case KEY1Token::floating_content : // when exist with value=true, probably meaning has floating content
1543
0
    break;
1544
0
  default :
1545
0
    ETONYEK_DEBUG_MSG(("SlideElement::attribute[KEY1Parser.cpp]: unknown attribute\n"));
1546
0
    break;
1547
0
  }
1548
0
}
1549
1550
void SlideElement::startOfElement()
1551
0
{
1552
0
  getState().pushIsMasterSlide(m_isMasterSlide);
1553
0
  getState().getDictionary().pushStylesContext();
1554
0
  if (isCollector())
1555
0
  {
1556
0
    getCollector().startPage();
1557
0
    getCollector().startLayer();
1558
0
    m_recorder = std::make_shared<IWORKRecorder>();
1559
0
    getCollector().setRecorder(m_recorder);
1560
0
  }
1561
0
}
1562
1563
IWORKXMLContextPtr_t SlideElement::element(const int name)
1564
0
{
1565
0
  switch (name)
1566
0
  {
1567
0
  case +KEY1Token::bullets | KEY1Token::NS_URI_KEY :
1568
0
    return std::make_shared<BulletsElement>(getState(), false);
1569
0
  case +KEY1Token::drawables | KEY1Token::NS_URI_KEY :
1570
0
    return std::make_shared<DrawablesElement>(getState(), false);
1571
0
  case +KEY1Token::guides | KEY1Token::NS_URI_KEY : // list of guide, safe to ignore?
1572
0
    break;
1573
0
  case +KEY1Token::notes | KEY1Token::NS_URI_KEY :
1574
0
    return std::make_shared<CDATAElement>(getState(), m_notes);
1575
0
  case +KEY1Token::prototype_bullets | KEY1Token::NS_URI_KEY :
1576
0
    return std::make_shared<BulletsElement>(getState(), true);
1577
0
  case +KEY1Token::prototype_drawables | KEY1Token::NS_URI_KEY :
1578
0
    return std::make_shared<DrawablesElement>(getState(), true);
1579
0
  case +KEY1Token::prototype_plugins | KEY1Token::NS_URI_KEY :
1580
0
    return std::make_shared<PluginsElement>(getState(), true);
1581
0
  case +KEY1Token::background_fill_style | KEY1Token::NS_URI_KEY :
1582
0
    return std::make_shared<KEY1FillElement>(getState(), m_background);
1583
0
  case +KEY1Token::transition_style | KEY1Token::NS_URI_KEY :
1584
0
    return std::make_shared<TransitionStyleElement>(getState());
1585
0
  case +KEY1Token::thumbnails | KEY1Token::NS_URI_KEY : // ok to ignore
1586
0
    break;
1587
0
  default :
1588
0
    ETONYEK_DEBUG_MSG(("SlideElement::element[KEY1Parser.cpp]: unknown element\n"));
1589
0
    break;
1590
0
  }
1591
1592
0
  return IWORKXMLContextPtr_t();
1593
0
}
1594
1595
void SlideElement::endOfElement()
1596
0
{
1597
0
  getState().getDictionary().linkStylesContext(m_masterRef);
1598
0
  if (m_isMasterSlide && getId()) getState().getDictionary().collectStylesContext(get(getId()));
1599
0
  if (isCollector())
1600
0
  {
1601
0
    if (m_background)
1602
0
    {
1603
0
      IWORKPropertyMap props;
1604
0
      props.put<property::Fill>(get(m_background));
1605
0
      IWORKStylePtr_t style(new IWORKStyle(props, boost::none, boost::none));
1606
1607
0
      getCollector().setSlideStyle(style);
1608
0
    }
1609
0
    if (!m_isMasterSlide)
1610
0
    {
1611
0
      for (int i=0; i<2; ++i)
1612
0
      {
1613
0
        KEYPlaceholderPtr_t placeholder=i==0 ? getState().getDictionary().getTitlePlaceholder() :
1614
0
                                        getState().getDictionary().getBodyPlaceholder();
1615
0
        if (!placeholder || (placeholder->m_visible && !get(placeholder->m_visible)))
1616
0
          continue;
1617
0
        getCollector().insertTextPlaceholder(placeholder);
1618
0
      }
1619
0
    }
1620
0
    const KEYLayerPtr_t layer(getCollector().collectLayer());
1621
0
    getCollector().endLayer();
1622
0
    if (bool(layer))
1623
0
      getCollector().insertLayer(layer);
1624
0
    if (m_notes)
1625
0
    {
1626
0
      assert(!getState().m_currentText);
1627
0
      getState().m_currentText = getCollector().createText(getState().m_langManager);
1628
0
      getState().m_currentText->insertText(get(m_notes).c_str());
1629
0
      getCollector().collectText(getState().m_currentText);
1630
0
      getState().m_currentText.reset();
1631
0
      getCollector().collectNote();
1632
0
    }
1633
0
    KEYSlidePtr_t slide=getCollector().collectSlide();
1634
0
    getCollector().endPage();
1635
0
    if (!slide)
1636
0
      return;
1637
0
    slide->m_name=m_name;
1638
0
    if (m_masterRef && m_isMasterSlide)
1639
0
    {
1640
0
      ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: find a master slide with masterRef\n"));
1641
0
    }
1642
0
    else if (m_masterRef)
1643
0
    {
1644
0
      const KEYSlideMap_t::const_iterator it = getState().getDictionary().m_masterSlides.find(get(m_masterRef));
1645
0
      if (it != getState().getDictionary().m_masterSlides.end())
1646
0
        slide->m_masterSlide=it->second;
1647
0
      else
1648
0
      {
1649
0
        ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: unknown master %s\n", get(m_masterRef).c_str()));
1650
0
      }
1651
0
    }
1652
0
    if (!m_isMasterSlide)
1653
0
      getState().getDictionary().m_slides.push_back(slide);
1654
0
    else if (getId())
1655
0
      getState().getDictionary().m_masterSlides[get(getId())]=slide;
1656
0
    else
1657
0
    {
1658
0
      ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: can not find a master id\n"));
1659
0
    }
1660
0
  }
1661
0
  getState().getDictionary().popStylesContext();
1662
0
  getState().popIsMasterSlide();
1663
0
}
1664
1665
}
1666
1667
namespace
1668
{
1669
1670
class SlideListElement : public KEY1XMLElementContextBase
1671
{
1672
public:
1673
  explicit SlideListElement(KEY1ParserState &state);
1674
1675
private:
1676
  void startOfElement() override;
1677
  IWORKXMLContextPtr_t element(int name) override;
1678
  void endOfElement() override;
1679
};
1680
1681
SlideListElement::SlideListElement(KEY1ParserState &state)
1682
0
  : KEY1XMLElementContextBase(state)
1683
0
{
1684
0
}
1685
1686
void SlideListElement::startOfElement()
1687
0
{
1688
0
  if (isCollector())
1689
0
    getCollector().startSlides();
1690
0
}
1691
1692
IWORKXMLContextPtr_t SlideListElement::element(const int name)
1693
0
{
1694
0
  switch (name)
1695
0
  {
1696
0
  case +KEY1Token::slide | KEY1Token::NS_URI_KEY :
1697
0
    return std::make_shared<SlideElement>(getState(), false);
1698
0
  default :
1699
0
    ETONYEK_DEBUG_MSG(("SlideListElement::element[KEY1Parser.cpp]: unexpected element\n"));
1700
0
    break;
1701
0
  }
1702
1703
0
  return IWORKXMLContextPtr_t();
1704
0
}
1705
1706
void SlideListElement::endOfElement()
1707
0
{
1708
0
  if (isCollector())
1709
0
    getCollector().endSlides();
1710
0
}
1711
1712
}
1713
1714
namespace
1715
{
1716
1717
class MasterSlidesElement : public KEY1XMLElementContextBase
1718
{
1719
public:
1720
  explicit MasterSlidesElement(KEY1ParserState &state);
1721
1722
private:
1723
  void startOfElement() override;
1724
  IWORKXMLContextPtr_t element(int name) override;
1725
  void endOfElement() override;
1726
};
1727
1728
MasterSlidesElement::MasterSlidesElement(KEY1ParserState &state)
1729
0
  : KEY1XMLElementContextBase(state)
1730
0
{
1731
0
}
1732
1733
void MasterSlidesElement::startOfElement()
1734
0
{
1735
0
  if (isCollector())
1736
0
    getCollector().startSlides();
1737
0
}
1738
1739
IWORKXMLContextPtr_t MasterSlidesElement::element(const int name)
1740
0
{
1741
0
  switch (name)
1742
0
  {
1743
0
  case +KEY1Token::master_slide | KEY1Token::NS_URI_KEY :
1744
0
    return std::make_shared<SlideElement>(getState(), true);
1745
0
  default :
1746
0
    ETONYEK_DEBUG_MSG(("MasterSlidesElement::element[KEY1Parser.cpp]: unexpected element\n"));
1747
0
    break;
1748
0
  }
1749
1750
0
  return IWORKXMLContextPtr_t();
1751
0
}
1752
1753
void MasterSlidesElement::endOfElement()
1754
0
{
1755
0
  if (isCollector())
1756
0
    getCollector().endSlides();
1757
0
}
1758
}
1759
1760
namespace
1761
{
1762
class ThemeElement : public KEY1XMLElementContextBase
1763
{
1764
public:
1765
  explicit ThemeElement(KEY1ParserState &state);
1766
1767
private:
1768
  void attribute(int name, const char *value) override;
1769
  IWORKXMLContextPtr_t element(int name) override;
1770
1771
private:
1772
  boost::optional<std::string> m_description;
1773
};
1774
1775
ThemeElement::ThemeElement(KEY1ParserState &state)
1776
0
  : KEY1XMLElementContextBase(state)
1777
0
  , m_description()
1778
0
{
1779
0
}
1780
1781
void ThemeElement::attribute(int name, const char *value)
1782
0
{
1783
0
  switch (name)
1784
0
  {
1785
0
  case KEY1Token::slide_size :
1786
0
  {
1787
0
    boost::optional<IWORKSize> size=KEY1StringConverter<IWORKSize>::convert(value);
1788
0
    if (size && isCollector())
1789
0
      getCollector().collectPresentationSize(get(size));
1790
0
    break;
1791
0
  }
1792
0
  default :
1793
0
    ETONYEK_DEBUG_MSG(("ThemeElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
1794
0
    break;
1795
0
  }
1796
0
}
1797
1798
IWORKXMLContextPtr_t ThemeElement::element(const int name)
1799
0
{
1800
0
  switch (name)
1801
0
  {
1802
0
  case +KEY1Token::description | KEY1Token::NS_URI_KEY :
1803
0
    return std::make_shared<CDATAElement>(getState(), m_description);
1804
0
  case +KEY1Token::prototype_drawables | KEY1Token::NS_URI_KEY :
1805
0
    return std::make_shared<DrawablesElement>(getState(), true);
1806
0
  case +KEY1Token::prototype_plugins | KEY1Token::NS_URI_KEY :
1807
0
    return std::make_shared<PluginsElement>(getState(), true);
1808
0
  case +KEY1Token::master_slides | KEY1Token::NS_URI_KEY :
1809
0
    return std::make_shared<MasterSlidesElement>(getState());
1810
0
  default :
1811
0
    ETONYEK_DEBUG_MSG(("ThemeElement::element[KEY1Parser.cpp]: unexpected element\n"));
1812
0
    break;
1813
0
  }
1814
1815
0
  return IWORKXMLContextPtr_t();
1816
0
}
1817
}
1818
1819
namespace
1820
{
1821
class PresentationElement : public KEY1XMLElementContextBase
1822
{
1823
public:
1824
  explicit PresentationElement(KEY1ParserState &state);
1825
1826
private:
1827
  void attribute(int name, const char *value) override;
1828
  void startOfElement() override;
1829
  IWORKXMLContextPtr_t element(int name) override;
1830
  void endOfElement() override;
1831
1832
private:
1833
};
1834
1835
PresentationElement::PresentationElement(KEY1ParserState &state)
1836
0
  : KEY1XMLElementContextBase(state)
1837
0
{
1838
0
}
1839
1840
void PresentationElement::startOfElement()
1841
0
{
1842
0
  if (isCollector())
1843
0
  {
1844
0
    getCollector().startDocument();
1845
0
    getCollector().setAccumulateTransformTo(false);
1846
0
  }
1847
0
}
1848
1849
void PresentationElement::attribute(const int name, const char *const /*value*/)
1850
0
{
1851
0
  switch (name)
1852
0
  {
1853
0
  case KEY1Token::version : // find 36
1854
0
    break;
1855
0
  default :
1856
    // normally only the namespace xmlns:plugin
1857
0
    break;
1858
0
  }
1859
0
}
1860
1861
IWORKXMLContextPtr_t PresentationElement::element(const int name)
1862
0
{
1863
0
  switch (name)
1864
0
  {
1865
0
  case +KEY1Token::metadata | KEY1Token::NS_URI_KEY :
1866
0
    return std::make_shared<MetadataElement>(getState());
1867
0
  case +KEY1Token::theme | KEY1Token::NS_URI_KEY :
1868
0
    return std::make_shared<ThemeElement>(getState());
1869
0
  case +KEY1Token::slide_list | KEY1Token::NS_URI_KEY :
1870
0
    return std::make_shared<SlideListElement>(getState());
1871
0
  case +KEY1Token::ui_state | KEY1Token::NS_URI_KEY : // safe to ignore
1872
0
    break;
1873
0
  default :
1874
0
    ETONYEK_DEBUG_MSG(("PresentationElement::element[KEY1Parser.cpp]: unexpected element\n"));
1875
0
    break;
1876
0
  }
1877
1878
0
  return IWORKXMLContextPtr_t();
1879
0
}
1880
1881
void PresentationElement::endOfElement()
1882
0
{
1883
0
  if (isCollector())
1884
0
  {
1885
0
    getCollector().sendSlides(getState().getDictionary().m_slides);
1886
0
    getCollector().endDocument();
1887
0
  }
1888
0
}
1889
1890
}
1891
1892
namespace
1893
{
1894
1895
class XMLDocument : public KEY1XMLElementContextBase
1896
{
1897
public:
1898
  explicit XMLDocument(KEY1ParserState &state);
1899
1900
private:
1901
  IWORKXMLContextPtr_t element(int name) override;
1902
};
1903
1904
XMLDocument::XMLDocument(KEY1ParserState &state)
1905
0
  : KEY1XMLElementContextBase(state)
1906
0
{
1907
0
}
1908
1909
IWORKXMLContextPtr_t XMLDocument::element(const int name)
1910
0
{
1911
0
  switch (name)
1912
0
  {
1913
0
  case +KEY1Token::presentation | KEY1Token::NS_URI_KEY :
1914
0
    return std::make_shared<PresentationElement>(m_state);
1915
0
  default:
1916
0
    ETONYEK_DEBUG_MSG(("XMLDocument::element[KEY1Parser.cpp]: unexpected element\n"));
1917
0
    break;
1918
0
  }
1919
1920
0
  return IWORKXMLContextPtr_t();
1921
0
}
1922
1923
}
1924
1925
namespace
1926
{
1927
1928
class DiscardContext : public KEY1XMLContextBase<IWORKDiscardContext>
1929
{
1930
public:
1931
  explicit DiscardContext(KEY1ParserState &state);
1932
  ~DiscardContext();
1933
1934
private:
1935
  IWORKXMLContextPtr_t element(int name) override;
1936
1937
};
1938
1939
DiscardContext::DiscardContext(KEY1ParserState &state)
1940
0
  : KEY1XMLContextBase<IWORKDiscardContext>(state)
1941
0
{
1942
0
}
1943
1944
DiscardContext::~DiscardContext()
1945
{
1946
}
1947
1948
IWORKXMLContextPtr_t DiscardContext::element(const int name)
1949
0
{
1950
0
  return KEY1XMLContextBase<IWORKDiscardContext>::element(name);
1951
0
}
1952
1953
}
1954
1955
KEY1Parser::KEY1Parser(const RVNGInputStreamPtr_t &input, const RVNGInputStreamPtr_t &package, KEYCollector &collector, KEY1Dictionary &dict)
1956
0
  : IWORKParser(input, package)
1957
0
  , m_state(*this, collector, dict)
1958
0
  , m_data()
1959
0
{
1960
1961
0
}
1962
1963
KEY1Parser::~KEY1Parser()
1964
0
{
1965
0
}
1966
1967
IWORKXMLContextPtr_t KEY1Parser::createDocumentContext()
1968
0
{
1969
0
  return std::make_shared<XMLDocument>(m_state);
1970
0
}
1971
1972
IWORKXMLContextPtr_t KEY1Parser::createDiscardContext()
1973
0
{
1974
0
  return std::make_shared<DiscardContext>(m_state);
1975
0
}
1976
1977
const IWORKTokenizer &KEY1Parser::getTokenizer() const
1978
0
{
1979
0
  return KEY1Token::getTokenizer();
1980
0
}
1981
1982
}
1983
1984
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */