Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/GreatWksGraph.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cmath>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <map>
39
#include <set>
40
#include <sstream>
41
42
#include <librevenge/librevenge.h>
43
44
#include "MWAWFont.hxx"
45
#include "MWAWGraphicEncoder.hxx"
46
#include "MWAWGraphicListener.hxx"
47
#include "MWAWGraphicShape.hxx"
48
#include "MWAWGraphicStyle.hxx"
49
#include "MWAWListener.hxx"
50
#include "MWAWParser.hxx"
51
#include "MWAWPictMac.hxx"
52
#include "MWAWPosition.hxx"
53
#include "MWAWRSRCParser.hxx"
54
#include "MWAWSubDocument.hxx"
55
56
#include "GreatWksDocument.hxx"
57
#include "GreatWksGraph.hxx"
58
59
/** Internal: the structures of a GreatWksGraph */
60
namespace GreatWksGraphInternal
61
{
62
////////////////////////////////////////
63
//! Internal: the graphic zone of a GreatWksGraph
64
struct Frame {
65
  //! the frame type
66
  enum Type { T_BAD, T_BASIC, T_GROUP, T_PICTURE, T_TEXT, T_DBFIELD, T_UNSET };
67
  //! constructor
68
  Frame()
69
349k
    : m_type(-1)
70
349k
    , m_styleId(-1)
71
349k
    , m_parent(0)
72
349k
    , m_order(-1)
73
349k
    , m_dataSize(0)
74
349k
    , m_box()
75
349k
    , m_page(-1)
76
349k
    , m_extra("")
77
349k
    , m_parsed(false)
78
349k
  {
79
349k
  }
80
47.1k
  Frame(Frame const &)=default;
81
  //! destructor
82
  virtual ~Frame();
83
  //! return the frame type
84
  virtual Type getType() const
85
2.17k
  {
86
2.17k
    return T_UNSET;
87
2.17k
  }
88
  //! operator<<
89
  friend std::ostream &operator<<(std::ostream &o, Frame const &zone)
90
0
  {
91
0
    zone.print(o);
92
0
    return o;
93
0
  }
94
  //! a virtual print function
95
  virtual void print(std::ostream &o) const
96
0
  {
97
0
    switch (m_type) {
98
0
    case 1:
99
0
      o << "text,";
100
0
      break;
101
0
    case 2:
102
0
      o << "line,";
103
0
      break;
104
0
    case 3:
105
0
      o << "rect,";
106
0
      break;
107
0
    case 4:
108
0
      o << "roundrect,";
109
0
      break;
110
0
    case 5:
111
0
      o << "oval,";
112
0
      break;
113
0
    case 6:
114
0
      o << "arc,";
115
0
      break;
116
0
    case 7:
117
0
      o << "poly[regular],";
118
0
      break;
119
0
    case 8:
120
0
      o << "poly,";
121
0
      break;
122
0
    case 10:
123
0
      o << "database[field],";
124
0
      break;
125
0
    case 11:
126
0
      o << "picture,";
127
0
      break;
128
0
    case 12:
129
0
      o << "spline,";
130
0
      break;
131
0
    case 15:
132
0
      o << "group,";
133
0
      break;
134
0
    default:
135
0
      o << "type=" << m_type << ",";
136
0
      break;
137
0
    }
138
0
    if (m_styleId >= 0)
139
0
      o << "S" << m_styleId << ",";
140
0
    if (m_order >= 0)
141
0
      o << "order=" << m_order << ",";
142
0
    if (m_parent > 0)
143
0
      o << "F" << m_parent << "[parent],";
144
0
    if (m_dataSize > 0)
145
0
      o << "dataSize=" << m_dataSize << ",";
146
0
    o << "box=" << m_box << ",";
147
0
    if (m_page>0)
148
0
      o << "page=" << m_page << ",";
149
0
    o << m_extra;
150
0
  }
151
  //! the zone type
152
  int m_type;
153
  //! the style identifier
154
  int m_styleId;
155
  //! the parent identifier
156
  int m_parent;
157
  //! the z order
158
  int m_order;
159
  //! the data size ( if know)
160
  long m_dataSize;
161
  //! the zone bdbox
162
  MWAWBox2f m_box;
163
  //! the page
164
  int m_page;
165
  //! extra data
166
  std::string m_extra;
167
  //! true if the frame is send
168
  mutable bool m_parsed;
169
};
170
171
Frame::~Frame()
172
396k
{
173
396k
}
174
175
////////////////////////////////////////
176
//! Internal: a unknown zone of a GreatWksGraph
177
struct FrameBad final : public Frame {
178
  //! constructor
179
151k
  FrameBad() : Frame()
180
151k
  {
181
151k
  }
182
  //! destructor
183
  ~FrameBad() final;
184
  //! return the frame type
185
  Type getType() const final
186
1.54k
  {
187
1.54k
    return T_BAD;
188
1.54k
  }
189
};
190
191
FrameBad::~FrameBad()
192
{
193
}
194
195
////////////////////////////////////////
196
//! Internal: the basic shape of a GreatWksGraph
197
struct FrameShape final : public Frame {
198
  //! constructor
199
  explicit FrameShape(Frame const &frame)
200
13.9k
    : Frame(frame)
201
13.9k
    , m_shape()
202
13.9k
    , m_lineArrow(0)
203
13.9k
    , m_lineFormat(0)
204
13.9k
  {
205
13.9k
  }
206
  //! destructor
207
  ~FrameShape() final;
208
  //! return the frame type
209
  Type getType() const final
210
18.3k
  {
211
18.3k
    return T_BASIC;
212
18.3k
  }
213
  //! print function
214
  void print(std::ostream &o) const final
215
0
  {
216
0
    Frame::print(o);
217
0
    switch (m_lineArrow) {
218
0
    case 0: // unset
219
0
    case 1: // none
220
0
      break;
221
0
    case 2:
222
0
      o << "arrow=\'>\',";
223
0
      break;
224
0
    case 3:
225
0
      o << "arrow=\'<\',";
226
0
      break;
227
0
    case 4:
228
0
      o << "arrow=\'<>\',";
229
0
      break;
230
0
    default:
231
0
      o<< "#arrow=" << m_lineArrow << ",";
232
0
    }
233
0
    if (m_lineFormat)
234
0
      o << "L" << m_lineFormat << ",";
235
0
  }
236
  //! update the style
237
  void updateStyle(MWAWGraphicStyle &style) const
238
8.08k
  {
239
8.08k
    if (m_shape.m_type!=MWAWGraphicShape::Line) {
240
4.85k
      style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
241
4.85k
      style.m_lineDashWidth.resize(0);
242
4.85k
    }
243
3.23k
    else if (m_lineArrow > 1) {
244
866
      switch (m_lineArrow) {
245
734
      case 2:
246
734
        style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
247
734
        break;
248
60
      case 3:
249
60
        style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
250
60
        break;
251
3
      case 4:
252
3
        style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
253
3
        break;
254
69
      default:
255
69
        break;
256
866
      }
257
866
    }
258
8.08k
  }
259
  //! the shape
260
  MWAWGraphicShape m_shape;
261
  //! the line arrow style (in v1)
262
  int m_lineArrow;
263
  //! the line format?
264
  int m_lineFormat;
265
private:
266
  FrameShape(FrameShape const &) = delete;
267
  FrameShape &operator=(FrameShape const &) = delete;
268
};
269
270
FrameShape::~FrameShape()
271
13.9k
{
272
13.9k
}
273
274
////////////////////////////////////////
275
//! Internal: the group zone of a GreatWksGraph
276
struct FrameGroup final : public Frame {
277
  //! constructor
278
  explicit FrameGroup(Frame const &frame)
279
203
    : Frame(frame)
280
203
    , m_numChild(0)
281
203
    , m_childList()
282
203
  {
283
203
  }
284
  //! destructor
285
  ~FrameGroup() final;
286
  //! return the frame type
287
  Type getType() const final
288
262
  {
289
262
    return T_GROUP;
290
262
  }
291
  //! print funtion
292
  void print(std::ostream &o) const final
293
0
  {
294
0
    Frame::print(o);
295
0
    if (m_numChild)
296
0
      o << "nChild=" << m_numChild << ",";
297
0
  }
298
  //! the number of child
299
  int m_numChild;
300
  //! the list of child
301
  std::vector<int> m_childList;
302
};
303
304
FrameGroup::~FrameGroup()
305
203
{
306
203
}
307
308
////////////////////////////////////////
309
//! Internal: the picture zone of a GreatWksGraph
310
struct FramePicture final : public Frame {
311
  //! constructor
312
  explicit FramePicture(Frame const &frame)
313
121
    : Frame(frame)
314
121
    , m_entry()
315
121
  {
316
121
  }
317
  //! destructor
318
  ~FramePicture() final;
319
  //! return the frame type
320
  Type getType() const final
321
159
  {
322
159
    return T_PICTURE;
323
159
  }
324
  //! print funtion
325
  void print(std::ostream &o) const final
326
0
  {
327
0
    Frame::print(o);
328
0
    if (m_entry.valid())
329
0
      o << "pos=" << std::hex << m_entry.begin() << "->" << m_entry.end() << std::dec << ",";
330
0
  }
331
  //! the picture entry
332
  MWAWEntry m_entry;
333
};
334
335
FramePicture::~FramePicture()
336
121
{
337
121
}
338
339
////////////////////////////////////////
340
//! Internal: the text zone of a GreatWksGraph
341
struct FrameText final : public Frame {
342
  //! constructor
343
  explicit FrameText(Frame const &frame)
344
5.82k
    : Frame(frame)
345
5.82k
    , m_entry()
346
5.82k
    , m_rotate(0)
347
5.82k
  {
348
11.6k
    for (auto &flip : m_flip) flip=false;
349
5.82k
  }
350
  //! destructor
351
  ~FrameText() final;
352
  //! return the frame type
353
  Type getType() const final
354
7.50k
  {
355
7.50k
    return T_TEXT;
356
7.50k
  }
357
  //! print funtion
358
  void print(std::ostream &o) const final
359
0
  {
360
0
    Frame::print(o);
361
0
    if (m_entry.valid())
362
0
      o << "pos=" << std::hex << m_entry.begin() << "->" << m_entry.end() << std::dec << ",";
363
0
    if (m_rotate) o << "rot=" << m_rotate << ",";
364
0
    if (m_flip[0]) o << "flipX=" << m_flip[0] << ",";
365
0
    if (m_flip[1]) o << "flipY=" << m_flip[1] << ",";
366
0
  }
367
  //! return the text style
368
  MWAWGraphicStyle getStyle(MWAWGraphicStyle const &zoneStyle) const
369
1.24k
  {
370
1.24k
    MWAWGraphicStyle res(zoneStyle);
371
1.24k
    res.m_lineWidth=0; // no border
372
1.24k
    res.m_flip[0]=m_flip[0];
373
1.24k
    res.m_flip[1]=m_flip[1];
374
1.24k
    res.m_rotate = float(m_rotate);
375
1.24k
    return res;
376
1.24k
  }
377
  /** return true if the has some transforms.
378
379
      \note as we have no way to retrieve mirror, we consider only rotation here*/
380
  bool hasTransform() const
381
1.48k
  {
382
1.48k
    return (m_flip[0]&m_flip[1]) || m_rotate;
383
1.48k
  }
384
  //! the text entry
385
  MWAWEntry m_entry;
386
  //! two bool to know if we must flip x or y
387
  bool m_flip[2];
388
  //! the rotate angle
389
  int m_rotate;
390
};
391
392
FrameText::~FrameText()
393
5.82k
{
394
5.82k
}
395
396
////////////////////////////////////////
397
//! Internal: the DBField zone of a GreatWksGraph
398
struct FrameDBField final : public Frame {
399
  //! constructor
400
  explicit FrameDBField(Frame const &frame)
401
1.22k
    : Frame(frame)
402
1.22k
  {
403
1.22k
  }
404
  //! destructor
405
  ~FrameDBField() final;
406
  //! return the frame type
407
  Type getType() const final
408
589
  {
409
589
    return T_DBFIELD;
410
589
  }
411
  //! print funtion
412
  void print(std::ostream &o) const final
413
0
  {
414
0
    Frame::print(o);
415
0
  }
416
};
417
418
FrameDBField::~FrameDBField()
419
{
420
}
421
422
////////////////////////////////////////
423
//! Internal: a list of graphic corresponding to a page
424
struct Zone {
425
  //! constructor
426
  Zone()
427
10.3k
    : m_page(-1)
428
10.3k
    , m_frameList()
429
10.3k
    , m_rootList()
430
10.3k
    , m_styleList()
431
10.3k
    , m_parsed(false)
432
10.3k
  {
433
10.3k
  }
434
  //! the page number (if known)
435
  int m_page;
436
  //! the list of frame
437
  std::vector<std::shared_ptr<Frame> > m_frameList;
438
  //! the list of root id
439
  std::vector<int> m_rootList;
440
  //! the list of style
441
  std::vector<MWAWGraphicStyle> m_styleList;
442
  //! true if we have send the data
443
  mutable bool m_parsed;
444
};
445
446
////////////////////////////////////////
447
//! Internal: the state of a GreatWksGraph
448
struct State {
449
  //! constructor
450
  State()
451
99.3k
    : m_zoneList()
452
99.3k
    , m_numPages(0) { }
453
  //! the list of zone ( one by page)
454
  std::vector<Zone> m_zoneList;
455
  int m_numPages /* the number of pages */;
456
};
457
458
459
////////////////////////////////////////
460
//! Internal: the subdocument of a GreatWksGraph
461
class SubDocument final : public MWAWSubDocument
462
{
463
public:
464
  //! constructor
465
  SubDocument(GreatWksGraph &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry)
466
2.25k
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry(entry))
467
2.25k
    , m_graphParser(&pars) {}
468
469
470
  //! destructor
471
0
  ~SubDocument() final {}
472
473
  //! operator!=
474
  bool operator!=(MWAWSubDocument const &doc) const final;
475
476
  //! the parser function
477
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType) final;
478
479
protected:
480
  /** the graph parser */
481
  GreatWksGraph *m_graphParser;
482
483
private:
484
  SubDocument(SubDocument const &orig) = delete;
485
  SubDocument &operator=(SubDocument const &orig) = delete;
486
};
487
488
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType)
489
2.25k
{
490
2.25k
  if (!listener || !listener->canWriteText()) {
491
0
    MWAW_DEBUG_MSG(("GreatWksGraphInternal::SubDocument::parse: no listener\n"));
492
0
    return;
493
0
  }
494
2.25k
  if (!m_graphParser) {
495
0
    MWAW_DEBUG_MSG(("GreatWksGraphInternal::SubDocument::parse: no parser\n"));
496
0
    return;
497
0
  }
498
2.25k
  long pos = m_input->tell();
499
2.25k
  m_graphParser->sendTextbox(m_zone,listener);
500
2.25k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
501
2.25k
}
502
503
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
504
0
{
505
0
  if (MWAWSubDocument::operator!=(doc)) return true;
506
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
507
0
  if (!sDoc) return true;
508
0
  if (m_graphParser != sDoc->m_graphParser) return true;
509
0
  return false;
510
0
}
511
}
512
513
////////////////////////////////////////////////////////////
514
// constructor/destructor, ...
515
////////////////////////////////////////////////////////////
516
GreatWksGraph::GreatWksGraph(GreatWksDocument &document)
517
99.3k
  : m_document(document)
518
99.3k
  , m_parserState(document.m_parserState)
519
99.3k
  , m_state(new GreatWksGraphInternal::State)
520
99.3k
  , m_mainParser(&document.getMainParser())
521
99.3k
{
522
99.3k
}
523
524
GreatWksGraph::~GreatWksGraph()
525
99.3k
{ }
526
527
int GreatWksGraph::version() const
528
14.4M
{
529
14.4M
  return m_parserState->m_version;
530
14.4M
}
531
532
533
int GreatWksGraph::numPages() const
534
14.1k
{
535
14.1k
  if (m_state->m_numPages)
536
0
    return m_state->m_numPages;
537
14.1k
  int nPages = 0;
538
14.1k
  for (auto const &zone : m_state->m_zoneList) {
539
7.74k
    if (zone.m_page>nPages)
540
944
      nPages=zone.m_page>nPages;
541
7.74k
  }
542
543
14.1k
  m_state->m_numPages = nPages;
544
14.1k
  return nPages;
545
14.1k
}
546
547
bool GreatWksGraph::sendTextbox(MWAWEntry const &entry, MWAWListenerPtr listener)
548
2.25k
{
549
2.25k
  return m_document.sendTextbox(entry, listener);
550
2.25k
}
551
552
////////////////////////////////////////////////////////////
553
//
554
// Intermediate level
555
//
556
////////////////////////////////////////////////////////////
557
558
////////////////////////////////////////////////////////////
559
// read the patterns list
560
////////////////////////////////////////////////////////////
561
bool GreatWksGraph::readPatterns(MWAWEntry const &entry)
562
760
{
563
760
  if (!entry.valid() || (entry.length()%8) != 2) {
564
330
    MWAW_DEBUG_MSG(("GreatWksGraph::readPatterns: the entry is bad\n"));
565
330
    return false;
566
330
  }
567
568
430
  long pos = entry.begin();
569
430
  MWAWInputStreamPtr input = m_parserState->m_rsrcParser->getInput();
570
430
  libmwaw::DebugFile &ascFile = m_parserState->m_rsrcParser->ascii();
571
430
  libmwaw::DebugStream f;
572
430
  entry.setParsed(true);
573
574
430
  input->seek(pos, librevenge::RVNG_SEEK_SET);
575
430
  f << "Entries(Pattern):";
576
430
  auto N=static_cast<int>(input->readLong(2));
577
430
  f << "N=" << N << ",";
578
430
  if (2+8*N!=int(entry.length())) {
579
85
    f << "###";
580
85
    MWAW_DEBUG_MSG(("GreatWksGraph::readPatterns: the number of entries seems bad\n"));
581
85
    ascFile.addPos(pos-4);
582
85
    ascFile.addNote(f.str().c_str());
583
85
    return true;
584
85
  }
585
345
  ascFile.addPos(pos-4);
586
345
  ascFile.addNote(f.str().c_str());
587
33.4k
  for (int i=0; i < N; ++i) {
588
33.1k
    pos = input->tell();
589
33.1k
    f.str("");
590
33.1k
    f << "Pattern-" << i << ":";
591
33.1k
    MWAWGraphicStyle::Pattern pat;
592
33.1k
    pat.m_dim=MWAWVec2i(8,8);
593
33.1k
    pat.m_data.resize(8);
594
298k
    for (size_t j=0; j < 8; ++j)
595
264k
      pat.m_data[j]=static_cast<unsigned char>(input->readLong(1));
596
33.1k
    f << pat;
597
33.1k
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
598
33.1k
    ascFile.addPos(pos);
599
33.1k
    ascFile.addNote(f.str().c_str());
600
33.1k
  }
601
345
  return true;
602
430
}
603
604
bool GreatWksGraph::readPalettes(MWAWEntry const &entry)
605
483
{
606
483
  if (!entry.valid() || entry.length() != 0x664) {
607
254
    MWAW_DEBUG_MSG(("GreatWksGraph::readPalettes: the entry is bad\n"));
608
254
    return false;
609
254
  }
610
611
229
  long pos = entry.begin();
612
229
  MWAWInputStreamPtr input = m_parserState->m_rsrcParser->getInput();
613
229
  libmwaw::DebugFile &ascFile = m_parserState->m_rsrcParser->ascii();
614
229
  libmwaw::DebugStream f;
615
229
  entry.setParsed(true);
616
617
229
  input->seek(pos, librevenge::RVNG_SEEK_SET);
618
229
  f << "Entries(Palette):";
619
229
  auto val=static_cast<int>(input->readLong(2));
620
229
  if (val!=2)
621
0
    f << "#f0=" << val << ",";
622
229
  val=static_cast<int>(input->readLong(2));
623
229
  if (val!=8)
624
0
    f << "#f1=" << val << ",";
625
229
  ascFile.addPos(pos-4);
626
229
  ascFile.addNote(f.str().c_str());
627
628
  // 16 sets like: ffff, 6464, 0202 : maybe some color
629
3.89k
  for (int i=0; i < 16; ++i) {
630
3.66k
    pos = input->tell();
631
3.66k
    f.str("");
632
3.66k
    f << "Palette-" << i << ":";
633
14.6k
    for (int j=0; j < 3; ++j)
634
10.9k
      f << std::hex << input->readULong(2) << std::dec << ",";
635
3.66k
    input->seek(pos+6, librevenge::RVNG_SEEK_SET);
636
3.66k
    ascFile.addPos(pos);
637
3.66k
    ascFile.addNote(f.str().c_str());
638
3.66k
  }
639
640
58.8k
  for (int i=0; i < 256; ++i) {
641
58.6k
    pos = input->tell();
642
58.6k
    f.str("");
643
58.6k
    if (i==0) f << "Entries(Colors)-0:";
644
58.3k
    else f << "Colors-" << i << ":";
645
58.6k
    unsigned char col[3];
646
175k
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
647
58.6k
    f << MWAWColor(col[0], col[1], col[2]) << ",";
648
58.6k
    input->seek(pos+6, librevenge::RVNG_SEEK_SET);
649
58.6k
    ascFile.addPos(pos);
650
58.6k
    ascFile.addNote(f.str().c_str());
651
58.6k
  }
652
653
229
  return true;
654
483
}
655
656
////////////////////////////////////////////////////////////
657
// graphic zone ( main header )
658
////////////////////////////////////////////////////////////
659
bool GreatWksGraph::isGraphicZone()
660
1.05M
{
661
1.05M
  int const vers=version();
662
1.05M
  bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW;
663
1.05M
  if (vers == 1 && !isDraw)
664
0
    return false;
665
1.05M
  int headerSize;
666
1.05M
  if (vers==1)
667
648k
    headerSize= 0x1c+0x38+0x1e +0x1a;
668
408k
  else
669
408k
    headerSize= 0x1c+0xaa+0x30;
670
1.05M
  MWAWInputStreamPtr input = m_parserState->m_input;
671
1.05M
  long pos = input->tell();
672
1.05M
  if (!input->checkPosition(pos+headerSize))
673
4.63k
    return false;
674
675
1.05M
  int dim[4];
676
1.34M
  for (int st=0; st<2; ++st) {
677
5.04M
    for (auto &d : dim) d=static_cast<int>(input->readLong(2));
678
1.26M
    if (dim[0]>=dim[2] || dim[1]>=dim[3] || dim[2]<=0 || dim[3]<=0) {
679
969k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
680
969k
      return false;
681
969k
    }
682
1.26M
  }
683
684
83.0k
  input->seek(pos+headerSize, librevenge::RVNG_SEEK_SET);
685
83.0k
  int pageHeaderSize=vers==1 ? 16 : isDraw ? 12 : 22;
686
83.0k
  if (!input->checkPosition(pos+headerSize+pageHeaderSize)) {
687
99
    bool ok=input->isEnd();
688
99
    input->seek(pos, librevenge::RVNG_SEEK_SET);
689
99
    return ok;
690
99
  }
691
82.9k
  bool ok=isPageFrames();
692
82.9k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
693
82.9k
  return ok;
694
83.0k
}
695
696
bool GreatWksGraph::readGraphicZone()
697
26.6k
{
698
26.6k
  int const vers=version();
699
26.6k
  bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW;
700
26.6k
  if (vers == 1 && !isDraw)
701
461
    return false;
702
703
26.1k
  MWAWInputStreamPtr input = m_parserState->m_input;
704
26.1k
  long beginPos = input->tell();
705
26.1k
  if (!isGraphicZone() && !findGraphicZone()) {
706
18.2k
    input->seek(beginPos, librevenge::RVNG_SEEK_SET);
707
18.2k
    return false;
708
18.2k
  }
709
7.97k
  long pos = input->tell();
710
7.97k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
711
7.97k
  if (pos!=beginPos) {
712
2.78k
    ascFile.addPos(beginPos);
713
2.78k
    ascFile.addNote("Entries(Unknown):");
714
2.78k
  }
715
7.97k
  libmwaw::DebugStream f;
716
7.97k
  f << "Entries(GZoneHeader):";
717
23.9k
  for (int st=0; st<2; ++st) {
718
15.9k
    int dim[4];
719
63.7k
    for (auto &d : dim) d=static_cast<int>(input->readLong(2));
720
15.9k
    f << "dim" << st << "=" << dim[1] << "x" << dim[0]
721
15.9k
      << "<->"<< dim[3] << "x" << dim[2] << ",";
722
15.9k
  }
723
7.97k
  ascFile.addDelimiter(input->tell(),'|');
724
7.97k
  ascFile.addPos(pos);
725
7.97k
  ascFile.addNote(f.str().c_str());
726
7.97k
  pos += 0x1c;
727
7.97k
  if (vers==1) {
728
2.60k
    ascFile.addPos(pos);
729
2.60k
    ascFile.addNote("GZoneHeader-II");
730
2.60k
    pos += 0x38;
731
732
2.60k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
733
2.60k
    f.str("");
734
2.60k
    f << "Entries(GLineFormat):";
735
2.60k
    std::string extra;
736
2.60k
    if (!readLineFormat(extra))
737
0
      f << "###";
738
2.60k
    else
739
2.60k
      f << extra;
740
2.60k
    ascFile.addPos(pos);
741
2.60k
    ascFile.addNote(f.str().c_str());
742
2.60k
    pos += 0x1e;
743
2.60k
  }
744
5.37k
  else {
745
5.37k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
746
5.37k
    MWAWGraphicStyle style;
747
5.37k
    f.str("");
748
5.37k
    f << "Entries(GStyle):";
749
5.37k
    if (!readStyle(style))
750
0
      f << "###";
751
5.37k
    else
752
5.37k
      f << style;
753
5.37k
    ascFile.addPos(pos);
754
5.37k
    ascFile.addNote(f.str().c_str());
755
756
5.37k
    pos += 0xaa;
757
758
5.37k
    ascFile.addPos(pos);
759
5.37k
    ascFile.addNote("Entries(GDatC)[_]:");
760
5.37k
    pos += 0x16;
761
5.37k
  }
762
7.97k
  ascFile.addPos(pos);
763
7.97k
  ascFile.addNote("Entries(GDatD)[_]:");
764
7.97k
  pos += 0x1a;
765
766
7.97k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
767
17.1k
  while (!input->isEnd() && readPageFrames())
768
9.22k
    pos=input->tell();
769
7.97k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
770
7.97k
  return true;
771
26.1k
}
772
773
bool GreatWksGraph::findGraphicZone()
774
21.0k
{
775
21.0k
  int const vers=version();
776
21.0k
  bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW;
777
21.0k
  if (vers == 1 && !isDraw)
778
0
    return false;
779
21.0k
  int headerSize;
780
21.0k
  if (vers==1)
781
4.00k
    headerSize= 0x1c+0x38+0x1e +0x1a;
782
17.0k
  else
783
17.0k
    headerSize= 0x1c+0xaa+0x30;
784
21.0k
  int pageHeaderSize=vers==1 ? 16 : isDraw ? 12 : 22;
785
786
21.0k
  MWAWInputStreamPtr input = m_parserState->m_input;
787
21.0k
  long pos = input->tell();
788
21.0k
  input->seek(pos+headerSize+pageHeaderSize, librevenge::RVNG_SEEK_SET);
789
23.6M
  while (!input->isEnd()) {
790
23.6M
    long actPos = input->tell();
791
23.6M
    unsigned long value= input->readULong(4);
792
23.6M
    int decal=-1;
793
    // if we find some tabs, we have a problem
794
23.6M
    if (value==0x20FFFF)
795
20.0k
      decal = 0;
796
23.6M
    else if (value==0x20FFFFFF)
797
24.5k
      decal = 1;
798
23.6M
    else if (value==0xFFFFFFFF)
799
600k
      decal = 2;
800
23.0M
    else if (value==0xFFFFFF2E)
801
7.37k
      decal = 3;
802
23.6M
    if (decal>=0) {
803
652k
      input->seek(actPos-decal, librevenge::RVNG_SEEK_SET);
804
652k
      if (input->readULong(4)==0x20FFFF && input->readULong(4)==0xFFFF2E00)
805
2.70k
        break;
806
649k
      input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
807
649k
      continue;
808
652k
    }
809
810
    // graphic size
811
23.0M
    if ((value>>24)==0x36)
812
425k
      decal = 3;
813
22.5M
    else if ((value>>16)==0x36)
814
303k
      decal = 2;
815
22.2M
    else if (((value>>8)&0xFFFF)==0x36)
816
280k
      decal = 1;
817
21.9M
    else if ((value&0xFFFF)==0x36)
818
275k
      decal = 0;
819
23.0M
    if (decal==-1)
820
21.7M
      continue;
821
822
1.28M
    input->seek(actPos-decal, librevenge::RVNG_SEEK_SET);
823
1.28M
    auto N=static_cast<int>(input->readULong(2));
824
1.28M
    if (input->readLong(2)!=0x36 || !input->checkPosition(actPos-decal+4+0x36*N)) {
825
253k
      input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
826
253k
      continue;
827
253k
    }
828
1.03M
    input->seek(actPos-decal-pageHeaderSize-headerSize, librevenge::RVNG_SEEK_SET);
829
1.03M
    if (!isGraphicZone()) {
830
1.02M
      input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
831
1.02M
      continue;
832
1.02M
    }
833
2.78k
    input->seek(actPos-decal-pageHeaderSize-headerSize, librevenge::RVNG_SEEK_SET);
834
2.78k
    return true;
835
1.03M
  }
836
18.2k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
837
18.2k
  return false;
838
21.0k
}
839
840
////////////////////////////////////////////////////////////
841
// graphic zone ( page frames)
842
////////////////////////////////////////////////////////////
843
bool GreatWksGraph::isPageFrames()
844
96.4k
{
845
96.4k
  int const vers=version();
846
96.4k
  bool isDatabase=m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE;
847
96.4k
  bool hasPageUnknown=vers==2 && m_parserState->m_kind!=MWAWDocument::MWAW_K_DRAW &&
848
28.3k
                      !isDatabase;
849
96.4k
  int const headerSize=hasPageUnknown ? 22 : (vers==2&&!isDatabase) ? 12 : 16;
850
96.4k
  int const nZones= (vers==2||isDatabase) ? 3 : 4;
851
96.4k
  MWAWInputStreamPtr &input= m_parserState->m_input;
852
96.4k
  long pos=input->tell();
853
96.4k
  long endPos=pos+headerSize+4*nZones;
854
96.4k
  if (!input->checkPosition(endPos))
855
1.19k
    return false;
856
95.2k
  long sz=-1;
857
95.2k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
858
95.2k
  if (hasPageUnknown) {
859
27.4k
    input->seek(2, librevenge::RVNG_SEEK_CUR); // page or 1c for spreadsheet
860
27.4k
    sz=long(input->readULong(4));
861
27.4k
    endPos=input->tell()+sz;
862
27.4k
  }
863
95.2k
  long zoneSz[4]= {0,0,0,0};
864
427k
  for (int i=0; i<nZones; ++i)
865
332k
    zoneSz[i]=long(input->readULong(4));
866
95.2k
  if (hasPageUnknown &&
867
27.4k
      (6+sz<headerSize+4*nZones || zoneSz[0]+zoneSz[1]+zoneSz[2]>sz ||
868
15.8k
       !input->checkPosition(endPos))) {
869
14.2k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
870
14.2k
    return false;
871
14.2k
  }
872
80.9k
  pos+=headerSize;
873
80.9k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
874
80.9k
  int expectedSz[]= {0x36, 0xaa, 0x2, 0};
875
80.9k
  if (vers==1) {
876
46.9k
    expectedSz[1]=0x34;
877
46.9k
    expectedSz[2]=0x1e;
878
46.9k
    expectedSz[3]=2;
879
46.9k
  }
880
202k
  for (int i=0; i < nZones; ++i) {
881
184k
    pos=input->tell();
882
184k
    if (pos==endPos)
883
0
      return true;
884
184k
    auto nData=static_cast<int>(input->readLong(2));
885
184k
    auto fSz=static_cast<int>(input->readLong(2));
886
184k
    if (nData<0 || (nData!=0 && fSz!=expectedSz[i]) || nData*fSz+4 > zoneSz[i]) {
887
37.8k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
888
37.8k
      return false;
889
37.8k
    }
890
146k
    if (i!=nZones-1 && nData *fSz+4!=zoneSz[i]) {
891
116k
      MWAW_DEBUG_MSG(("GreatWksGraph::isPageFrames: find a diff of %ld for data %d\n", zoneSz[i]-nData *fSz-4, i));
892
116k
      if ((2*nData+4)*fSz+4 < zoneSz[i]) {
893
24.8k
        input->seek(pos, librevenge::RVNG_SEEK_SET);
894
24.8k
        return false;
895
24.8k
      }
896
116k
    }
897
121k
    input->seek(expectedSz[i]*nData, librevenge::RVNG_SEEK_CUR);
898
121k
  }
899
18.2k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
900
18.2k
  return true;
901
80.9k
}
902
903
bool GreatWksGraph::readStyle(MWAWGraphicStyle &style)
904
13.0M
{
905
13.0M
  style=MWAWGraphicStyle();
906
13.0M
  MWAWInputStreamPtr &input= m_parserState->m_input;
907
13.0M
  libmwaw::DebugStream f;
908
13.0M
  int const vers=version();
909
13.0M
  int const gDataSize=vers==1 ? 0x34 : 0xaa;
910
911
13.0M
  long pos=input->tell();
912
13.0M
  long endPos=pos+gDataSize;
913
13.0M
  if (!input->checkPosition(endPos))
914
12.7M
    return false;
915
916
276k
  auto val=static_cast<int>(input->readLong(2));
917
276k
  if (val) f << "used=" << val << ",";
918
276k
  float dim[2];
919
552k
  for (auto &d : dim) d=float(input->readLong(4))/65536.f;
920
276k
  if (dim[0]<dim[1] || dim[0]>dim[1]) f << "lineWidth[real]=" << MWAWVec2f(dim[1],dim[0]) << ",";
921
276k
  style.m_lineWidth=(dim[1]+dim[0])/2.f;
922
276k
  if (vers==1) {
923
346k
    for (int i=0; i < 2; ++i) { // two flags 0|1
924
231k
      val=static_cast<int>(input->readULong(1));
925
231k
      if (val==0 || val==1) {
926
114k
        if (i==0)
927
57.3k
          style.m_lineOpacity=float(val);
928
56.9k
        else
929
56.9k
          style.m_surfaceOpacity=float(val);
930
114k
      }
931
117k
      else
932
117k
        f << "#hasPat" << i << "=" << val << ",";
933
231k
    }
934
115k
    MWAWGraphicStyle::Pattern patterns[2];
935
231k
    for (auto &pattern : patterns) {
936
231k
      pattern.m_dim=MWAWVec2i(8,8);
937
231k
      pattern.m_data.resize(8);
938
1.85M
      for (auto &data : pattern.m_data) data=static_cast<unsigned char>(input->readULong(1));
939
231k
    }
940
578k
    for (int i=0; i < 4; ++i) {
941
462k
      unsigned char col[3];
942
1.38M
      for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
943
462k
      patterns[i/2].m_colors[1-i%2]=MWAWColor(col[0], col[1], col[2]);
944
462k
    }
945
115k
    if (!patterns[0].getUniqueColor(style.m_lineColor)) {
946
78.3k
      f << "linePattern=[" << patterns[0] << "],";
947
78.3k
      patterns[0].getAverageColor(style.m_lineColor);
948
78.3k
    }
949
115k
    if (!patterns[1].getUniqueColor(style.m_surfaceColor)) {
950
79.3k
      if (style.m_surfaceOpacity<=0)
951
73.8k
        f << "surfPattern=[" << patterns[1] << "],";
952
5.52k
      else
953
5.52k
        style.setPattern(patterns[1]);
954
79.3k
    }
955
956
115k
    style.m_extra=f.str();
957
115k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
958
115k
    return true;
959
115k
  }
960
160k
  MWAWGraphicStyle::Pattern patterns[2];
961
802k
  for (int i=0; i < 4; ++i) {
962
641k
    val=static_cast<int>(input->readULong(2));
963
641k
    if (val) f << "col" << i << "=" << std::hex << val << std::dec << ",";
964
641k
    unsigned char col[3];
965
1.92M
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
966
641k
    patterns[i/2].m_colors[1-i%2]=MWAWColor(col[0], col[1], col[2]);
967
641k
  }
968
160k
  val=static_cast<int>(input->readULong(2));
969
160k
  if (val) f << "col4=" << std::hex << val << std::dec << ",";
970
481k
  for (int i=0; i < 2; ++i) {
971
320k
    val=static_cast<int>(input->readULong(2)); // small number
972
320k
    if (i==0)
973
160k
      style.m_lineOpacity=val ? 1.0 : 0.0;
974
160k
    else
975
160k
      style.m_surfaceOpacity=val ? 1.0 : 0.0;
976
320k
    if (val>1)
977
217k
      f << "pat" << i << "=" << val << ",";
978
320k
    patterns[i].m_dim=MWAWVec2i(8,8);
979
320k
    patterns[i].m_data.resize(8);
980
2.56M
    for (auto &data : patterns[i].m_data) data=static_cast<unsigned char>(input->readULong(1));
981
320k
  }
982
160k
  if (!patterns[0].getUniqueColor(style.m_lineColor)) {
983
116k
    f << "linePattern=[" << patterns[0] << "],";
984
116k
    patterns[0].getAverageColor(style.m_lineColor);
985
116k
  }
986
160k
  if (!patterns[1].getUniqueColor(style.m_surfaceColor)) {
987
117k
    if (style.m_surfaceOpacity<=0)
988
23.2k
      f << "surfPattern=[" << patterns[1] << "],";
989
94.1k
    else
990
94.1k
      style.setPattern(patterns[1]);
991
117k
  }
992
993
160k
  val=static_cast<int>(input->readULong(2));
994
160k
  if (val!=1) f << "patId=" << val << ",";
995
996
160k
  int nDash=val==1 ? 1 : static_cast<int>(input->readULong(2));
997
160k
  if (nDash<0||nDash>6) {
998
90.3k
    MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: can not read number of line dash\n"));
999
90.3k
    f << "#nDash=" << nDash << ",";
1000
90.3k
  }
1001
70.0k
  else {
1002
109k
    for (int i=0; i < nDash; ++i) {
1003
49.2k
      float w=float(input->readLong(4))/65536.f;
1004
49.2k
      if (w<=0) {
1005
10.1k
        if (i==0 && nDash==1)
1006
4.56k
          break;
1007
5.59k
        MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: the line dash seems bad\n"));
1008
5.59k
        f << "###dash" << i << ":w=" << w << ",";
1009
5.59k
        style.m_lineDashWidth.resize(0);
1010
5.59k
        break;
1011
10.1k
      }
1012
39.0k
      style.m_lineDashWidth.push_back(w);
1013
39.0k
    }
1014
70.0k
  }
1015
160k
  input->seek(pos+116, librevenge::RVNG_SEEK_SET);
1016
160k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1017
160k
  ascFile.addDelimiter(pos+92,'|'); // some data?
1018
160k
  ascFile.addDelimiter(input->tell(),'|');
1019
160k
  auto gradId=static_cast<int>(input->readLong(2));
1020
160k
  if (gradId) f << "gradientId=" << gradId << ",";
1021
160k
  auto gradType=static_cast<int>(input->readLong(2));
1022
160k
  if (gradId>=1 && gradId<=16 && (gradType>=1&&gradType<=3)) {
1023
9.38k
    auto &finalGrad=style.m_gradient;
1024
9.38k
    finalGrad.m_stopList.resize(2);
1025
9.38k
    finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::white());
1026
9.38k
    finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::black());
1027
9.38k
    finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Linear;
1028
9.38k
    switch (gradId) {
1029
3.07k
    case 1:
1030
3.07k
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1031
3.07k
      finalGrad.m_angle = -90;
1032
3.07k
      break;
1033
388
    case 2:
1034
388
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1035
388
      finalGrad.m_angle = -45;
1036
388
      break;
1037
538
    case 3:
1038
538
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1039
538
      break;
1040
1.07k
    case 4:
1041
1.07k
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1042
1.07k
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black());
1043
1.07k
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white());
1044
1.07k
      finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Axial;
1045
1.07k
      finalGrad.m_angle = -45;
1046
1.07k
      break;
1047
438
    case 5:
1048
438
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1049
438
      finalGrad.m_angle = 90;
1050
438
      break;
1051
254
    case 6:
1052
254
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1053
254
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black());
1054
254
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white());
1055
254
      finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Axial;
1056
254
      finalGrad.m_angle = 45;
1057
254
      break;
1058
602
    case 7:
1059
602
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1060
602
      finalGrad.m_angle = 180;
1061
602
      break;
1062
393
    case 8:
1063
393
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1064
393
      finalGrad.m_angle = -135;
1065
393
      break;
1066
707
    case 9:
1067
707
      if (gradType!=3) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1068
707
      finalGrad.m_percentCenter=MWAWVec2f(.5f,.5f);
1069
707
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black());
1070
707
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white());
1071
707
      finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Square;
1072
707
      break;
1073
158
    case 10:
1074
158
      if (gradType!=3) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1075
158
      finalGrad.m_percentCenter=MWAWVec2f(.5f,.5f);
1076
158
      finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Square;
1077
158
      break;
1078
543
    case 11:
1079
761
    case 12:
1080
761
      if (gradType!=2) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1081
761
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black());
1082
761
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white());
1083
761
      finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Radial;
1084
761
      break;
1085
165
    case 13:
1086
165
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1087
165
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0x88,0,0));
1088
165
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0xee,0,0));
1089
165
      finalGrad.m_angle = 90;
1090
165
      break;
1091
558
    case 14:
1092
558
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1093
558
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0,0x55,0));
1094
558
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0,0xee,0));
1095
558
      finalGrad.m_angle = 90;
1096
558
      break;
1097
85
    case 15:
1098
85
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1099
85
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0,0,0x88));
1100
85
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0,0,0xff));
1101
85
      finalGrad.m_angle = 90;
1102
85
      break;
1103
190
    case 16:
1104
190
      if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None;
1105
190
      finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0xff,0xff,0));
1106
190
      finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0xff,0xff,0xcc));
1107
190
      finalGrad.m_angle = 90;
1108
190
      break;
1109
0
    default:
1110
0
      break;
1111
9.38k
    }
1112
9.38k
    if (finalGrad.m_type==MWAWGraphicStyle::Gradient::G_None) {
1113
2.10k
      MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: find odd gradient\n"));
1114
2.10k
      f << "grad[##type]=" << gradType << ",";
1115
2.10k
    }
1116
9.38k
  }
1117
481k
  for (size_t i=0; i < 2; ++i) {
1118
320k
    unsigned char col[3];
1119
962k
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1120
320k
    f << "grad[col" << i << "]=" << MWAWColor(col[0], col[1], col[2]) << ",";
1121
320k
  }
1122
160k
  input->seek(2, librevenge::RVNG_SEEK_CUR); // junk ?
1123
160k
  val=static_cast<int>(input->readLong(2));
1124
160k
  switch (val) {
1125
13.6k
  case 1: // none
1126
13.6k
    break;
1127
3.04k
  case 2:
1128
3.04k
    style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
1129
3.04k
    break;
1130
3.62k
  case 3:
1131
3.62k
    style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
1132
3.62k
    break;
1133
1.68k
  case 4:
1134
1.68k
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
1135
1.68k
    break;
1136
138k
  default:
1137
138k
    f << "#lineArrows=" << val << ",";
1138
160k
  }
1139
160k
  val=static_cast<int>(input->readLong(2));
1140
160k
  if (val!=1)
1141
146k
    f << "#lineArrow[unset],";
1142
160k
  style.m_extra=f.str();
1143
1144
160k
  pos = input->tell();
1145
160k
  std::string extra("");
1146
160k
  f.str("");
1147
160k
  f << "Entries(GLineFormat):";
1148
160k
  if (readLineFormat(extra))
1149
160k
    f << extra;
1150
0
  else
1151
0
    f << "###";
1152
160k
  ascFile.addPos(pos);
1153
160k
  ascFile.addNote(f.str().c_str());
1154
160k
  ascFile.addDelimiter(input->tell(),'|');
1155
160k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1156
160k
  return true;
1157
160k
}
1158
1159
bool GreatWksGraph::readLineFormat(std::string &extra)
1160
6.94M
{
1161
6.94M
  MWAWInputStreamPtr &input= m_parserState->m_input;
1162
6.94M
  libmwaw::DebugStream f;
1163
6.94M
  int const gDataSize=0x1e;
1164
6.94M
  long pos=input->tell();
1165
6.94M
  if (!input->checkPosition(pos+gDataSize))
1166
6.46M
    return false;
1167
1168
  // find: f0=1, f1=0, f2=9|c f3=3|5, f5=c|f, f0+a dim?
1169
2.87M
  for (int i=0; i<5; ++i) {
1170
2.39M
    auto val=static_cast<int>(input->readLong(2));
1171
2.39M
    if (val) f << "f" << i << "=" << val << ",";
1172
2.39M
  }
1173
1174
479k
  extra=f.str();
1175
  // then 3ffda4bc7d1934f709244002fcfb724c879139b4
1176
479k
  m_parserState->m_asciiFile.addDelimiter(input->tell(),'|');
1177
479k
  input->seek(pos+gDataSize, librevenge::RVNG_SEEK_SET);
1178
479k
  return true;
1179
6.94M
}
1180
1181
bool GreatWksGraph::readPageFrames()
1182
13.4k
{
1183
13.4k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1184
13.4k
  int const vers=version();
1185
13.4k
  bool isDraw = m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW;
1186
13.4k
  bool isSpreadsheet = m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET;
1187
13.4k
  bool isDatabase = m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE;
1188
13.4k
  bool hasPageUnknown=vers==2 && !isDraw && !isDatabase;
1189
13.4k
  int const nZones=hasPageUnknown ? 4 : (vers==2&&!isDatabase) ? 3 : 4;
1190
13.4k
  long pos=input->tell();
1191
13.4k
  if (!isPageFrames()) {
1192
3.10k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1193
3.10k
    return false;
1194
3.10k
  }
1195
10.3k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1196
10.3k
  libmwaw::DebugStream f;
1197
10.3k
  f << "Entries(GFrame):";
1198
10.3k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1199
10.3k
  long endPos=-1;
1200
10.3k
  GreatWksGraphInternal::Zone pageZone;
1201
10.3k
  if (isSpreadsheet) {
1202
63
    auto val=static_cast<int>(input->readLong(2));
1203
63
    if (val != 0x1c) {
1204
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops unexpected key word\n"));
1205
0
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1206
0
      return false;
1207
0
    }
1208
63
    endPos=pos+6+long(input->readULong(4));
1209
63
  }
1210
10.3k
  else if (hasPageUnknown) {
1211
3.45k
    pageZone.m_page = static_cast<int>(input->readLong(2));
1212
3.45k
    f << "page=" << pageZone.m_page << ",";
1213
3.45k
    endPos=pos+6+long(input->readULong(4));
1214
3.45k
  }
1215
10.3k
  static char const* const wh[]= {"head", "gstyle", "root", "unknown"};
1216
10.3k
  long zoneSz[4]= {0,0,0,0};
1217
48.1k
  for (int i=0; i < nZones; ++i) {
1218
37.7k
    zoneSz[i] = long(input->readULong(4));
1219
37.7k
    if (zoneSz[i])
1220
36.0k
      f << wh[i] << "[sz]=" << std::hex << zoneSz[i] << std::dec << ",";
1221
37.7k
  }
1222
1223
10.3k
  int z=0;
1224
10.3k
  long zoneEnd=input->tell()+zoneSz[z++];
1225
10.3k
  auto nFrames=static_cast<int>(input->readLong(2));
1226
10.3k
  input->seek(2, librevenge::RVNG_SEEK_CUR);
1227
10.3k
  f << "nFrames=" << nFrames << ",";
1228
10.3k
  ascFile.addPos(pos);
1229
10.3k
  ascFile.addNote(f.str().c_str());
1230
10.3k
  auto &frames=pageZone.m_frameList;
1231
208k
  for (int i=0; i < nFrames; ++i) {
1232
198k
    pos = input->tell();
1233
198k
    f.str("");
1234
198k
    f << "GFrame[head]-F" << i+1 << ":";
1235
198k
    std::shared_ptr<GreatWksGraphInternal::Frame> zone;
1236
198k
    if (pos+0x36<=zoneEnd) zone=readFrameHeader();
1237
198k
    if (!zone) {
1238
151k
      MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops graphic detection is probably bad\n"));
1239
151k
      f << "###";
1240
151k
      input->seek(pos+0x36, librevenge::RVNG_SEEK_SET);
1241
151k
      zone.reset(new GreatWksGraphInternal::FrameBad());
1242
151k
    }
1243
47.1k
    else
1244
47.1k
      f << *zone;
1245
198k
    zone->m_page=pageZone.m_page;
1246
198k
    frames.push_back(zone);
1247
198k
    ascFile.addPos(pos);
1248
198k
    ascFile.addNote(f.str().c_str());
1249
198k
  }
1250
10.3k
  pos=input->tell();
1251
10.3k
  if (pos!=zoneEnd) {
1252
8.24k
    ascFile.addPos(pos);
1253
8.24k
    ascFile.addNote("GFrame[head]-end:###");
1254
8.24k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1255
8.24k
  }
1256
1257
10.3k
  pos=input->tell();
1258
10.3k
  zoneEnd=pos+zoneSz[z++];
1259
10.3k
  auto nData=static_cast<int>(input->readLong(2));
1260
10.3k
  input->seek(2, librevenge::RVNG_SEEK_CUR);
1261
10.3k
  f.str("");
1262
10.3k
  f << "Entries(GStyle): N=" << nData << ",";
1263
10.3k
  ascFile.addPos(pos);
1264
10.3k
  ascFile.addNote(f.str().c_str());
1265
10.3k
  int const gDataSize=vers==1 ? 0x34 : 0xaa;
1266
48.6M
  for (int i=0; i < nData; ++i) {
1267
48.5M
    pos = input->tell();
1268
48.5M
    f.str("");
1269
48.5M
    f << "GStyle-S" << i+1 << ":";
1270
48.5M
    MWAWGraphicStyle style;
1271
48.5M
    if (pos+gDataSize>zoneEnd || !readStyle(style))
1272
48.3M
      f << "###";
1273
270k
    else
1274
270k
      f << style;
1275
48.5M
    pageZone.m_styleList.push_back(style);
1276
48.5M
    ascFile.addPos(pos);
1277
48.5M
    ascFile.addNote(f.str().c_str());
1278
48.5M
    input->seek(pos+gDataSize, librevenge::RVNG_SEEK_SET);
1279
48.5M
  }
1280
10.3k
  pos=input->tell();
1281
10.3k
  if (pos!=zoneEnd) {
1282
8.26k
    ascFile.addPos(pos);
1283
8.26k
    ascFile.addNote("GStyle-end:###");
1284
8.26k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1285
8.26k
  }
1286
1287
10.3k
  if (vers==1) {
1288
3.04k
    pos=input->tell();
1289
3.04k
    zoneEnd=pos+zoneSz[z++];
1290
3.04k
    nData=static_cast<int>(input->readLong(2));
1291
3.04k
    input->seek(2, librevenge::RVNG_SEEK_CUR);
1292
3.04k
    f.str("");
1293
3.04k
    f << "Entries(GLineFormat): N=" << nData << ",";
1294
3.04k
    ascFile.addPos(pos);
1295
3.04k
    ascFile.addNote(f.str().c_str());
1296
3.04k
    int const gLineFSize= 0x1e;
1297
6.78M
    for (int i=0; i < nData; ++i) {
1298
6.77M
      pos = input->tell();
1299
6.77M
      f.str("");
1300
6.77M
      f << "GLineFormat-L" << i << ",";
1301
6.77M
      std::string extra("");
1302
6.77M
      if (!readLineFormat(extra))
1303
6.46M
        f << "###";
1304
316k
      else
1305
316k
        f << extra;
1306
6.77M
      ascFile.addPos(pos);
1307
6.77M
      ascFile.addNote(f.str().c_str());
1308
6.77M
      input->seek(pos+gLineFSize, librevenge::RVNG_SEEK_SET);
1309
6.77M
    }
1310
3.04k
    pos=input->tell();
1311
3.04k
    if (pos!=zoneEnd) {
1312
2.24k
      ascFile.addPos(pos);
1313
2.24k
      ascFile.addNote("GLineFormat-end:###");
1314
2.24k
      input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1315
2.24k
    }
1316
3.04k
  }
1317
1318
10.3k
  pos = input->tell();
1319
10.3k
  zoneEnd=pos+zoneSz[z++];
1320
10.3k
  auto nRoots=static_cast<int>(input->readLong(2));
1321
10.3k
  input->seek(2, librevenge::RVNG_SEEK_CUR);
1322
10.3k
  f.str("");
1323
10.3k
  f << "GFrame[roots]: N=" << nRoots << ",roots=[";
1324
7.03M
  for (int i=0; i < nRoots; ++i) {
1325
7.02M
    if (input->tell()+2>zoneEnd) {
1326
3.06k
      MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not read some roots\n"));
1327
3.06k
      f << "###";
1328
3.06k
      break;
1329
3.06k
    }
1330
7.01M
    auto val = static_cast<int>(input->readLong(2));
1331
7.01M
    if (val==0) {
1332
6.00M
      f << "_,";
1333
6.00M
      continue;
1334
6.00M
    }
1335
1.01M
    pageZone.m_rootList.push_back(val);
1336
1.01M
    f << "F" << val << ",";
1337
1.01M
  }
1338
10.3k
  f << "],";
1339
10.3k
  if (input->tell()!=zoneEnd) { // ok
1340
6.73k
    ascFile.addDelimiter(input->tell(),'|');
1341
6.73k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1342
6.73k
  }
1343
10.3k
  ascFile.addPos(pos);
1344
10.3k
  ascFile.addNote(f.str().c_str());
1345
1346
10.3k
  if (isDraw) {
1347
    // in draw document, we must sequence the frames recursively ...
1348
    // sort rootList using m_order
1349
6.54k
    std::map<int, int> orderMap;
1350
951k
    for (auto id : pageZone.m_rootList) {
1351
951k
      if (id<=0 || id>nFrames) {
1352
807k
        MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find order for frame %d\n",id));
1353
807k
        continue;
1354
807k
      }
1355
143k
      int ord=frames[size_t(id-1)]->m_order;
1356
143k
      if (orderMap.find(ord)!=orderMap.end()) {
1357
137k
        MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops order %d already exist\n",ord));
1358
137k
        continue;
1359
137k
      }
1360
6.47k
      orderMap[ord]=id;
1361
6.47k
    }
1362
6.54k
    pageZone.m_rootList.resize(0);
1363
6.54k
    for (auto const &it : orderMap)
1364
6.47k
      pageZone.m_rootList.push_back(it.second);
1365
1366
6.54k
    std::set<int> seens;
1367
6.54k
    bool ok=true;
1368
9.14k
    for (size_t c=pageZone.m_rootList.size(); c > 0;) {
1369
3.34k
      if (!readFrameExtraDataRec(pageZone, pageZone.m_rootList[--c]-1, seens, endPos)) {
1370
748
        ok = false;
1371
748
        break;
1372
748
      }
1373
3.34k
    }
1374
6.54k
    m_state->m_zoneList.push_back(pageZone);
1375
6.54k
    if (endPos>0)
1376
0
      input->seek(endPos, librevenge::RVNG_SEEK_SET);
1377
6.54k
    return ok;
1378
6.54k
  }
1379
1380
  // in text document, we must go through the last frame to the first frame to retrieve data
1381
3.83k
  bool ok=true;
1382
12.3k
  for (int id=nFrames-1; id >= 0; --id) {
1383
9.72k
    if (id>=nFrames) {
1384
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find frame with id=%d\n",id));
1385
0
      continue;
1386
0
    }
1387
9.72k
    auto zone=frames[size_t(id)];
1388
9.72k
    if (!zone) continue;
1389
9.72k
    pos=input->tell();
1390
9.72k
    ok = readFrameExtraData(*zone, id, endPos);
1391
9.72k
    f.str("");
1392
9.72k
    f << "GFrame-data:F" << id+1 << "[" << *zone << "]:";
1393
9.72k
    if (zone->m_dataSize>0 && input->tell()!=pos+zone->m_dataSize) {
1394
1.36k
      if (input->tell()>pos+zone->m_dataSize || !input->checkPosition(pos+zone->m_dataSize)) {
1395
268
        MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: must stop, file position seems bad\n"));
1396
268
        f << "###";
1397
268
        ascFile.addPos(pos);
1398
268
        ascFile.addNote(f.str().c_str());
1399
268
        ok = false;
1400
268
        break;
1401
268
      }
1402
1.09k
      if (!ok) {
1403
1.09k
        f << "[##unparsed]";
1404
1.09k
        ascFile.addPos(pos);
1405
1.09k
        ascFile.addNote(f.str().c_str());
1406
1.09k
      }
1407
1.09k
      input->seek(pos+zone->m_dataSize, librevenge::RVNG_SEEK_SET);
1408
1.09k
      ok = true;
1409
1.09k
    }
1410
9.45k
    if (ok)
1411
8.50k
      continue;
1412
952
    MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: must stop parsing graphic data\n"));
1413
952
    f << "###";
1414
952
    ascFile.addPos(pos);
1415
952
    ascFile.addNote(f.str().c_str());
1416
952
    break;
1417
9.45k
  }
1418
  // check the roots
1419
3.83k
  std::set<int> seens;
1420
61.7k
  for (auto &id : pageZone.m_rootList) {
1421
61.7k
    if (!checkGraph(pageZone, id-1, seens))
1422
52.7k
      id=0; // set the root has invalid
1423
61.7k
  }
1424
3.83k
  pos=input->tell();
1425
3.83k
  if (endPos>0 && pos!=endPos) {
1426
2.99k
    MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: find some end data\n"));
1427
2.99k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1428
2.99k
    ascFile.addPos(pos);
1429
2.99k
    ascFile.addNote("GFrame-end:###");
1430
2.99k
    ok=true;
1431
2.99k
  }
1432
3.83k
  m_state->m_zoneList.push_back(pageZone);
1433
3.83k
  return ok;
1434
10.3k
}
1435
1436
bool GreatWksGraph::checkGraph(GreatWksGraphInternal::Zone &zone, int id, std::set<int> &seens)
1437
61.7k
{
1438
61.7k
  if (seens.find(id)!=seens.end()) {
1439
1.26k
    MWAW_DEBUG_MSG(("GreatWksGraph::checkGraph: index %d is already read\n", id));
1440
1.26k
    return false;
1441
1.26k
  }
1442
60.4k
  if (id < 0 || id >= int(zone.m_frameList.size())) {
1443
51.4k
    MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find zone %d\n", id));
1444
51.4k
    return false;
1445
51.4k
  }
1446
8.98k
  seens.insert(id);
1447
8.98k
  auto frame=zone.m_frameList[size_t(id)];
1448
8.98k
  if (!frame) return true;
1449
8.98k
  if (frame->getType()!=GreatWksGraphInternal::Frame::T_GROUP)
1450
8.93k
    return true;
1451
48
  auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(*frame);
1452
48
  for (size_t c=0; c < group.m_childList.size(); ++c) {
1453
8
    if (!checkGraph(zone, group.m_childList[c]-1, seens)) {
1454
8
      group.m_childList.resize(c);
1455
8
      break;
1456
8
    }
1457
8
  }
1458
48
  return true;
1459
8.98k
}
1460
1461
bool GreatWksGraph::readFrameExtraDataRec(GreatWksGraphInternal::Zone &zone, int id, std::set<int> &seens, long endPos)
1462
3.36k
{
1463
3.36k
  if (seens.find(id)!=seens.end()) {
1464
1
    MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: index %d is already read\n", id));
1465
1
    return false;
1466
1
  }
1467
3.36k
  if (id < 0 || id >= int(zone.m_frameList.size())) {
1468
20
    MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraDataRec: can not find zone %d\n", id));
1469
20
    return false;
1470
20
  }
1471
3.34k
  seens.insert(id);
1472
3.34k
  auto frame=zone.m_frameList[size_t(id)];
1473
3.34k
  if (!frame) return true;
1474
3.34k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1475
3.34k
  long pos=input->tell();
1476
3.34k
  if (!readFrameExtraData(*frame, id, endPos)) return false;
1477
2.66k
  if (frame->m_dataSize>0 && input->tell()!=pos+frame->m_dataSize) {
1478
47
    if (input->tell()>pos+frame->m_dataSize || !input->checkPosition(pos+frame->m_dataSize)) {
1479
47
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraDataRec: must stop, file position seems bad\n"));
1480
47
      libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1481
47
      ascFile.addPos(pos);
1482
47
      ascFile.addNote("GFrame-Data###");
1483
47
      if (endPos>0)
1484
0
        input->seek(endPos, librevenge::RVNG_SEEK_SET);
1485
47
      return false;
1486
47
    }
1487
0
    input->seek(pos+frame->m_dataSize, librevenge::RVNG_SEEK_SET);
1488
0
  }
1489
2.62k
  if (frame->getType()!=GreatWksGraphInternal::Frame::T_GROUP)
1490
2.59k
    return true;
1491
26
  auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(*frame);
1492
28
  for (size_t c=0; c < group.m_childList.size(); ++c) {
1493
24
    if (!readFrameExtraDataRec(zone, group.m_childList[c]-1, seens, endPos)) {
1494
22
      group.m_childList.resize(c);
1495
22
      return false;
1496
22
    }
1497
24
  }
1498
4
  return true;
1499
26
}
1500
1501
std::shared_ptr<GreatWksGraphInternal::Frame> GreatWksGraph::readFrameHeader()
1502
198k
{
1503
198k
  int const vers=version();
1504
198k
  GreatWksGraphInternal::Frame zone;
1505
198k
  std::shared_ptr<GreatWksGraphInternal::Frame> res;
1506
198k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1507
198k
  long pos=input->tell();
1508
198k
  long endPos=pos+54;
1509
198k
  if (!input->checkPosition(endPos))
1510
0
    return res;
1511
1512
198k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1513
198k
  libmwaw::DebugStream f;
1514
198k
  zone.m_type=static_cast<int>(input->readLong(1));
1515
198k
  auto locked=static_cast<int>(input->readLong(1));
1516
198k
  if (zone.m_type<0||zone.m_type>16||locked<0||locked>1) {
1517
115k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1518
115k
    return res;
1519
115k
  }
1520
82.9k
  if (locked) f << "lock,";
1521
82.9k
  float dim[4];
1522
331k
  for (auto &d : dim) d=float(input->readLong(4))/65536.f;
1523
82.9k
  if (dim[2]<dim[0] || dim[3]<dim[1]) {
1524
35.7k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1525
35.7k
    return res;
1526
35.7k
  }
1527
47.1k
  zone.m_box=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
1528
47.1k
  zone.m_styleId=static_cast<int>(input->readULong(2));
1529
47.1k
  zone.m_parent=static_cast<int>(input->readULong(2));
1530
47.1k
  zone.m_order=static_cast<int>(input->readULong(2));
1531
47.1k
  switch (zone.m_type) {
1532
5.82k
  case 1: {
1533
5.82k
    auto textBox = std::make_shared<GreatWksGraphInternal::FrameText>(zone);
1534
5.82k
    res = textBox;
1535
5.82k
    res->m_dataSize=long(input->readULong(4));
1536
5.82k
    auto val=long(input->readULong(2));
1537
5.82k
    if (val&1) textBox->m_flip[0]=true;
1538
5.82k
    if (val&2) textBox->m_flip[1]=true;
1539
5.82k
    val &= 0xFFFC;
1540
5.82k
    if (val) f << "#flip=" << val << ",";
1541
5.82k
    textBox->m_rotate=static_cast<int>(input->readLong(2));
1542
5.82k
    if (vers==2) // checkme odd
1543
2.00k
      textBox->m_rotate = -textBox->m_rotate;
1544
5.82k
    val=input->readLong(2); // 0 or 100
1545
5.82k
    if (val) f << "f1=" << std::hex << val << std::dec << ",";
1546
5.82k
    break;
1547
0
  }
1548
121
  case 11:
1549
121
    res.reset(new GreatWksGraphInternal::FramePicture(zone));
1550
121
    res->m_dataSize=long(input->readULong(4));
1551
121
    break;
1552
203
  case 15: {
1553
203
    auto grp = std::make_shared<GreatWksGraphInternal::FrameGroup>(zone);
1554
203
    res = grp;
1555
203
    grp->m_numChild=static_cast<int>(input->readULong(2));
1556
203
    break;
1557
0
  }
1558
4.42k
  case 2: {
1559
4.42k
    auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone);
1560
4.42k
    res = graph;
1561
4.42k
    if (vers==1) {
1562
1.42k
      graph->m_lineArrow=static_cast<int>(input->readLong(2));
1563
1.42k
      graph->m_lineFormat=static_cast<int>(input->readLong(2));
1564
1.42k
    }
1565
4.42k
    float points[4];
1566
17.6k
    for (auto &pt : points) pt=float(input->readLong(4))/65536;
1567
4.42k
    graph->m_shape=MWAWGraphicShape::line(MWAWVec2f(points[1],points[0]), MWAWVec2f(points[3],points[2]));
1568
4.42k
    break;
1569
0
  }
1570
1.43k
  case 4: {
1571
1.43k
    auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone);
1572
1.43k
    res = graph;
1573
1.43k
    auto roundType = static_cast<int>(input->readLong(2));
1574
1.43k
    auto cornerDim = float(input->readLong(2));
1575
1.43k
    graph->m_shape = MWAWGraphicShape::rectangle(zone.m_box);
1576
1.43k
    switch (roundType) {
1577
910
    case 1: // normal
1578
910
      graph->m_shape.m_cornerWidth[0]=cornerDim > zone.m_box.size()[0] ? zone.m_box.size()[0]/2.f : cornerDim/2.f;
1579
910
      graph->m_shape.m_cornerWidth[1]=cornerDim > zone.m_box.size()[1] ? zone.m_box.size()[1]/2.f : cornerDim/2.f;
1580
910
      break;
1581
10
    case 2:
1582
10
      f << "cornerDim[minWidth/2],";
1583
10
      cornerDim = zone.m_box.size()[0] < zone.m_box.size()[1] ? zone.m_box.size()[0] : zone.m_box.size()[1];
1584
10
      graph->m_shape.m_cornerWidth[0]=graph->m_shape.m_cornerWidth[1]=0.5f*cornerDim;
1585
10
      break;
1586
511
    default:
1587
511
      f << "#type[corner]=" << roundType << "[" << cornerDim << "],";
1588
511
      break;
1589
1.43k
    }
1590
1.43k
    break;
1591
1.43k
  }
1592
1.43k
  case 6: {
1593
939
    auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone);
1594
939
    res = graph;
1595
939
    int fileAngle[2];
1596
1.87k
    for (auto &angle : fileAngle) angle=static_cast<int>(input->readLong(2));
1597
939
    auto type=static_cast<int>(input->readLong(1)); // 0:open, 1: close
1598
939
    if (type==1) f << "closed,";
1599
920
    else if (type) f << "#type=" << type << ",";
1600
1601
939
    int angle[2] = { int(90-fileAngle[0]-fileAngle[1]), int(90-fileAngle[0]) };
1602
939
    if (fileAngle[1]<0) {
1603
89
      angle[0]=int(90-fileAngle[0]);
1604
89
      angle[1]=int(90-fileAngle[0]-fileAngle[1]);
1605
89
    }
1606
850
    else if (fileAngle[1]==360)
1607
0
      angle[0]=int(90-fileAngle[0]-359);
1608
939
    if (angle[1]>360) {
1609
73
      int numLoop=int(angle[1]/360)-1;
1610
73
      angle[0]-=numLoop*360;
1611
73
      angle[1]-=numLoop*360;
1612
146
      while (angle[1] > 360) {
1613
73
        angle[0]-=360;
1614
73
        angle[1]-=360;
1615
73
      }
1616
73
    }
1617
939
    if (angle[0] < -360) {
1618
563
      int numLoop=int(angle[0]/360)+1;
1619
563
      angle[0]-=numLoop*360;
1620
563
      angle[1]-=numLoop*360;
1621
1.12k
      while (angle[0] < -360) {
1622
558
        angle[0]+=360;
1623
558
        angle[1]+=360;
1624
558
      }
1625
563
    }
1626
    // we must compute the real bd box
1627
939
    float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
1628
939
    int limitAngle[2];
1629
2.81k
    for (int i = 0; i < 2; ++i)
1630
1.87k
      limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
1631
40.0k
    for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) {
1632
39.0k
      float ang = (bord == limitAngle[0]) ? float(angle[0]) :
1633
39.0k
                  (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord);
1634
39.0k
      ang *= float(M_PI/180.);
1635
39.0k
      float const actVal[2] = { std::cos(ang), -std::sin(ang)};
1636
39.0k
      if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
1637
37.7k
      else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
1638
39.0k
      if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
1639
37.7k
      else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
1640
39.0k
    }
1641
939
    MWAWBox2f circleBox=zone.m_box;
1642
    // we have the shape box, we need to reconstruct the circle box
1643
939
    if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) {
1644
939
      float const scaling[2]= { (zone.m_box[1][0]-zone.m_box[0][0])/(maxVal[0]-minVal[0]),
1645
939
                                (zone.m_box[1][1]-zone.m_box[0][1])/(maxVal[1]-minVal[1])
1646
939
                              };
1647
939
      float const constant[2]= { zone.m_box[0][0]-minVal[0] *scaling[0], zone.m_box[0][1]-minVal[1] *scaling[1]};
1648
939
      circleBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]),
1649
939
                          MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1]));
1650
939
    }
1651
939
    if (type==1)
1652
19
      graph->m_shape = MWAWGraphicShape::pie(zone.m_box, circleBox, MWAWVec2f(float(angle[0]), float(angle[1])));
1653
920
    else
1654
920
      graph->m_shape = MWAWGraphicShape::arc(zone.m_box, circleBox, MWAWVec2f(float(angle[0]), float(angle[1])));
1655
939
    break;
1656
1.43k
  }
1657
1.83k
  case 3: // rect: no data
1658
4.05k
  case 5: { // oval no data
1659
4.05k
    auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone);
1660
4.05k
    MWAWGraphicShape &shape = graph->m_shape;
1661
4.05k
    res = graph;
1662
4.05k
    shape.m_bdBox = shape.m_formBox = zone.m_box;
1663
4.05k
    shape.m_type = zone.m_type==3 ? MWAWGraphicShape::Rectangle : MWAWGraphicShape::Circle;
1664
4.05k
    break;
1665
1.83k
  }
1666
1.22k
  case 10: {
1667
1.22k
    auto field = std::make_shared<GreatWksGraphInternal::FrameDBField>(zone);
1668
1.22k
    res = field;
1669
1.22k
    field->m_dataSize=long(input->readULong(4));
1670
1.22k
    break;
1671
1.83k
  }
1672
363
  case 7:
1673
2.04k
  case 8:
1674
3.09k
  case 12: {
1675
3.09k
    auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone);
1676
3.09k
    res = graph;
1677
3.09k
    graph->m_shape = zone.m_type==12 ? MWAWGraphicShape::path(zone.m_box) : MWAWGraphicShape::polygon(zone.m_box);
1678
3.09k
    graph->m_dataSize=long(input->readULong(4));
1679
3.09k
    break;
1680
2.04k
  }
1681
25.8k
  default:
1682
25.8k
    break;
1683
47.1k
  }
1684
47.1k
  if (!res)
1685
25.8k
    res.reset(new GreatWksGraphInternal::Frame(zone));
1686
47.1k
  res->m_extra=f.str();
1687
47.1k
  ascFile.addDelimiter(input->tell(),'|');
1688
47.1k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1689
47.1k
  return res;
1690
47.1k
}
1691
1692
bool GreatWksGraph::readFrameExtraData(GreatWksGraphInternal::Frame &frame, int id, long endPos)
1693
13.0k
{
1694
13.0k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1695
13.0k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1696
13.0k
  libmwaw::DebugStream f;
1697
13.0k
  f << "GFrame[data]-F" << id+1 << ":";
1698
13.0k
  long pos=input->tell();
1699
13.0k
  switch (frame.m_type) {
1700
410
  case 0:
1701
410
    MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: find group with type=0\n"));
1702
410
    return false;
1703
2.84k
  case 1: {
1704
2.84k
    if (frame.getType()!=GreatWksGraphInternal::Frame::T_TEXT) {
1705
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for text\n"));
1706
0
      return false;
1707
0
    }
1708
2.84k
    auto &text=static_cast<GreatWksGraphInternal::FrameText &>(frame);
1709
2.84k
    if (!input->checkPosition(pos+text.m_dataSize)) {
1710
157
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: text size seems bad\n"));
1711
157
      return false;
1712
157
    }
1713
2.69k
    text.m_entry.setBegin(pos);
1714
2.69k
    text.m_entry.setLength(text.m_dataSize);
1715
2.69k
    input->seek(pos+text.m_dataSize, librevenge::RVNG_SEEK_SET);
1716
2.69k
    ascFile.addPos(pos);
1717
2.69k
    ascFile.addNote(f.str().c_str());
1718
2.69k
    return true;
1719
2.84k
  }
1720
504
  case 10:
1721
504
    input->seek(pos+frame.m_dataSize, librevenge::RVNG_SEEK_SET);
1722
504
    ascFile.addPos(pos);
1723
504
    ascFile.addNote(f.str().c_str());
1724
504
    return true;
1725
2.98k
  case 2:
1726
4.17k
  case 3:
1727
4.99k
  case 4:
1728
5.51k
  case 5:
1729
5.69k
  case 6:
1730
5.69k
    return true;
1731
1.30k
  case 8: // poly normal
1732
1.53k
  case 7: // regular poly
1733
2.46k
  case 12: { // spline
1734
2.46k
    if (frame.getType()!=GreatWksGraphInternal::Frame::T_BASIC) {
1735
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for basic graph\n"));
1736
0
      return false;
1737
0
    }
1738
2.46k
    auto nPt=static_cast<int>(input->readLong(2));
1739
2.46k
    long endData=pos+10+8*nPt;
1740
2.46k
    if (pos+frame.m_dataSize > endData)
1741
1.79k
      endData=pos+frame.m_dataSize;
1742
2.46k
    if (nPt<0 || (endPos>0 && endData>endPos) ||
1743
1.13k
        (endPos<0 && !input->checkPosition(endData)))
1744
1.36k
      return false;
1745
1.10k
    float dim[4];
1746
4.40k
    for (auto &d : dim) d=float(input->readLong(4))/65536.f;
1747
1.10k
    f << "dim=" << dim[1] << "x" << dim[0] << "<->"
1748
1.10k
      << dim[3] << "x" << dim[2] << ",";
1749
1.10k
    f << "pt=[";
1750
1.10k
    auto &graph=static_cast<GreatWksGraphInternal::FrameShape &>(frame);
1751
1.10k
    float pt[2];
1752
1.10k
    std::vector<MWAWVec2f> vertices;
1753
10.0k
    for (int p=0; p<nPt; ++p) {
1754
17.9k
      for (auto &i: pt) i=float(input->readLong(4))/65536.f;
1755
8.97k
      vertices.push_back(MWAWVec2f(pt[1],pt[0]));
1756
8.97k
      f << pt[1] << "x" << pt[0] << ",";
1757
8.97k
    }
1758
1.10k
    f << "],";
1759
1.10k
    if (graph.m_shape.m_type == MWAWGraphicShape::Polygon)
1760
688
      graph.m_shape.m_vertices = vertices;
1761
412
    else if (graph.m_shape.m_type == MWAWGraphicShape::Path) {
1762
412
      if (nPt<4 || (nPt%3)!=1) {
1763
184
        MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: the spline number of points seems bad\n"));
1764
184
        f << "###";
1765
184
      }
1766
228
      else {
1767
228
        std::vector<MWAWGraphicShape::PathData> &path=graph.m_shape.m_path;
1768
228
        path.push_back(MWAWGraphicShape::PathData('M', vertices[0]));
1769
1770
1.69k
        for (size_t p=1; p < size_t(nPt); p+=3) {
1771
1.47k
          bool hasFirstC=vertices[p-1]!=vertices[p];
1772
1.47k
          bool hasSecondC=vertices[p+1]!=vertices[p+2];
1773
1.47k
          if (!hasFirstC && !hasSecondC)
1774
354
            path.push_back(MWAWGraphicShape::PathData('L', vertices[p+2]));
1775
1.11k
          else if (hasFirstC)
1776
900
            path.push_back(MWAWGraphicShape::PathData('C', vertices[p+2], vertices[p+1], vertices[p+1]));
1777
216
          else
1778
216
            path.push_back(MWAWGraphicShape::PathData('S', vertices[p+2], vertices[p+1]));
1779
1.47k
        }
1780
228
        path.push_back(MWAWGraphicShape::PathData('Z'));
1781
228
      }
1782
412
    }
1783
0
    else {
1784
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: find unexpected vertices\n"));
1785
0
      f << "###";
1786
0
    }
1787
1.10k
    if (input->tell()!=endData) {
1788
634
      ascFile.addDelimiter(input->tell(),'|');
1789
634
      input->seek(endData,librevenge::RVNG_SEEK_SET);
1790
634
    }
1791
1.10k
    ascFile.addPos(pos);
1792
1.10k
    ascFile.addNote(f.str().c_str());
1793
1.10k
    return true;
1794
2.46k
  }
1795
53
  case 11: {
1796
53
    if (frame.getType()!=GreatWksGraphInternal::Frame::T_PICTURE) {
1797
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for picture\n"));
1798
0
      return false;
1799
0
    }
1800
53
    auto &pict=static_cast<GreatWksGraphInternal::FramePicture &>(frame);
1801
53
    if (!input->checkPosition(pos+pict.m_dataSize)) {
1802
16
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: picture size seems bad\n"));
1803
16
      return false;
1804
16
    }
1805
37
    pict.m_entry.setBegin(pos);
1806
37
    pict.m_entry.setLength(pict.m_dataSize);
1807
37
    input->seek(pos+pict.m_dataSize, librevenge::RVNG_SEEK_SET);
1808
37
    return true;
1809
53
  }
1810
172
  case 15: {
1811
172
    auto nGrp=static_cast<int>(input->readLong(2));
1812
172
    if (nGrp<0 || (endPos>0 && pos+4+2*nGrp>endPos) ||
1813
118
        (endPos<0 && !input->checkPosition(pos+4+2*nGrp))) {
1814
65
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected number of group\n"));
1815
65
      return false;
1816
65
    }
1817
1818
107
    if (frame.getType()!=GreatWksGraphInternal::Frame::T_GROUP) {
1819
0
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for group\n"));
1820
0
      input->seek(pos+4+2*nGrp, librevenge::RVNG_SEEK_SET);
1821
0
      f << "###[internal]";
1822
0
      return false;
1823
0
    }
1824
107
    auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(frame);
1825
107
    if (nGrp != group.m_numChild) {
1826
83
      f << "###[N=" << group.m_numChild << "]";
1827
83
      MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected number of group child\n"));
1828
83
    }
1829
107
    auto val=static_cast<int>(input->readLong(2)); // always 2
1830
107
    if (val!=2) f << "f0=" << val << ",";
1831
107
    f << "grpId=[";
1832
3.27k
    for (int j=0; j < nGrp; ++j) {
1833
3.17k
      val = static_cast<int>(input->readLong(2));
1834
3.17k
      group.m_childList.push_back(val);
1835
3.17k
      f << val << ",";
1836
3.17k
    }
1837
107
    f << "],";
1838
107
    ascFile.addPos(pos);
1839
107
    ascFile.addNote(f.str().c_str());
1840
107
    return true;
1841
107
  }
1842
925
  default:
1843
925
    break;
1844
13.0k
  }
1845
925
  MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type\n"));
1846
925
  return false;
1847
13.0k
}
1848
1849
////////////////////////////////////////////////////////////
1850
// textbox
1851
////////////////////////////////////////////////////////////
1852
bool GreatWksGraph::sendTextbox(GreatWksGraphInternal::FrameText const &text, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos)
1853
2.25k
{
1854
2.25k
  MWAWListenerPtr listener=m_parserState->getMainListener();
1855
2.25k
  if (!listener) {
1856
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendTextbox: can not find the listener\n"));
1857
0
    return true;
1858
0
  }
1859
2.25k
  MWAWGraphicStyle style;
1860
2.25k
  if (text.m_styleId>=1 && text.m_styleId <= int(zone.m_styleList.size()))
1861
1.94k
    style = zone.m_styleList[size_t(text.m_styleId-1)];
1862
2.25k
  MWAWVec2f fSz=pos.size();
1863
  // increase slightly x and set y to atleast
1864
2.25k
  MWAWVec2f newSz(fSz[0]+3,fSz[1]);
1865
2.25k
  if (listener->getType()==MWAWListener::Graphic)
1866
777
    return sendTextboxAsGraphic(MWAWBox2f(pos.origin(),pos.origin()+newSz), text, style, listener);
1867
1868
1.48k
  MWAWPosition finalPos(pos);
1869
1.48k
  finalPos.setSize(MWAWVec2f(newSz[0], -newSz[1]));
1870
1.48k
  if ((text.hasTransform() || style.hasPattern() || style.hasGradient()) &&
1871
485
      m_document.canSendTextboxAsGraphic(text.m_entry)) {
1872
468
    MWAWBox2f box(MWAWVec2f(0,0),newSz);
1873
468
    MWAWGraphicEncoder graphicEncoder;
1874
468
    MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, box, &graphicEncoder));
1875
468
    graphicListener->startDocument();
1876
468
    bool ok=sendTextboxAsGraphic(box, text, style, graphicListener);
1877
468
    graphicListener->endDocument();
1878
468
    MWAWEmbeddedObject picture;
1879
468
    if (!graphicEncoder.getBinaryResult(picture) || !ok)
1880
0
      return false;
1881
468
    listener->insertPicture(finalPos, picture);
1882
468
    return true;
1883
468
  }
1884
1885
1.01k
  std::shared_ptr<MWAWSubDocument> doc(new GreatWksGraphInternal::SubDocument(*this, m_parserState->m_input, text.m_entry));
1886
1.01k
  MWAWGraphicStyle frameStyle;
1887
1.01k
  if (style.hasSurfaceColor())
1888
24
    frameStyle.setBackgroundColor(style.m_surfaceColor);
1889
1.01k
  listener->insertTextBox(finalPos, doc, frameStyle);
1890
1.01k
  return true;
1891
1.48k
}
1892
1893
bool GreatWksGraph::sendTextboxAsGraphic(MWAWBox2f const &box, GreatWksGraphInternal::FrameText const &text,
1894
    MWAWGraphicStyle const &style, MWAWListenerPtr listener)
1895
1.24k
{
1896
1.24k
  libmwaw::SubDocumentType subdocType;
1897
1.24k
  if (!listener || !listener->isDocumentStarted() || listener->isSubDocumentOpened(subdocType)) {
1898
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendTextboxAsGraphic: unexpected graphic state\n"));
1899
0
    return false;
1900
0
  }
1901
1.24k
  std::shared_ptr<MWAWSubDocument> doc(new GreatWksGraphInternal::SubDocument(*this, m_parserState->m_input, text.m_entry));
1902
1903
1.24k
  MWAWVec2f fSz=box.size();
1904
1.24k
  MWAWBox2f textBox=MWAWBox2f(box[0],box[0]+MWAWVec2f(fSz[0], -fSz[1]));
1905
  /* rotation are multiple of 90, so we can use the inverse rotation to find
1906
     the original box */
1907
1.24k
  if (text.m_rotate)
1908
754
    textBox=libmwaw::rotateBoxFromCenter(box, -float(text.m_rotate));
1909
1.24k
  MWAWPosition textPos(textBox[0], textBox.size(), librevenge::RVNG_POINT);
1910
1.24k
  textPos.m_anchorTo=MWAWPosition::Page;
1911
1.24k
  textPos.m_wrapping = MWAWPosition::WBackground;
1912
1.24k
  listener->insertTextBox(textPos, doc, text.getStyle(style));
1913
1.24k
  return true;
1914
1.24k
}
1915
1916
////////////////////////////////////////////////////////////
1917
// picture
1918
////////////////////////////////////////////////////////////
1919
bool GreatWksGraph::sendPicture(MWAWEntry const &entry, MWAWPosition const &pos)
1920
77
{
1921
77
  MWAWListenerPtr listener=m_parserState->getMainListener();
1922
77
  if (!listener) {
1923
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendPicture: can not find the listener\n"));
1924
0
    return true;
1925
0
  }
1926
77
  if (!entry.valid()) {
1927
57
    MWAW_DEBUG_MSG(("GreatWksGraph::sendPicture: can not find the entry\n"));
1928
57
    return false;
1929
57
  }
1930
20
  entry.setParsed(true);
1931
20
  MWAWInputStreamPtr &input= m_parserState->m_input;
1932
20
  long actPos = input->tell();
1933
1934
20
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1935
20
  std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(input, static_cast<int>(entry.length())));
1936
20
  MWAWEmbeddedObject picture;
1937
20
  if (thePict && thePict->getBinary(picture))
1938
10
    listener->insertPicture(pos, picture);
1939
1940
#ifdef DEBUG_WITH_FILES
1941
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1942
  ascFile.skipZone(entry.begin(), entry.end()-1);
1943
  librevenge::RVNGBinaryData file;
1944
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1945
  input->readDataBlock(entry.length(), file);
1946
1947
  static int volatile pictName = 0;
1948
  libmwaw::DebugStream f;
1949
  f << "DATA-" << ++pictName << ".pct";
1950
  libmwaw::Debug::dumpFile(file, f.str().c_str());
1951
#endif
1952
1953
20
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
1954
20
  return true;
1955
77
}
1956
1957
////////////////////////////////////////////////////////////
1958
// group
1959
////////////////////////////////////////////////////////////
1960
bool GreatWksGraph::sendGroup(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos)
1961
81
{
1962
81
  sendGroupChild(group,zone,pos);
1963
81
  return true;
1964
81
}
1965
1966
bool GreatWksGraph::canCreateGraphic(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone)
1967
0
{
1968
0
  if (group.m_childList.empty())
1969
0
    return true;
1970
0
  auto numFrames=static_cast<int>(zone.m_frameList.size());
1971
0
  int page=group.m_page;
1972
0
  for (auto childId : group.m_childList) {
1973
0
    if (childId<=0 || childId>int(numFrames)) continue;
1974
0
    std::shared_ptr<GreatWksGraphInternal::Frame> frame=zone.m_frameList[size_t(childId-1)];
1975
0
    if (!frame) continue;
1976
0
    if (frame->m_page!=page) return false;
1977
0
    switch (frame->getType()) {
1978
0
    case GreatWksGraphInternal::Frame::T_BASIC:
1979
0
      break;
1980
0
    case GreatWksGraphInternal::Frame::T_DBFIELD:
1981
0
    case GreatWksGraphInternal::Frame::T_PICTURE:
1982
0
      return false;
1983
0
    case GreatWksGraphInternal::Frame::T_GROUP:
1984
0
      if (!canCreateGraphic(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone))
1985
0
        return false;
1986
0
      break;
1987
0
    case GreatWksGraphInternal::Frame::T_TEXT: {
1988
0
      auto const &text=static_cast<GreatWksGraphInternal::FrameText const &>(*frame);
1989
0
      if (!m_document.canSendTextboxAsGraphic(text.m_entry))
1990
0
        return false;
1991
0
      break;
1992
0
    }
1993
0
    case GreatWksGraphInternal::Frame::T_BAD:
1994
0
    case GreatWksGraphInternal::Frame::T_UNSET:
1995
#if !defined(__clang__)
1996
    default:
1997
#endif
1998
0
      break;
1999
0
    }
2000
0
  }
2001
0
  return true;
2002
0
}
2003
2004
void GreatWksGraph::sendGroup(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWGraphicListenerPtr &listener)
2005
0
{
2006
0
  if (!listener || group.m_childList.empty()) return;
2007
0
  auto numFrames=static_cast<int>(zone.m_frameList.size());
2008
0
  for (auto childId : group.m_childList) {
2009
0
    if (childId<=0 || childId>int(numFrames)) continue;
2010
0
    auto frame=zone.m_frameList[size_t(childId-1)];
2011
0
    if (!frame) continue;
2012
2013
0
    MWAWBox2f const &box=frame->m_box;
2014
0
    MWAWGraphicStyle style;
2015
0
    if (frame->m_styleId>=1 && frame->m_styleId <= int(zone.m_styleList.size()))
2016
0
      style = zone.m_styleList[size_t(frame->m_styleId-1)];
2017
0
    switch (frame->getType()) {
2018
0
    case GreatWksGraphInternal::Frame::T_BASIC: {
2019
0
      auto const &shape=static_cast<GreatWksGraphInternal::FrameShape const &>(*frame);
2020
0
      shape.updateStyle(style);
2021
0
      MWAWPosition shapePos(box[0], box.size(), librevenge::RVNG_POINT);
2022
0
      shapePos.m_anchorTo=MWAWPosition::Page;
2023
0
      listener->insertShape(shapePos, shape.m_shape, style);
2024
0
      break;
2025
0
    }
2026
0
    case GreatWksGraphInternal::Frame::T_GROUP:
2027
0
      sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone,listener);
2028
0
      break;
2029
0
    case GreatWksGraphInternal::Frame::T_TEXT:
2030
0
      sendTextboxAsGraphic(MWAWBox2f(box[0],box[1]+MWAWVec2f(3,0)),
2031
0
                           static_cast<GreatWksGraphInternal::FrameText const &>(*frame), style, listener);
2032
0
      break;
2033
0
    case GreatWksGraphInternal::Frame::T_DBFIELD:
2034
0
    case GreatWksGraphInternal::Frame::T_PICTURE:
2035
0
    case GreatWksGraphInternal::Frame::T_BAD:
2036
0
    case GreatWksGraphInternal::Frame::T_UNSET:
2037
#if !defined(__clang__)
2038
    default:
2039
#endif
2040
0
      break;
2041
0
    }
2042
0
  }
2043
0
}
2044
2045
void GreatWksGraph::sendGroupChild(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos)
2046
81
{
2047
81
  MWAWListenerPtr listener=m_parserState->getMainListener();
2048
81
  if (!listener) {
2049
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendGroupChild: can not find the listeners\n"));
2050
0
    return;
2051
0
  }
2052
81
  size_t numChilds=group.m_childList.size(), childNotSent=0;
2053
81
  if (!numChilds) return;
2054
2055
2
  bool isDraw=listener->getType()==MWAWListener::Graphic;
2056
2
  int numDataToMerge=0;
2057
2
  auto numFrames=static_cast<int>(zone.m_frameList.size());
2058
2
  MWAWBox2f partialBdBox;
2059
2
  MWAWPosition partialPos(pos);
2060
2061
4
  for (size_t c=0; c<numChilds; ++c) {
2062
2
    int childId=group.m_childList[c];
2063
2
    if (childId<=0 || childId>int(numFrames)) continue;
2064
2
    std::shared_ptr<GreatWksGraphInternal::Frame> frame=zone.m_frameList[size_t(childId-1)];
2065
2
    if (!frame) continue;
2066
2067
2
    bool canMerge=false;
2068
2
    if (!isDraw && frame->m_page==group.m_page) {
2069
0
      switch (frame->getType()) {
2070
0
      case GreatWksGraphInternal::Frame::T_BASIC:
2071
0
        canMerge=true;
2072
0
        break;
2073
0
      case GreatWksGraphInternal::Frame::T_GROUP:
2074
0
        canMerge=canCreateGraphic(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone);
2075
0
        break;
2076
0
      case GreatWksGraphInternal::Frame::T_TEXT: {
2077
0
        auto const &text=static_cast<GreatWksGraphInternal::FrameText const &>(*frame);
2078
0
        canMerge=m_document.canSendTextboxAsGraphic(text.m_entry);
2079
0
        break;
2080
0
      }
2081
0
      case GreatWksGraphInternal::Frame::T_DBFIELD:
2082
0
      case GreatWksGraphInternal::Frame::T_PICTURE:
2083
0
      case GreatWksGraphInternal::Frame::T_BAD:
2084
0
      case GreatWksGraphInternal::Frame::T_UNSET:
2085
#if !defined(__clang__)
2086
      default:
2087
#endif
2088
0
        break;
2089
0
      }
2090
0
    }
2091
2
    MWAWBox2f box=frame->m_box;
2092
2
    bool isLast=false;
2093
2
    if (canMerge) {
2094
0
      if (numDataToMerge == 0)
2095
0
        partialBdBox=box;
2096
0
      else
2097
0
        partialBdBox=partialBdBox.getUnion(box);
2098
0
      ++numDataToMerge;
2099
0
      if (c+1 < numChilds)
2100
0
        continue;
2101
0
      isLast=true;
2102
0
    }
2103
2104
2
    if (numDataToMerge>1) {
2105
0
      MWAWGraphicEncoder graphicEncoder;
2106
0
      MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, partialBdBox, &graphicEncoder));
2107
0
      graphicListener->startDocument();
2108
0
      size_t lastChild = isLast ? c : c-1;
2109
0
      for (size_t ch=childNotSent; ch <= lastChild; ++ch) {
2110
0
        int localCId = group.m_childList[ch];
2111
0
        if (localCId<=0 || localCId>int(numFrames)) continue;
2112
0
        auto child=zone.m_frameList[size_t(localCId-1)];
2113
0
        if (!child) continue;
2114
2115
0
        box=child->m_box;
2116
0
        MWAWGraphicStyle style;
2117
0
        if (child->m_styleId>=1 && child->m_styleId <= int(zone.m_styleList.size()))
2118
0
          style = zone.m_styleList[size_t(child->m_styleId-1)];
2119
0
        switch (child->getType()) {
2120
0
        case GreatWksGraphInternal::Frame::T_BASIC: {
2121
0
          auto const &shape=static_cast<GreatWksGraphInternal::FrameShape const &>(*child);
2122
0
          shape.updateStyle(style);
2123
0
          MWAWPosition shapePos(box[0], box.size(), librevenge::RVNG_POINT);
2124
0
          shapePos.m_anchorTo=MWAWPosition::Page;
2125
0
          graphicListener->insertShape(shapePos, shape.m_shape, style);
2126
0
          break;
2127
0
        }
2128
0
        case GreatWksGraphInternal::Frame::T_GROUP:
2129
0
          sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*child), zone,graphicListener);
2130
0
          break;
2131
0
        case GreatWksGraphInternal::Frame::T_TEXT:
2132
0
          sendTextboxAsGraphic(MWAWBox2f(box[0],box[1]+MWAWVec2f(3,0)),
2133
0
                               static_cast<GreatWksGraphInternal::FrameText const &>(*child), style, graphicListener);
2134
0
          break;
2135
0
        case GreatWksGraphInternal::Frame::T_DBFIELD:
2136
0
        case GreatWksGraphInternal::Frame::T_PICTURE:
2137
0
        case GreatWksGraphInternal::Frame::T_BAD:
2138
0
        case GreatWksGraphInternal::Frame::T_UNSET:
2139
#if !defined(__clang__)
2140
        default:
2141
#endif
2142
0
          break;
2143
0
        }
2144
0
      }
2145
0
      graphicListener->endDocument();
2146
0
      MWAWEmbeddedObject picture;
2147
0
      if (graphicEncoder.getBinaryResult(picture)) {
2148
0
        partialPos.setOrigin(pos.origin()+partialBdBox[0]-group.m_box[0]);
2149
0
        partialPos.setSize(partialBdBox.size());
2150
0
        listener->insertPicture(partialPos, picture);
2151
0
        if (isLast)
2152
0
          break;
2153
0
        childNotSent=c;
2154
0
      }
2155
0
    }
2156
2157
    // time to send back the data
2158
4
    for (; childNotSent <= c; ++childNotSent) {
2159
2
      int localCId=group.m_childList[childNotSent];
2160
2
      if (localCId<=0 || localCId>int(numFrames)) continue;
2161
2
      auto child=zone.m_frameList[size_t(localCId-1)];
2162
2
      if (!child) continue;
2163
2
      sendFrame(child, zone);
2164
2
    }
2165
2
    numDataToMerge=0;
2166
2
  }
2167
2
}
2168
2169
2170
////////////////////////////////////////////////////////////
2171
// send data to a listener
2172
////////////////////////////////////////////////////////////
2173
2174
////////////////////////////////////////////////////////////
2175
// send data
2176
////////////////////////////////////////////////////////////
2177
bool GreatWksGraph::sendShape(GreatWksGraphInternal::FrameShape const &graph, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos)
2178
8.08k
{
2179
8.08k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2180
8.08k
  if (!listener) {
2181
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendShape: can not find a listener\n"));
2182
0
    return false;
2183
0
  }
2184
8.08k
  MWAWGraphicStyle style;
2185
8.08k
  if (graph.m_styleId>=1 && graph.m_styleId <= int(zone.m_styleList.size()))
2186
7.49k
    style = zone.m_styleList[size_t(graph.m_styleId-1)];
2187
8.08k
  graph.updateStyle(style);
2188
8.08k
  MWAWPosition finalPos(pos);
2189
8.08k
  finalPos.setOrigin(pos.origin()-MWAWVec2f(2,2));
2190
8.08k
  finalPos.setSize(pos.size()+MWAWVec2f(4,4));
2191
8.08k
  listener->insertShape(finalPos,graph.m_shape, style);
2192
8.08k
  return true;
2193
8.08k
}
2194
2195
bool GreatWksGraph::sendFrame(std::shared_ptr<GreatWksGraphInternal::Frame> frame, GreatWksGraphInternal::Zone const &zone)
2196
13.5k
{
2197
13.5k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2198
13.5k
  if (!listener || !frame) {
2199
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendFrame: can not find a listener\n"));
2200
0
    return false;
2201
0
  }
2202
13.5k
  frame->m_parsed=true;
2203
13.5k
  MWAWInputStreamPtr &input= m_parserState->m_input;
2204
13.5k
  long pos=input->tell();
2205
13.5k
  MWAWVec2f LTPos(0,0);
2206
13.5k
  if (m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW)
2207
6.47k
    LTPos=72.0f*MWAWVec2f(float(m_mainParser->getPageSpan().getMarginLeft()), float(m_mainParser->getPageSpan().getMarginTop()));
2208
13.5k
  MWAWPosition fPos(frame->m_box[0]+LTPos,frame->m_box.size(),librevenge::RVNG_POINT);
2209
13.5k
  fPos.setRelativePosition(MWAWPosition::Page);
2210
13.5k
  fPos.setPage(frame->m_page<0 ? 1: frame->m_page);
2211
13.5k
  fPos.m_wrapping = MWAWPosition::WBackground;
2212
13.5k
  bool ok=true;
2213
13.5k
  switch (frame->getType()) {
2214
8.08k
  case GreatWksGraphInternal::Frame::T_BASIC:
2215
8.08k
    ok = sendShape(static_cast<GreatWksGraphInternal::FrameShape const &>(*frame), zone, fPos);
2216
8.08k
    break;
2217
66
  case GreatWksGraphInternal::Frame::T_PICTURE:
2218
66
    ok = sendPicture(static_cast<GreatWksGraphInternal::FramePicture const &>(*frame).m_entry, fPos);
2219
66
    break;
2220
81
  case GreatWksGraphInternal::Frame::T_GROUP:
2221
81
    ok = sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone, fPos);
2222
81
    break;
2223
2.25k
  case GreatWksGraphInternal::Frame::T_TEXT:
2224
2.25k
    ok = sendTextbox(static_cast<GreatWksGraphInternal::FrameText const &>(*frame), zone, fPos);
2225
2.25k
    break;
2226
88
  case GreatWksGraphInternal::Frame::T_DBFIELD:
2227
  // do me
2228
917
  case GreatWksGraphInternal::Frame::T_BAD:
2229
3.02k
  case GreatWksGraphInternal::Frame::T_UNSET:
2230
#if !defined(__clang__)
2231
  default:
2232
#endif
2233
3.02k
    ok=false;
2234
13.5k
  }
2235
13.5k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2236
13.5k
  return ok;
2237
13.5k
}
2238
2239
bool GreatWksGraph::sendPageFrames(GreatWksGraphInternal::Zone const &zone)
2240
7.56k
{
2241
7.56k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2242
7.56k
  if (!listener) {
2243
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendPageFrames: can not find a listener\n"));
2244
0
    return false;
2245
0
  }
2246
7.56k
  zone.m_parsed=true;
2247
14.0k
  for (auto id : zone.m_rootList) {
2248
14.0k
    --id;
2249
14.0k
    if (id<0 || !zone.m_frameList[size_t(id)])
2250
511
      continue;
2251
13.5k
    auto frame=zone.m_frameList[size_t(id)];
2252
13.5k
    if (frame->m_parsed)
2253
0
      continue;
2254
13.5k
    sendFrame(frame,zone);
2255
13.5k
  }
2256
7.56k
  return true;
2257
7.56k
}
2258
2259
bool GreatWksGraph::sendPageGraphics()
2260
12.6k
{
2261
12.6k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2262
12.6k
  if (!listener) {
2263
0
    MWAW_DEBUG_MSG(("GreatWksGraph::sendPageGraphics: can not find a listener\n"));
2264
0
    return false;
2265
0
  }
2266
12.6k
  for (auto const &zone : m_state->m_zoneList) {
2267
7.56k
    if (zone.m_parsed)
2268
0
      continue;
2269
7.56k
    sendPageFrames(zone);
2270
7.56k
  }
2271
12.6k
  return true;
2272
12.6k
}
2273
2274
void GreatWksGraph::flushExtra()
2275
0
{
2276
0
  sendPageGraphics();
2277
0
}
2278
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: