Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MsWksGraph.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 "MWAWListener.hxx"
45
#include "MWAWFont.hxx"
46
#include "MWAWFontConverter.hxx"
47
#include "MWAWGraphicEncoder.hxx"
48
#include "MWAWGraphicListener.hxx"
49
#include "MWAWGraphicShape.hxx"
50
#include "MWAWGraphicStyle.hxx"
51
#include "MWAWParagraph.hxx"
52
#include "MWAWPictBitmap.hxx"
53
#include "MWAWPictMac.hxx"
54
#include "MWAWPosition.hxx"
55
#include "MWAWSubDocument.hxx"
56
57
#include "MsWksTable.hxx"
58
#include "MsWksDocument.hxx"
59
60
#include "MsWksGraph.hxx"
61
62
/** Internal: the structures of a MsWksGraph */
63
namespace MsWksGraphInternal
64
{
65
////////////////////////////////////////
66
//! Internal: a list of zones ( for v4)
67
struct RBZone {
68
  RBZone()
69
53.4k
    : m_isMain(true)
70
53.4k
    , m_id(-2)
71
53.4k
    , m_idList()
72
53.4k
    , m_frame("")
73
53.4k
  {
74
53.4k
  }
75
  //! returns a unique id
76
  int getId() const
77
30.8k
  {
78
30.8k
    return m_isMain ? -1 : m_id;
79
30.8k
  }
80
  //! the zone type: rbdr(true) or rbil
81
  bool m_isMain;
82
  //! the zone id
83
  int m_id;
84
  //! the list of rb
85
  std::vector<int> m_idList;
86
  //! the frame name ( if it exist )
87
  std::string m_frame;
88
};
89
90
////////////////////////////////////////
91
//! Internal: the generic pict
92
struct Zone {
93
  enum Type { Unknown, Shape, ChartZone, Group, Pict, Text, Textv4, Bitmap, TableZone, OLE};
94
  //! constructor
95
  Zone()
96
102M
    : m_subType(-1)
97
102M
    , m_zoneId(-1)
98
102M
    , m_pos()
99
102M
    , m_dataPos(-1)
100
102M
    , m_fileId(-1)
101
102M
    , m_page(-1)
102
102M
    , m_decal()
103
102M
    , m_finalDecal()
104
102M
    , m_box()
105
102M
    , m_line(-1)
106
102M
    , m_style()
107
102M
    , m_order(0)
108
102M
    , m_extra("")
109
102M
    , m_doNotSend(false)
110
102M
    , m_isSent(false)
111
102M
  {
112
306M
    for (auto &id : m_ids) id = 0;
113
102M
  }
114
25.6M
  Zone(Zone const &)=default;
115
  Zone &operator=(Zone const &)=default;
116
43.4M
  Zone &operator=(Zone &&)=default;
117
  //! destructor
118
127M
  virtual ~Zone() {}
119
120
  //! operator<<
121
  friend std::ostream &operator<<(std::ostream &o, Zone const &pict)
122
0
  {
123
0
    pict.print(o);
124
0
    return o;
125
0
  }
126
  //! return the type
127
  virtual Type type() const
128
0
  {
129
0
    return Unknown;
130
0
  }
131
132
  //! return a binary data (if known)
133
  virtual bool getBinaryData(MWAWInputStreamPtr, MWAWEmbeddedObject &picture) const
134
0
  {
135
0
    picture=MWAWEmbeddedObject();
136
0
    return false;
137
0
  }
138
139
  //! return the extra border space ( if needed)
140
  virtual float needExtraBorderWidth() const
141
666k
  {
142
666k
    return 0.0;
143
666k
  }
144
145
  //! add frame parameters to propList (if needed )
146
0
  virtual void fillFrame(MWAWGraphicStyle &) const { }
147
148
  //! return the box
149
  MWAWBox2f getLocalBox(bool extendWithBord=true) const
150
3.61M
  {
151
3.61M
    float x = m_box.size().x(), y=m_box.size().y();
152
3.61M
    MWAWVec2f min = m_box.min();
153
3.61M
    if (x < 0) {
154
1.17M
      min+=MWAWVec2f(x,0);
155
1.17M
      x *= -1.0f;
156
1.17M
    }
157
3.61M
    if (y < 0) {
158
1.12M
      min+=MWAWVec2f(0,y);
159
1.12M
      y *= -1.0f;
160
1.12M
    }
161
3.61M
    MWAWBox2f res(min, min+MWAWVec2f(x,y));
162
3.61M
    if (!extendWithBord) return res;
163
3.45M
    float bExtra = needExtraBorderWidth();
164
3.45M
    if (bExtra > 0) res.extend(2.0f*bExtra);
165
3.45M
    return res;
166
3.61M
  }
167
168
  MWAWPosition getPosition(MWAWPosition::AnchorTo rel) const
169
3.27M
  {
170
3.27M
    MWAWPosition res;
171
3.27M
    MWAWBox2f box = getLocalBox();
172
3.27M
    if (rel==MWAWPosition::Paragraph || rel==MWAWPosition::Frame) {
173
1.87M
      res = MWAWPosition(box.min()+m_finalDecal, box.size(), librevenge::RVNG_POINT);
174
1.87M
      res.setRelativePosition(rel);
175
1.87M
      if (rel==MWAWPosition::Paragraph)
176
1.86M
        res.m_wrapping = MWAWPosition::WBackground;
177
1.87M
    }
178
1.39M
    else if (rel!=MWAWPosition::Page) {
179
8.89k
      res = MWAWPosition(MWAWVec2f(0,0), box.size(), librevenge::RVNG_POINT);
180
8.89k
      res.setRelativePosition(MWAWPosition::Char,
181
8.89k
                              MWAWPosition::XLeft, MWAWPosition::YTop);
182
8.89k
    }
183
1.38M
    else {
184
1.38M
      res = MWAWPosition(box.min()+m_finalDecal, box.size(), librevenge::RVNG_POINT);
185
1.38M
      res.setRelativePosition(MWAWPosition::Page);
186
1.38M
      if (m_page >=0)
187
381k
        res.setPage(m_page+1);
188
1.38M
      res.m_wrapping =  MWAWPosition::WBackground;
189
1.38M
    }
190
3.27M
    if (m_order > 0) res.setOrder(m_order);
191
3.27M
    return res;
192
3.27M
  }
193
194
  //! the virtual print function
195
  virtual void print(std::ostream &o) const;
196
197
  //! the type
198
  int m_subType;
199
  //! the zone id
200
  int m_zoneId;
201
  //! the file position
202
  MWAWEntry m_pos;
203
  //! the data begin position
204
  long m_dataPos;
205
  //! the file id
206
  int m_fileId;
207
  //! the zones id (main, previous, next)
208
  long m_ids[3];
209
  //! the page
210
  int m_page;
211
  //! the local position
212
  MWAWBox2f m_decal;
213
  //! the final local position
214
  MWAWVec2f m_finalDecal;
215
  //! local bdbox
216
  MWAWBox2f m_box;
217
  //! the line position(v1)
218
  int m_line;
219
  //! the style
220
  MsWksGraph::Style m_style;
221
  //! the picture order
222
  int m_order;
223
  //! extra data
224
  std::string m_extra;
225
  //! a flag used to know if we need to send the data ( or if this is the part of a sub group)
226
  bool m_doNotSend;
227
  //! true if the zone is send
228
  bool m_isSent;
229
};
230
231
void Zone::print(std::ostream &o) const
232
0
{
233
0
  if (m_fileId >= 0) {
234
0
    o << "P" << m_fileId;
235
0
    if (m_zoneId >= 0) o << "[" << m_zoneId << "],";
236
0
    else o << ",";
237
0
  }
238
0
  for (int i = 0; i < 3; i++) {
239
0
    if (m_ids[i] <= 0) continue;
240
0
    switch (i) {
241
0
    case 0:
242
0
      o << "id=";
243
0
      break;
244
0
    case 1:
245
0
      o << "pId=";
246
0
      break;
247
0
    default:
248
0
      o << "nId=";
249
0
      break;
250
0
    }
251
0
    o << std::hex << m_ids[i] << std::dec << ",";
252
0
  }
253
0
  switch (m_subType) {
254
0
  case 0:
255
0
    o << "line,";
256
0
    break;
257
0
  case 1:
258
0
    o << "rect,";
259
0
    break;
260
0
  case 2:
261
0
    o << "rectOval,";
262
0
    break;
263
0
  case 3:
264
0
    o << "circle,";
265
0
    break;
266
0
  case 4:
267
0
    o << "arc,";
268
0
    break;
269
0
  case 5:
270
0
    o << "poly,";
271
0
    break;
272
0
  case 7:
273
0
    o << "pict,";
274
0
    break;
275
0
  case 8:
276
0
    o << "group,";
277
0
    break;
278
0
  case 9:
279
0
    o << "textbox,";
280
0
    break;
281
0
  case 0xa:
282
0
    o << "chart,";
283
0
    break;
284
0
  case 0xc:
285
0
    o << "equation/graph,";
286
0
    break;
287
0
  case 0xd:
288
0
    o << "bitmap,";
289
0
    break;
290
0
  case 0xe:
291
0
    o << "ssheet,";
292
0
    break;
293
0
  case 0xf:
294
0
    o << "textbox2,";
295
0
    break;
296
0
  case 0x10:
297
0
    o << "table,";
298
0
    break;
299
0
  case 0x100:
300
0
    o << "pict,";
301
0
    break; // V1 pict
302
0
  default:
303
0
    o << "#type=" << m_subType << ",";
304
0
  }
305
0
  if (m_page>=0) o << "page=" << m_page << ",";
306
0
  if (m_decal!=MWAWBox2f())
307
0
    o << "pos=" << m_decal << ",";
308
0
  o << "bdbox=" << m_box << ",";
309
0
  o << "style=[" << m_style << "],";
310
0
  if (m_line >= 0) o << "line=" << m_line << ",";
311
0
  if (m_extra.length()) o << m_extra;
312
0
}
313
////////////////////////////////////////
314
//! Internal: the group of a MsWksGraph
315
struct GroupZone final : public Zone {
316
  //! constructor
317
  explicit GroupZone(Zone const &z)
318
459k
    : Zone(z)
319
459k
    , m_childs()
320
459k
  {
321
459k
  }
322
  //! destructor
323
  ~GroupZone() final;
324
  //! return the type
325
  Type type() const final
326
1.02M
  {
327
1.02M
    return Group;
328
1.02M
  }
329
  //! operator<<
330
  void print(std::ostream &o) const final
331
0
  {
332
0
    Zone::print(o);
333
0
    o << "childs=[";
334
0
    for (auto id : m_childs)
335
0
      o << "P" << id << ",";
336
0
    o << "],";
337
0
  }
338
  //! list of child id
339
  std::vector<int> m_childs;
340
};
341
342
GroupZone::~GroupZone()
343
459k
{
344
459k
}
345
346
////////////////////////////////////////
347
//! Internal: the simple form of a MsWksGraph ( line, rect, ...)
348
struct BasicShape final : public Zone {
349
  //! constructor
350
  explicit BasicShape(Zone const &z)
351
10.0M
    : Zone(z)
352
10.0M
    , m_shape()
353
10.0M
  {
354
10.0M
  }
355
  //! destructor
356
  ~BasicShape() final;
357
  //! return the type
358
  Type type() const final
359
6.23M
  {
360
6.23M
    return Shape;
361
6.23M
  }
362
  //! operator<<
363
  void print(std::ostream &o) const final
364
0
  {
365
0
    Zone::print(o);
366
0
    o << m_shape << ",";
367
0
  }
368
  //! return the extra border size
369
  float needExtraBorderWidth() const final
370
2.78M
  {
371
2.78M
    float res=m_style.m_lineWidth;
372
2.78M
    if (m_shape.m_type==MWAWGraphicShape::Line) {
373
5.01M
      for (const auto &arrow : m_style.m_arrows) {
374
5.01M
        if (!arrow.isEmpty()) res+=4;
375
5.01M
      }
376
2.50M
    }
377
2.78M
    return 0.5f*res;
378
2.78M
  }
379
  //! return the shape type
380
  MWAWGraphicStyle getStyle() const
381
3.56M
  {
382
3.56M
    MWAWGraphicStyle style(m_style);
383
3.56M
    if (m_subType!=0)
384
307k
      style.m_arrows[0] = style.m_arrows[1]=MWAWGraphicStyle::Arrow();
385
3.56M
    return style;
386
3.56M
  }
387
388
  //! the basic shape
389
  MWAWGraphicShape m_shape;
390
private:
391
  BasicShape(BasicShape const &) = delete;
392
  BasicShape &operator=(BasicShape const &) = delete;
393
};
394
395
BasicShape::~BasicShape()
396
10.0M
{
397
10.0M
}
398
399
////////////////////////////////////////
400
//! Internal: the table of a MsWksGraph
401
struct Chart final : public Zone {
402
  //! constructor
403
  explicit Chart(Zone const &z)
404
6.49M
    : Zone(z)
405
6.49M
    , m_chartId(0)
406
6.49M
  {
407
6.49M
  }
408
  //! empty constructor
409
  Chart()
410
    : Zone()
411
    , m_chartId(0)
412
0
  {
413
0
  }
414
  //! destructor
415
  ~Chart() final;
416
417
  //! return the type
418
  Type type() const final
419
367
  {
420
367
    return ChartZone;
421
367
  }
422
  //! the chart id
423
  int m_chartId;
424
};
425
426
Chart::~Chart()
427
6.49M
{
428
6.49M
}
429
430
////////////////////////////////////////
431
//! Internal: the picture of a MsWksGraph
432
struct DataPict final : public Zone {
433
  //! constructor
434
  explicit DataPict(Zone const &z)
435
340k
    : Zone(z)
436
340k
    , m_dataEndPos(-1)
437
340k
    , m_naturalBox()
438
340k
  {
439
340k
  }
440
  //! empty constructor
441
  DataPict()
442
5.31M
    : Zone(),
443
5.31M
      m_dataEndPos(-1)
444
5.31M
    , m_naturalBox()
445
5.31M
  {
446
5.31M
  }
447
448
  //! return the type
449
  Type type() const final
450
383k
  {
451
383k
    return Pict;
452
383k
  }
453
  //! return a binary data (if known)
454
  bool getBinaryData(MWAWInputStreamPtr ip, MWAWEmbeddedObject &picture) const final;
455
456
  //! operator<<
457
  void print(std::ostream &o) const final
458
0
  {
459
0
    Zone::print(o);
460
0
  }
461
  //! the end of data (only defined when different to m_pos.end())
462
  long m_dataEndPos;
463
  //! the pict box (if known )
464
  mutable MWAWBox2f m_naturalBox;
465
};
466
467
bool DataPict::getBinaryData(MWAWInputStreamPtr ip, MWAWEmbeddedObject &picture) const
468
106k
{
469
106k
  picture=MWAWEmbeddedObject();
470
106k
  long endPos = m_dataEndPos<=0 ? m_pos.end() : m_dataEndPos;
471
106k
  long pictSize = endPos-m_dataPos;
472
106k
  if (pictSize < 0) {
473
0
    MWAW_DEBUG_MSG(("MsWksGraphInternal::DataPict::getBinaryData: picture size is bad\n"));
474
0
    return false;
475
0
  }
476
477
#ifdef DEBUG_WITH_FILES
478
  if (1) {
479
    librevenge::RVNGBinaryData file;
480
    ip->seek(m_dataPos, librevenge::RVNG_SEEK_SET);
481
    ip->readDataBlock(pictSize, file);
482
    static int volatile pictName = 0;
483
    libmwaw::DebugStream f;
484
    f << "Pict-" << ++pictName << ".pct";
485
    libmwaw::Debug::dumpFile(file, f.str().c_str());
486
  }
487
#endif
488
489
106k
  ip->seek(m_dataPos, librevenge::RVNG_SEEK_SET);
490
106k
  auto res = MWAWPictData::check(ip, static_cast<int>(pictSize), m_naturalBox);
491
106k
  if (res == MWAWPict::MWAW_R_BAD) {
492
66.0k
    MWAW_DEBUG_MSG(("MsWksGraphInternal::DataPict::getBinaryData: can not find the picture\n"));
493
66.0k
    return false;
494
66.0k
  }
495
496
40.8k
  ip->seek(m_dataPos, librevenge::RVNG_SEEK_SET);
497
40.8k
  std::shared_ptr<MWAWPict> pict(MWAWPictData::get(ip, static_cast<int>(pictSize)));
498
499
40.8k
  return pict && pict->getBinary(picture);
500
106k
}
501
502
////////////////////////////////////////
503
//! Internal: the bitmap of a MsWksGraph
504
struct DataBitmap final : public Zone {
505
  //! constructor
506
  explicit DataBitmap(Zone const &z)
507
12
    : Zone(z)
508
12
    , m_numRows(0)
509
12
    , m_numCols(0)
510
12
    , m_dataSize(0)
511
12
    , m_naturalBox()
512
12
  {
513
12
  }
514
  //! empty constructor
515
  DataBitmap()
516
    : Zone()
517
    , m_numRows(0)
518
    , m_numCols(0)
519
    , m_dataSize(0)
520
    , m_naturalBox()
521
0
  {
522
0
  }
523
  //! destructor
524
  ~DataBitmap() final;
525
526
  //! return the type
527
  Type type() const final
528
0
  {
529
0
    return Bitmap;
530
0
  }
531
  //! return a binary data (if known)
532
  bool getPictureData(MWAWInputStreamPtr ip, MWAWEmbeddedObject &picture, std::vector<MWAWColor> const &palette) const;
533
534
  //! operator<<
535
  void print(std::ostream &o) const final
536
0
  {
537
0
    o << "nRows=" << m_numRows << ",";
538
0
    o << "nCols=" << m_numCols << ",";
539
0
    if (m_dataSize > 0)
540
0
      o << "dSize=" << std::hex << m_dataSize << std::dec << ",";
541
0
    Zone::print(o);
542
0
  }
543
544
  int m_numRows /** the number of rows*/, m_numCols/** the number of columns*/;
545
  long m_dataSize /** the bitmap data size */;
546
  //! the pict box (if known )
547
  mutable MWAWBox2f m_naturalBox;
548
};
549
550
bool DataBitmap::getPictureData(MWAWInputStreamPtr ip, MWAWEmbeddedObject &picture, std::vector<MWAWColor> const &palette) const
551
0
{
552
0
  picture=MWAWEmbeddedObject();
553
0
  if (m_dataSize <= 0 || m_dataSize < m_numRows*m_numCols) {
554
0
    MWAW_DEBUG_MSG(("MsWksGraphInternal::DataBitmap::getPictureData: dataSize size is bad\n"));
555
0
    return false;
556
0
  }
557
0
  auto szCol = int(m_dataSize/m_numRows);
558
0
  long pos = m_dataPos;
559
560
0
  MWAWPictBitmapIndexed *btmap = new MWAWPictBitmapIndexed(MWAWVec2i(m_numCols, m_numRows));
561
0
  if (!btmap) return false;
562
0
  btmap->setColors(palette);
563
0
  std::shared_ptr<MWAWPict> pict(btmap);
564
0
  for (int i = 0; i < m_numRows; i++) {
565
0
    ip->seek(pos, librevenge::RVNG_SEEK_SET);
566
567
0
    unsigned long numRead;
568
0
    uint8_t const *value = ip->read(size_t(m_numCols), numRead);
569
0
    if (!value || int(numRead) != m_numCols) return false;
570
0
    btmap->setRow(i, value);
571
572
0
    pos += szCol;
573
0
  }
574
575
0
  return pict->getBinary(picture);
576
0
}
577
578
DataBitmap::~DataBitmap()
579
12
{
580
12
}
581
582
////////////////////////////////////////
583
//! Internal: the table of a MsWksGraph
584
struct Table final : public Zone {
585
  //! constructor
586
  explicit Table(Zone const &z)
587
174k
    : Zone(z)
588
174k
    , m_tableId(0)
589
174k
  {
590
174k
  }
591
  //! empty constructor
592
  Table()
593
    : Zone()
594
    , m_tableId(0)
595
0
  {
596
0
  }
597
  //! destructor
598
  ~Table() final;
599
600
  //! return the type
601
  Type type() const final
602
50.3k
  {
603
50.3k
    return TableZone;
604
50.3k
  }
605
  //! the table id
606
  int m_tableId;
607
};
608
609
Table::~Table()
610
174k
{
611
174k
}
612
613
////////////////////////////////////////
614
//! Internal: the textbox of a MsWksGraph ( v2-v3)
615
struct TextBox final : public Zone {
616
  //! constructor
617
  explicit TextBox(Zone const &z)
618
7.93M
    : Zone(z)
619
7.93M
    , m_numPositions(-1)
620
7.93M
    , m_fontsList()
621
7.93M
    , m_positions()
622
7.93M
    , m_formats()
623
7.93M
    , m_text("")
624
7.93M
    , m_justify(MWAWParagraph::JustificationLeft)
625
7.93M
  { }
626
  //! destructor
627
  ~TextBox() final;
628
  //! return the type
629
  Type type() const final
630
35.0k
  {
631
35.0k
    return Text;
632
35.0k
  }
633
  //! operator<<
634
  void print(std::ostream &o) const final
635
0
  {
636
0
    Zone::print(o);
637
0
    switch (m_justify) {
638
0
    case MWAWParagraph::JustificationLeft:
639
0
      break;
640
0
    case MWAWParagraph::JustificationCenter:
641
0
      o << ",centered";
642
0
      break;
643
0
    case MWAWParagraph::JustificationRight:
644
0
      o << ",right";
645
0
      break;
646
0
    case MWAWParagraph::JustificationFull:
647
0
      o << ",full";
648
0
      break;
649
0
    case MWAWParagraph::JustificationFullAllLines:
650
0
      o << ",fullAllLines";
651
0
      break;
652
#if !defined(__clang__)
653
    default:
654
      o << ",#just=" << m_justify;
655
      break;
656
#endif
657
0
    }
658
0
  }
659
660
  //! add frame parameters to propList (if needed )
661
  void fillFrame(MWAWGraphicStyle &style) const final
662
0
  {
663
0
    if (!m_style.m_baseSurfaceColor.isWhite())
664
0
      style.setBackgroundColor(m_style.m_baseSurfaceColor);
665
0
  }
666
667
  //! the number of positions
668
  int m_numPositions;
669
  //! the list of fonts
670
  std::vector<MWAWFont> m_fontsList;
671
  //! the list of positions
672
  std::vector<int> m_positions;
673
  //! the list of format
674
  std::vector<int> m_formats;
675
  //! the text
676
  std::string m_text;
677
  //! the paragraph alignment
678
  MWAWParagraph::Justification m_justify;
679
private:
680
  TextBox(TextBox const &) = delete;
681
  TextBox &operator=(TextBox const &) = delete;
682
};
683
684
TextBox::~TextBox()
685
7.93M
{
686
7.93M
}
687
688
////////////////////////////////////////
689
//! Internal: the ole zone of a MsWksGraph ( v4)
690
struct OLEZone final : public Zone {
691
  //! constructor
692
  explicit OLEZone(Zone const &z)
693
134k
    : Zone(z)
694
134k
    , m_oleId(-1)
695
134k
    , m_dim()
696
134k
  { }
697
  //! destructor
698
  ~OLEZone() final;
699
  //! return the type
700
  Type type() const final
701
102k
  {
702
102k
    return OLE;
703
102k
  }
704
  //! operator<<
705
  void print(std::ostream &o) const final
706
0
  {
707
0
    if (m_oleId >= 0) o << "ole" << m_oleId << ",";
708
0
    if (m_dim[0] > 0 && m_dim[1] > 0) o << "dim=" << m_dim << ",";
709
0
    Zone::print(o);
710
0
  }
711
712
  //! the ole id
713
  int m_oleId;
714
  //! the dimension
715
  MWAWVec2i m_dim;
716
};
717
718
OLEZone::~OLEZone()
719
134k
{
720
134k
}
721
722
////////////////////////////////////////
723
//! Internal: the textbox of a MsWksGraph ( v4)
724
struct TextBoxv4 final : public Zone {
725
  //! constructor
726
  explicit TextBoxv4(Zone const &z)
727
56.5k
    : Zone(z)
728
56.5k
    , m_text()
729
56.5k
    , m_frame("")
730
56.5k
  { }
731
  //! destructor
732
  ~TextBoxv4() final;
733
  //! return the type
734
  Type type() const final
735
182k
  {
736
182k
    return Textv4;
737
182k
  }
738
  //! operator<<
739
  void print(std::ostream &o) const final
740
0
  {
741
0
    Zone::print(o);
742
0
    if (m_text.valid()) o << ", textPos=[" << m_text.begin() << "-" << m_text.end() << "]";
743
0
  }
744
745
  //! add frame parameters to propList (if needed )
746
  void fillFrame(MWAWGraphicStyle &style) const final
747
174k
  {
748
174k
    if (!m_style.m_baseSurfaceColor.isWhite())
749
20.0k
      style.setBackgroundColor(m_style.m_baseSurfaceColor);
750
174k
  }
751
752
  //! the text of positions (0-0: means no text)
753
  MWAWEntry m_text;
754
  //! the frame name
755
  std::string m_frame;
756
};
757
758
759
TextBoxv4::~TextBoxv4()
760
56.5k
{
761
56.5k
}
762
763
//! Internal the pattern ressource of a MsWksGraph
764
struct Pattern {
765
  //! constructor ( 4 int by patterns )
766
  Pattern(int num, uint16_t const *data)
767
209k
    : m_num(num)
768
209k
    , m_valuesList()
769
209k
    , m_percentList()
770
209k
  {
771
209k
    if (m_num<=0) return;
772
209k
    m_valuesList.resize(size_t(m_num)*8);
773
21.9M
    for (size_t i=0; i < size_t(m_num)*4; ++i) {
774
21.7M
      uint16_t val=data[i];
775
21.7M
      m_valuesList[2*i]=static_cast<unsigned char>(val>>8);
776
21.7M
      m_valuesList[2*i+1]=static_cast<unsigned char>(val&0xFF);
777
21.7M
    }
778
209k
    size_t pat=0;
779
5.63M
    for (size_t i=0; i < size_t(num); ++i) {
780
5.42M
      int numOnes=0;
781
48.8M
      for (int j=0; j < 8; ++j) {
782
43.4M
        uint8_t val=m_valuesList[pat++];
783
390M
        for (int b=0; b < 8; b++) {
784
347M
          if (val&1) ++numOnes;
785
347M
          val = uint8_t(val>>1);
786
347M
        }
787
43.4M
      }
788
5.42M
      m_percentList.push_back(float(numOnes)/64.f);
789
5.42M
    }
790
209k
  }
791
  //! return the pattern corresponding to an id
792
  bool get(int id, MWAWGraphicStyle::Pattern &pat) const
793
1.72M
  {
794
1.72M
    if (id < 0 || id >= m_num) {
795
303k
      MWAW_DEBUG_MSG(("MsWksGraphInternal::Pattern::get: can not find pattern %d\n", id));
796
303k
      return false;
797
303k
    }
798
1.41M
    pat.m_dim=MWAWVec2i(8,8);
799
1.41M
    unsigned char const *ptr=&m_valuesList[8*size_t(id)];
800
1.41M
    pat.m_data.resize(8);
801
1.41M
    for (auto &data : pat.m_data)
802
11.3M
      data=*(ptr++);
803
1.41M
    return true;
804
1.72M
  }
805
  //! return the percentage corresponding to a pattern
806
  float getPercent(int id) const
807
2.47M
  {
808
2.47M
    if (id < 0 || id >= m_num) {
809
235k
      MWAW_DEBUG_MSG(("MsWksGraphInternal::Pattern::getPatternPercent: can not find pattern %d\n", id));
810
235k
      return 1.0;
811
235k
    }
812
2.23M
    return m_percentList[size_t(id)];
813
2.47M
  }
814
815
  //! the number of patterns
816
  int m_num;
817
  //! the pattern values (8 data by pattern)
818
  std::vector<unsigned char> m_valuesList;
819
  //! the pattern percent values
820
  std::vector<float> m_percentList;
821
};
822
823
////////////////////////////////////////
824
//! Internal: the state of a MsWksGraph
825
struct State {
826
  //! constructor
827
  State()
828
287k
    : m_version(-1)
829
287k
    , m_leftTopPos(0,0)
830
287k
    , m_zonesList()
831
287k
    , m_RBsMap()
832
287k
    , m_font(20,12)
833
287k
    , m_chartId(0)
834
287k
    , m_tableId(0)
835
287k
    , m_numPages(0)
836
287k
    , m_rsrcPatternMap()
837
287k
  {
838
287k
  }
839
  //! return the pattern corresponding to an id
840
  bool getPattern(MWAWGraphicStyle::Pattern &pat, int id, long rsid=-1);
841
  //! return the percentage corresponding to a pattern
842
  float getPatternPercent(int id, long rsid=-1);
843
  //! init the pattern value
844
  void initPattern(int vers);
845
  //! the version
846
  int m_version;
847
  //! the page left top position in points
848
  MWAWVec2f m_leftTopPos;
849
  //! the list of zone
850
  std::vector<std::shared_ptr<Zone> > m_zonesList;
851
  //! the RBIL zone id->list id
852
  std::map<int, RBZone> m_RBsMap;
853
  //! the actual font
854
  MWAWFont m_font;
855
  //! an index used to store chart
856
  int m_chartId;
857
  //! an index used to store table
858
  int m_tableId;
859
  //! the number of pages
860
  int m_numPages;
861
  //! a map ressource id -> patterns
862
  std::map<long, Pattern> m_rsrcPatternMap;
863
};
864
865
void State::initPattern(int vers)
866
36.8k
{
867
36.8k
  if (!m_rsrcPatternMap.empty()) return;
868
36.8k
  if (vers <= 2) {
869
24.8k
    static uint16_t const valuesV2[] = {
870
24.8k
      0xffff, 0xffff, 0xffff, 0xffff,  0xddff, 0x77ff, 0xddff, 0x77ff,  0xdd77, 0xdd77, 0xdd77, 0xdd77,  0xaa55, 0xaa55, 0xaa55, 0xaa55,
871
24.8k
      0x55ff, 0x55ff, 0x55ff, 0x55ff,  0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,  0xeedd, 0xbb77, 0xeedd, 0xbb77,  0x8888, 0x8888, 0x8888, 0x8888,
872
24.8k
      0xb130, 0x031b, 0xd8c0, 0x0c8d,  0x8010, 0x0220, 0x0108, 0x4004,  0xff88, 0x8888, 0xff88, 0x8888,  0xff80, 0x8080, 0xff08, 0x0808,
873
24.8k
      0x0000, 0x0002, 0x0000, 0x0002,  0x8040, 0x2000, 0x0204, 0x0800,  0x8244, 0x3944, 0x8201, 0x0101,  0xf874, 0x2247, 0x8f17, 0x2271,
874
24.8k
      0x55a0, 0x4040, 0x550a, 0x0404,  0x2050, 0x8888, 0x8888, 0x0502,  0xbf00, 0xbfbf, 0xb0b0, 0xb0b0,  0x0000, 0x0000, 0x0000, 0x0000,
875
24.8k
      0x8000, 0x0800, 0x8000, 0x0800,  0x8800, 0x2200, 0x8800, 0x2200,  0x8822, 0x8822, 0x8822, 0x8822,  0xaa00, 0xaa00, 0xaa00, 0xaa00,
876
24.8k
      0x00ff, 0x00ff, 0x00ff, 0x00ff,  0x1122, 0x4488, 0x1122, 0x4488,  0x8040, 0x2000, 0x0204, 0x0800,  0x0102, 0x0408, 0x1020, 0x4080,
877
24.8k
      0xaa00, 0x8000, 0x8800, 0x8000,  0xff80, 0x8080, 0x8080, 0x8080,  0x0814, 0x2241, 0x8001, 0x0204,  0x8814, 0x2241, 0x8800, 0xaa00,
878
24.8k
      0x40a0, 0x0000, 0x040a, 0x0000,  0x0384, 0x4830, 0x0c02, 0x0101,  0x8080, 0x413e, 0x0808, 0x14e3,  0x1020, 0x54aa, 0xff02, 0x0408,
879
24.8k
      0x7789, 0x8f8f, 0x7798, 0xf8f8,  0x0008, 0x142a, 0x552a, 0x1408,  0x0000, 0x0000, 0x0000, 0x0000,
880
24.8k
    };
881
24.8k
    m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(-1,Pattern(39, valuesV2)));
882
24.8k
  }
883
36.8k
  static uint16_t const values4002[] = {
884
36.8k
    0xffff, 0xffff, 0xffff, 0xffff,  0x7fff, 0xffff, 0xf7ff, 0xffff,  0x7fff, 0xf7ff, 0x7fff, 0xf7ff,  0x77ff, 0xddff, 0x77ff, 0xddff,
885
36.8k
    0x55ff, 0xddff, 0x55ff, 0xddff,  0x55ff, 0xeeff, 0x55ff, 0xbbff,  0x55ff, 0x55ff, 0x55ff, 0x55ff,  0x77dd, 0x77dd, 0x77dd, 0x77dd,
886
36.8k
    0x55bf, 0x55ff, 0x55fb, 0x55ff,  0x55bb, 0x55ff, 0x55bb, 0x55ff,  0x55bf, 0x55ee, 0x55fb, 0x55ee,  0x55bb, 0x55ee, 0x55bb, 0x55ee,
887
36.8k
    0x55bb, 0x55ea, 0x55bb, 0x55ae,  0x55ba, 0x55ab, 0x55ba, 0x55ab,  0x55ea, 0x55aa, 0x55ae, 0x55aa,  0xaa55, 0xaa55, 0xaa55, 0xaa55,
888
36.8k
    0xaa15, 0xaa55, 0xaa51, 0xaa55,  0xaa45, 0xaa54, 0xaa45, 0xaa54,  0xaa44, 0xaa15, 0xaa44, 0xaa51,  0xaa44, 0xaa11, 0xaa44, 0xaa11,
889
36.8k
    0xaa40, 0xaa11, 0xaa04, 0xaa11,  0xaa44, 0xaa00, 0xaa44, 0xaa00,  0xaa40, 0xaa00, 0xaa04, 0xaa00,  0x8822, 0x8822, 0x8822, 0x8822,
890
36.8k
    0xaa00, 0xaa00, 0xaa00, 0xaa00,  0xaa00, 0x1100, 0xaa00, 0x4400,  0xaa00, 0x2200, 0xaa00, 0x2200,  0x8800, 0x2200, 0x8800, 0x2200,
891
36.8k
    0x8800, 0x2000, 0x8800, 0x0200,  0x8000, 0x0800, 0x8000, 0x0800,  0x8000, 0x0000, 0x0800, 0x0000,  0x0000, 0x0000, 0x0000, 0x0000
892
36.8k
  };
893
36.8k
  m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(4002,Pattern(32, values4002)));
894
36.8k
  static uint16_t const values4003[] = {
895
36.8k
    0x0000, 0x0000, 0x0000, 0x0000,  0x8000, 0x0000, 0x0800, 0x0000,  0x8000, 0x0800, 0x8000, 0x0800,  0x8800, 0x2000, 0x8800, 0x0200,
896
36.8k
    0x8800, 0x2200, 0x8800, 0x2200,  0xaa00, 0x2200, 0xaa00, 0x2200,  0xaa00, 0x1100, 0xaa00, 0x4400,  0xaa00, 0xaa00, 0xaa00, 0xaa00,
897
36.8k
    0x8822, 0x8822, 0x8822, 0x8822,  0xaa44, 0xaa11, 0xaa44, 0xaa11,  0xaa45, 0xaa54, 0xaa45, 0xaa54,  0xaa55, 0xaa55, 0xaa55, 0xaa55,
898
36.8k
    0x55ea, 0x55aa, 0x55ae, 0x55aa,  0x55ba, 0x55ab, 0x55ba, 0x55ab,  0x55bb, 0x55ee, 0x55bb, 0x55ee,  0x77dd, 0x77dd, 0x77dd, 0x77dd,
899
36.8k
    0x55ff, 0x55ff, 0x55ff, 0x55ff,  0x55ff, 0xeeff, 0x55ff, 0xbbff,  0x77ff, 0xddff, 0x77ff, 0xddff,  0x7fff, 0xf7ff, 0x7fff, 0xf7ff,
900
36.8k
    0x7fff, 0xffff, 0xf7ff, 0xffff,  0xffff, 0xffff, 0xffff, 0xffff
901
36.8k
  };
902
36.8k
  m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(4003,Pattern(22, values4003)));
903
36.8k
  static uint16_t const values4004[] = {
904
36.8k
    0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f,  0xcccc, 0x3333, 0xcccc, 0x3333,  0x3333, 0xcccc, 0x3333, 0xcccc
905
36.8k
  };
906
36.8k
  m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(4004,Pattern(3, values4004)));
907
36.8k
  static uint16_t const values7000[] = {
908
36.8k
    0x0101, 0x1010, 0x0101, 0x1010,  0xcc00, 0x0000, 0x3300, 0x0000,  0x1122, 0x4400, 0x1122, 0x4400,  0x4422, 0x0088, 0x4422, 0x0088,
909
36.8k
    0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f,  0x9966, 0x6699, 0x9966, 0x6699,  0x0008, 0x1c3e, 0x7f3e, 0x1c08,  0x0008, 0x142a, 0x552a, 0x1408,
910
36.8k
    0xb130, 0x031b, 0xd8c0, 0x0c8d,  0x8010, 0x0220, 0x0108, 0x4004,  0x0814, 0x2241, 0x8001, 0x0204,  0x80c0, 0x2112, 0x0c04, 0x0201,
911
36.8k
    0xff80, 0x8080, 0xff08, 0x0808,  0x007f, 0x7f7f, 0x00f7, 0xf7f7,  0x8040, 0x2000, 0x0204, 0x0800,  0x8244, 0x3944, 0x8201, 0x0101,
912
36.8k
    0xf078, 0x2442, 0x870f, 0x1221,  0x1020, 0x54aa, 0xff02, 0x0408,  0xf874, 0x2247, 0x8f17, 0x2271,  0xbfa0, 0xbfbd, 0xbdfd, 0x05fd,
913
36.8k
    0x2050, 0x8888, 0x8888, 0x0502,  0x55a0, 0x4040, 0x550a, 0x0404,  0x8844, 0x2211, 0x1122, 0x4488,  0x8142, 0x2418, 0x8142, 0x2418,
914
36.8k
    0xaa00, 0x8000, 0x8800, 0x8000,  0x0384, 0x4830, 0x0c02, 0x0101,  0x8080, 0x413e, 0x0808, 0x14e3,  0xaf5f, 0xaf5f, 0x0d0b, 0x0d0b,
915
36.8k
    0x7789, 0x8f8f, 0x7798, 0xf8f8,  0x8814, 0x2241, 0x8800, 0xaa00,  0x40a0, 0x0000, 0x040a, 0x0000,  0xbf00, 0xbfbf, 0xb0b0, 0xb0b0
916
36.8k
  };
917
36.8k
  m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(7000,Pattern(32, values7000)));
918
36.8k
  static uint16_t const values14001[] = {
919
36.8k
    0x8844, 0x2211, 0x8844, 0x2211,  0x77bb, 0xddee, 0x77bb, 0xddee,  0x1122, 0x4488, 0x1122, 0x4488,  0xeedd, 0xbb77, 0xeedd, 0xbb77,
920
36.8k
    0x8040, 0x2010, 0x0804, 0x0201,  0x7fbf, 0xdfef, 0xf7fb, 0xfdfe,  0x0102, 0x0408, 0x1020, 0x4080,  0xfefd, 0xfbf7, 0xefdf, 0xbf7f,
921
36.8k
    0xe070, 0x381c, 0x0e07, 0x83c1,  0x99cc, 0x6633, 0x99cc, 0x6633,  0x8307, 0x0e1c, 0x3870, 0xe0c1,  0x3366, 0xcc99, 0x3366, 0xcc99,
922
36.8k
    0x8142, 0x2418, 0x1824, 0x4281,  0x7ebd, 0xdbe7, 0xe7db, 0xbd7e,  0x8244, 0x2810, 0x2844, 0x8201,  0x7dbb, 0xd7ef, 0xd7bb, 0x7dfe,
923
36.8k
    0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,  0x00ff, 0x00ff, 0x00ff, 0x00ff,  0x8888, 0x8888, 0x8888, 0x8888,  0x7777, 0x7777, 0x7777, 0x7777,
924
36.8k
    0xff00, 0x0000, 0xff00, 0x0000,  0x00ff, 0xffff, 0x00ff, 0xffff,  0x8080, 0x8080, 0x8080, 0x8080,  0x7f7f, 0x7f7f, 0x7f7f, 0x7f7f,
925
36.8k
    0xff00, 0x0000, 0x0000, 0x0000,  0x00ff, 0xffff, 0xffff, 0xffff,  0xcccc, 0xcccc, 0xcccc, 0xcccc,  0xffff, 0x0000, 0xffff, 0x0000,
926
36.8k
    0xff88, 0x8888, 0xff88, 0x8888,  0x0077, 0x7777, 0x0077, 0x7777,  0xff80, 0x8080, 0x8080, 0x8080,  0x007f, 0x7f7f, 0x7f7f, 0x7f7f
927
36.8k
  };
928
36.8k
  m_rsrcPatternMap.insert(std::map<long, Pattern>::value_type(14001,Pattern(32, values14001)));
929
36.8k
}
930
931
float State::getPatternPercent(int id, long rsid)
932
2.47M
{
933
2.47M
  if (m_rsrcPatternMap.empty())
934
24.8k
    initPattern(m_version);
935
2.47M
  if (m_rsrcPatternMap.find(rsid)==m_rsrcPatternMap.end()) {
936
0
    MWAW_DEBUG_MSG(("MsWksGraphInternal::State::getPatternPercent unknown map for rsdid=%ld\n",rsid));
937
0
    return 1.0;
938
0
  }
939
2.47M
  return m_rsrcPatternMap.find(rsid)->second.getPercent(id);
940
2.47M
}
941
942
bool State::getPattern(MWAWGraphicStyle::Pattern &pat, int id, long rsid)
943
12.3M
{
944
12.3M
  if (m_rsrcPatternMap.empty())
945
11.9k
    initPattern(m_version);
946
12.3M
  if (m_rsrcPatternMap.find(rsid)==m_rsrcPatternMap.end()) {
947
10.6M
    MWAW_DEBUG_MSG(("MsWksGraphInternal::State::getPattern unknown map for rsdid=%ld\n",rsid));
948
10.6M
    return false;
949
10.6M
  }
950
1.72M
  return m_rsrcPatternMap.find(rsid)->second.get(id, pat);
951
12.3M
}
952
953
////////////////////////////////////////
954
//! Internal: the subdocument of a MsWksGraph
955
class SubDocument final : public MWAWSubDocument
956
{
957
public:
958
  enum Type { RBILZone, Chart, Empty, Group, Table, TextBox, TextBoxv4 };
959
  SubDocument(MsWksGraph &pars, MWAWInputStreamPtr const &input, Type type, int zoneId)
960
25.8k
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
961
25.8k
    , m_graphParser(&pars)
962
25.8k
    , m_type(type)
963
25.8k
    , m_id(zoneId)
964
25.8k
    , m_frame("")
965
25.8k
  {
966
25.8k
  }
967
  SubDocument(MsWksGraph &pars, MWAWInputStreamPtr const &input, Type type,
968
              MWAWEntry const &entry, std::string const &frame=std::string(""))
969
174k
    : MWAWSubDocument(pars.m_mainParser, input, entry)
970
174k
    , m_graphParser(&pars)
971
174k
    , m_type(type)
972
174k
    , m_id(-1)
973
174k
    , m_frame(frame)
974
174k
  {
975
174k
  }
976
977
  //! destructor
978
200k
  ~SubDocument() final {}
979
980
  //! operator!=
981
  bool operator!=(MWAWSubDocument const &doc) const final;
982
983
  //! the parser function
984
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
985
private:
986
  SubDocument(SubDocument const &orig) = delete;
987
  SubDocument &operator=(SubDocument const &orig) = delete;
988
989
protected:
990
  /** the graph parser */
991
  MsWksGraph *m_graphParser;
992
  /** the type */
993
  Type m_type;
994
  /** the subdocument id*/
995
  int m_id;
996
  /** the frame name: for textv4 */
997
  std::string m_frame;
998
};
999
1000
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
1001
200k
{
1002
200k
  if (!listener.get()) {
1003
0
    MWAW_DEBUG_MSG(("MsWksGraphInternal::SubDocument::parse: no listener\n"));
1004
0
    return;
1005
0
  }
1006
200k
  if (!m_graphParser) {
1007
0
    MWAW_DEBUG_MSG(("MsWksGraphInternal::SubDocument::parse: no parser\n"));
1008
0
    return;
1009
0
  }
1010
1011
200k
  long pos = m_input->tell();
1012
200k
  switch (m_type) {
1013
0
  case Empty:
1014
0
    break;
1015
364
  case Chart:
1016
364
    m_graphParser->sendChart(m_id);
1017
364
    break;
1018
737
  case Group: {
1019
737
    MWAWPosition gPos;
1020
737
    gPos.setRelativePosition(MWAWPosition::Frame,
1021
737
                             MWAWPosition::XLeft, MWAWPosition::YTop);
1022
737
    m_graphParser->sendGroupChild(m_id, gPos);
1023
737
    break;
1024
0
  }
1025
0
  case Table:
1026
0
    m_graphParser->sendTable(m_id);
1027
0
    break;
1028
24.7k
  case TextBox:
1029
24.7k
    m_graphParser->sendTextBox(m_id, listener);
1030
24.7k
    break;
1031
174k
  case TextBoxv4:
1032
174k
    m_graphParser->sendFrameText(m_zone, m_frame);
1033
174k
    break;
1034
0
  case RBILZone: {
1035
0
    MsWksGraph::SendData sendData;
1036
0
    sendData.m_type = MsWksGraph::SendData::RBIL;
1037
0
    sendData.m_id = m_id;
1038
0
    sendData.m_anchor =  MWAWPosition::Frame;
1039
0
    m_graphParser->sendObjects(sendData);
1040
0
    break;
1041
0
  }
1042
#if !defined(__clang__)
1043
  default:
1044
    MWAW_DEBUG_MSG(("MsWksGraph::SubDocument::parse: unexpected zone type\n"));
1045
    break;
1046
#endif
1047
200k
  }
1048
200k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
1049
200k
}
1050
1051
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
1052
139k
{
1053
139k
  if (MWAWSubDocument::operator!=(doc)) return true;
1054
18.5k
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
1055
18.5k
  if (!sDoc) return true;
1056
0
  if (m_graphParser != sDoc->m_graphParser) return true;
1057
0
  if (m_id != sDoc->m_id) return true;
1058
0
  if (m_type != sDoc->m_type) return true;
1059
0
  if (m_frame != sDoc->m_frame) return true;
1060
0
  return false;
1061
0
}
1062
1063
}
1064
1065
////////////////////////////////////////////////////////////
1066
// constructor/destructor, ...
1067
////////////////////////////////////////////////////////////
1068
MsWksGraph::MsWksGraph(MsWksDocument &document)
1069
287k
  : m_parserState()
1070
287k
  , m_state(new MsWksGraphInternal::State)
1071
287k
  , m_mainParser(&document.getMainParser())
1072
287k
  , m_document(document)
1073
287k
  , m_tableParser()
1074
287k
{
1075
287k
  m_parserState=m_mainParser->getParserState();
1076
287k
  m_tableParser.reset(new MsWksTable(*m_mainParser, m_document, *this));
1077
287k
}
1078
1079
MsWksGraph::~MsWksGraph()
1080
287k
{
1081
287k
}
1082
1083
void MsWksGraph::setPageLeftTop(MWAWVec2f const &leftTop)
1084
74.0k
{
1085
74.0k
  m_state->m_leftTopPos=leftTop;
1086
74.0k
}
1087
1088
int MsWksGraph::version() const
1089
109M
{
1090
109M
  if (m_state->m_version < 0)
1091
77.4k
    m_state->m_version = m_parserState->m_version;
1092
109M
  return m_state->m_version;
1093
109M
}
1094
1095
int MsWksGraph::numPages(int zoneId) const
1096
77.5k
{
1097
77.5k
  if (m_state->m_numPages > 0)
1098
3.48k
    return m_state->m_numPages;
1099
1100
74.0k
  int maxPage = 0;
1101
1.24M
  for (auto const &zone : m_state->m_zonesList) {
1102
1.24M
    if (zoneId >= 0 && zone->m_zoneId!=zoneId) continue;
1103
1.12M
    if (zone->m_page > maxPage)
1104
8.37k
      maxPage = zone->m_page;
1105
1.12M
  }
1106
74.0k
  m_state->m_numPages = maxPage+1;
1107
74.0k
  return m_state->m_numPages;
1108
77.5k
}
1109
1110
void MsWksGraph::sendFrameText(MWAWEntry const &entry, std::string const &frame)
1111
174k
{
1112
174k
  m_document.sendTextbox(entry, frame);
1113
174k
}
1114
1115
void MsWksGraph::sendChart(int zoneId)
1116
364
{
1117
364
  m_tableParser->sendChart(zoneId);
1118
364
}
1119
1120
void MsWksGraph::sendTable(int zoneId)
1121
0
{
1122
0
  m_tableParser->sendTable(zoneId);
1123
0
}
1124
1125
////////////////////////////////////////////////////////////
1126
//
1127
// Intermediate level
1128
//
1129
////////////////////////////////////////////////////////////
1130
bool MsWksGraph::getZoneGraphicStyle(int id, MWAWGraphicStyle &style) const
1131
0
{
1132
0
  if (id<0 || id>=int(m_state->m_zonesList.size()) || !m_state->m_zonesList[size_t(id)]) {
1133
0
    MWAW_DEBUG_MSG(("MsWksGraph::getZoneGraphicStyle: unknown zone %d\n", id));
1134
0
    return false;
1135
0
  }
1136
0
  style = m_state->m_zonesList[size_t(id)]->m_style;
1137
0
  return true;
1138
0
}
1139
1140
bool MsWksGraph::getZonePosition(int id, MWAWPosition::AnchorTo anchor, MWAWPosition &pos) const
1141
1.45k
{
1142
1.45k
  if (id<0 || id>=int(m_state->m_zonesList.size()) || !m_state->m_zonesList[size_t(id)]) {
1143
0
    MWAW_DEBUG_MSG(("MsWksGraph::getZoneGraphicStyle: unknown zone %d\n", id));
1144
0
    return false;
1145
0
  }
1146
1.45k
  pos = m_state->m_zonesList[size_t(id)]->getPosition(anchor);
1147
1.45k
  return true;
1148
1.45k
}
1149
1150
bool MsWksGraph::readPictHeader(MsWksGraphInternal::Zone &pict)
1151
53.4M
{
1152
53.4M
  MWAWInputStreamPtr input=m_document.getInput();
1153
53.4M
  long pos=input->tell();
1154
53.4M
  int vers = version();
1155
53.4M
  if (!input->checkPosition(pos+(vers>=3 ? 54 : 38)) || input->readULong(1) != 0) return false;
1156
43.4M
  pict = MsWksGraphInternal::Zone();
1157
43.4M
  pict.m_subType = static_cast<int>(input->readULong(1));
1158
43.4M
  if (pict.m_subType > 0x10 || pict.m_subType == 6 || pict.m_subType == 0xb)
1159
1.78M
    return false;
1160
41.6M
  if (pict.m_subType>9) {
1161
16.2M
    if (vers<=2)
1162
3.30k
      return false;
1163
    // we can find chart in v3 spreadsheet file
1164
16.2M
    else if (vers==3 && pict.m_subType != 0xa && m_parserState->m_type!=MWAWParserState::Spreadsheet)
1165
512k
      return false;
1166
16.2M
  }
1167
41.1M
  libmwaw::DebugStream f;
1168
41.1M
  int val;
1169
41.1M
  if (vers >= 3) {
1170
40.2M
    val = static_cast<int>(input->readLong(2));
1171
40.2M
    if (vers == 4 || m_parserState->m_type==MWAWParserState::Graphic)
1172
29.0M
      pict.m_page = val==0 ? -2 : val-1;
1173
11.1M
    else if (val)
1174
7.37M
      f << "f0=" << val << ",";
1175
40.2M
  }
1176
  // color
1177
41.1M
  Style &style=pict.m_style;
1178
123M
  for (int i = 0; i < 2; i++) {
1179
82.2M
    auto rId = static_cast<int>(input->readLong(2));
1180
82.2M
    int cId = (vers <= 2) ? rId+1 : rId;
1181
82.2M
    MWAWColor col;
1182
82.2M
    if (m_document.getColor(cId,col,vers <= 3 ? vers : 3)) {
1183
24.2M
      if (i) style.m_baseSurfaceColor = col;
1184
9.85M
      else style.m_baseLineColor = col;
1185
24.2M
    }
1186
58.0M
    else
1187
58.0M
      f << "#col" << i << "=" << rId << ",";
1188
82.2M
  }
1189
41.1M
  bool hasSurfPatFunction=false;
1190
41.1M
  if (vers <= 2) {
1191
2.72M
    for (int i = 0; i < 2; i++) {
1192
1.81M
      auto pId = static_cast<int>(input->readLong(2));
1193
1.81M
      if (pId==38) { // empty
1194
6.17k
        if (i==0)
1195
4.91k
          style.m_lineWidth=0;
1196
6.17k
        continue;
1197
6.17k
      }
1198
1.80M
      float percent = m_state->getPatternPercent(pId);
1199
1.80M
      MWAWGraphicStyle::Pattern pattern;
1200
1.80M
      if (i==0)
1201
902k
        style.m_lineColor=MWAWColor::barycenter(percent, style.m_baseLineColor, 1.f-percent, style.m_baseSurfaceColor);
1202
905k
      else if (m_state->getPattern(pattern, pId)) {
1203
755k
        pattern.m_colors[0] = style.m_baseSurfaceColor;
1204
755k
        pattern.m_colors[1] = style.m_baseLineColor;
1205
755k
        style.setPattern(pattern);
1206
755k
      }
1207
150k
      else
1208
150k
        style.setSurfaceColor(MWAWColor::barycenter(percent, style.m_baseLineColor, 1.f-percent, style.m_baseSurfaceColor));
1209
1.80M
    }
1210
907k
    auto lineType=static_cast<int>(input->readLong(2));
1211
907k
    if (style.m_lineWidth>0) {
1212
902k
      switch (lineType) {
1213
701k
      case 0:
1214
701k
        style.m_lineWidth=0.;
1215
701k
        break;
1216
14.1k
      case 1:
1217
14.1k
        style.m_lineWidth=0.5;
1218
14.1k
        break;
1219
12.2k
      case 2: // lineW=1
1220
12.2k
        break;
1221
26.5k
      case 3:
1222
26.5k
        style.m_lineWidth=2;
1223
26.5k
        break;
1224
4.95k
      case 4:
1225
4.95k
        style.m_lineWidth=4;
1226
4.95k
        break;
1227
143k
      default:
1228
143k
        f << "#lineType=" << lineType << ",";
1229
143k
        break;
1230
902k
      }
1231
902k
    }
1232
907k
  }
1233
40.2M
  else {
1234
40.2M
    style.m_lineColor=style.m_baseLineColor;
1235
40.2M
    style.m_surfaceColor=style.m_baseSurfaceColor;
1236
120M
    for (int i = 0; i < 2; i++) {
1237
80.4M
      if (i) f << "surface";
1238
40.2M
      else f << "line";
1239
80.4M
      f << "Pattern=[";
1240
80.4M
      long rsid= input->readLong(2);
1241
80.4M
      if (rsid==0) f << "noColor,";
1242
56.4M
      else if (rsid==-1) f << "grad,";
1243
45.9M
      else f << "rsid=" << rsid << ",";
1244
80.4M
      auto patId = static_cast<int>(input->readULong(2));
1245
80.4M
      if (patId) f << "pat=" << patId << ",";
1246
25.1M
      else f << "_";
1247
80.4M
      if (vers==4 && rsid==-1 && patId==0xFFFF)
1248
5.78M
        hasSurfPatFunction=true;
1249
80.4M
      val = static_cast<int>(input->readLong(1));
1250
80.4M
      if (val) f << "unkn=" << val << ",";
1251
80.4M
      auto per = static_cast<int>(input->readULong(1));
1252
80.4M
      f << per << "%,";
1253
80.4M
      if (rsid<=0) {
1254
42.9M
        if (i==0 && rsid==0)
1255
13.4M
          style.m_lineWidth=0.;
1256
42.9M
      }
1257
37.4M
      else {
1258
37.4M
        float percent=1.0;
1259
37.4M
        bool done=false;
1260
37.4M
        MWAWGraphicStyle::Pattern pattern;
1261
37.4M
        if (per >= 0 && per < 100)
1262
26.0M
          percent = float(per)/100.f;
1263
11.4M
        else if (m_state->getPattern(pattern, patId, rsid)) {
1264
663k
          percent = m_state->getPatternPercent(patId, rsid);
1265
663k
          if (i) {
1266
294k
            pattern.m_colors[0] = style.m_baseSurfaceColor;
1267
294k
            pattern.m_colors[1] = style.m_baseLineColor;
1268
294k
            style.setPattern(pattern);
1269
294k
            done = true;
1270
294k
          }
1271
663k
        }
1272
10.8M
        else {
1273
10.8M
          MWAW_DEBUG_MSG(("MsWksGraph::readPictHeader:find odd pattern\n"));
1274
10.8M
          f << "##";
1275
10.8M
        }
1276
37.4M
        if (done) {
1277
294k
        }
1278
37.2M
        else if (i==0)
1279
17.9M
          style.m_lineColor=MWAWColor::barycenter(percent, style.m_baseLineColor, 1.f-percent, style.m_baseSurfaceColor);
1280
19.3M
        else
1281
19.3M
          style.setSurfaceColor(MWAWColor::barycenter(percent, style.m_baseLineColor, 1.f-percent, style.m_baseSurfaceColor));
1282
37.4M
      }
1283
80.4M
      f << "],";
1284
80.4M
    }
1285
40.2M
    int penSize[2];
1286
80.4M
    for (auto &pSize : penSize) pSize = static_cast<int>(input->readLong(2));
1287
40.2M
    if (style.m_lineWidth<=0)
1288
13.4M
      f << "pen=" << penSize[0] << "x" << penSize[1] << ",";
1289
26.7M
    else if (penSize[0]==penSize[1])
1290
7.62M
      style.m_lineWidth=float(penSize[0]);
1291
19.1M
    else {
1292
19.1M
      f << "pen=" << penSize[0] << "x" << penSize[1] << ",";
1293
19.1M
      style.m_lineWidth=0.5f*float(penSize[0]+penSize[1]);
1294
19.1M
    }
1295
40.2M
    if (style.m_lineWidth < 0 || style.m_lineWidth > 10) {
1296
21.6M
      f << "##penSize=" << style.m_lineWidth << ",";
1297
21.6M
      style.m_lineWidth = 1;
1298
21.6M
    }
1299
40.2M
    val = static_cast<int>(input->readLong(2));
1300
40.2M
    if (val)
1301
23.9M
      f << "f1=" << val << ",";
1302
40.2M
  }
1303
1304
41.1M
  float offset[4];
1305
164M
  for (auto &off : offset) off = float(input->readLong(2));
1306
41.1M
  pict.m_decal = MWAWBox2f(MWAWVec2f(offset[0],offset[1]), MWAWVec2f(offset[3],offset[2]));
1307
41.1M
  pict.m_finalDecal = MWAWVec2f(float(offset[0]+offset[3]), float(offset[1]+offset[2]));
1308
1309
  // the two point which allows to create the form ( in general the bdbox)
1310
41.1M
  float dim[4];
1311
164M
  for (auto &d : dim) d = float(input->readLong(4))/65536.f;
1312
41.1M
  pict.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
1313
1314
41.1M
  auto flags = static_cast<int>(input->readLong(1));
1315
  // 2: rotations, 1:lock ?, 0: nothing, other ?
1316
41.1M
  if (vers >= 4 && (flags&1)) {
1317
8.51M
    f << "locked,";
1318
8.51M
    flags &= 0xFE;
1319
8.51M
  }
1320
41.1M
  if (vers >= 4 && (flags&2)) {
1321
5.99M
    f << "Rot=[";
1322
197M
    for (int i = 0; i < 32; i++)
1323
191M
      f << input->readLong(2) << ",";
1324
5.99M
    f << "],";
1325
5.99M
    flags &= 0xFC;
1326
5.99M
  }
1327
41.1M
  if (flags) f << "fl0=" << flags << ",";
1328
41.1M
  auto lineFlags = static_cast<int>(input->readULong(1));
1329
41.1M
  switch (lineFlags&3) {
1330
4.48M
  case 2:
1331
4.48M
    style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
1332
4.48M
    MWAW_FALLTHROUGH;
1333
10.4M
  case 1:
1334
10.4M
    style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
1335
10.4M
    break;
1336
4.49M
  default:
1337
4.49M
    f << "#arrow=3,";
1338
4.49M
    break;
1339
26.1M
  case 0:
1340
26.1M
    break;
1341
41.1M
  }
1342
41.1M
  if (lineFlags&0xFC) f << "#lineFlags=" << std::hex << (lineFlags&0xFC) << std::dec << ",";
1343
41.1M
  if (vers >= 3) pict.m_ids[0] = long(input->readULong(4));
1344
41.1M
  if (vers >= 4 && hasSurfPatFunction) {
1345
4.08M
    pos = input->tell();
1346
4.08M
    if (!readGradient(style)) {
1347
851k
      f << "##gradient,";
1348
851k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1349
851k
    }
1350
4.08M
  }
1351
41.1M
  pict.m_extra = f.str();
1352
41.1M
  pict.m_dataPos = input->tell();
1353
41.1M
  return true;
1354
41.1M
}
1355
1356
bool MsWksGraph::readGradient(MsWksGraph::Style &style)
1357
4.08M
{
1358
4.08M
  MWAWInputStreamPtr input=m_document.getInput();
1359
4.08M
  long pos = input->tell();
1360
1361
4.08M
  if (!input->checkPosition(pos+22))
1362
851k
    return false;
1363
1364
3.23M
  libmwaw::DebugStream f;
1365
3.23M
  f << "gradient[unknown]=[";
1366
3.23M
  auto type=static_cast<int>(input->readLong(2));
1367
3.23M
  auto val=static_cast<int>(input->readLong(2)); // always 0?
1368
3.23M
  if (val) f << "f0=" << val << ",";
1369
3.23M
  val=static_cast<int>(input->readLong(1)); // always 8?
1370
3.23M
  if (val!=8) f << "f1=" << val << ",";
1371
3.23M
  val=static_cast<int>(input->readLong(2)); // find 1 in square
1372
3.23M
  if (val) f << "f2=" << val << ",";
1373
3.23M
  val=static_cast<int>(input->readULong(2)); // always 0 ?
1374
3.23M
  if (val) f << "f3=" << std::hex << val << std::dec << ",";
1375
3.23M
  auto angle =static_cast<int>(input->readLong(2));
1376
3.23M
  val=static_cast<int>(input->readLong(2)); // 89[square]|156[square:linearbi]|255
1377
3.23M
  if (val!=0xff) f << "f4=" << val << ",";
1378
3.23M
  val=static_cast<int>(input->readLong(2)); // 54[square]|0
1379
3.23M
  if (val) f << "f5=" << val << ",";
1380
3.23M
  val=static_cast<int>(input->readLong(2)); // 18
1381
3.23M
  if (val!=0x18) f << "f6=" << val << ",";
1382
3.23M
  val=static_cast<int>(input->readULong(2));
1383
3.23M
  int subType = (val&0xf);
1384
3.23M
  val = (val>>4);
1385
3.23M
  if (val!=0xFF)
1386
3.23M
    f << "sType[high]=" << std::hex << val << std::dec << ",";
1387
3.23M
  val=static_cast<int>(input->readLong(2)); // 0
1388
3.23M
  if (val) f << "f7=" << val << ",";
1389
3.23M
  val=static_cast<int>(input->readLong(1)); // 0
1390
3.23M
  if (val) f << "f8=" << val << ",";
1391
3.23M
  f << "],";
1392
3.23M
  auto &finalGrad=style.m_gradient;
1393
3.23M
  switch (type) {
1394
289k
  case 1:
1395
289k
    finalGrad.m_stopList.resize(2);
1396
289k
    finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, style.m_baseSurfaceColor);
1397
289k
    finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, style.m_baseLineColor);
1398
289k
    finalGrad.m_angle = float(90+angle);
1399
289k
    finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Linear;
1400
289k
    angle=type=0;
1401
289k
    break;
1402
394k
  case 2:
1403
394k
    finalGrad.m_stopList.resize(2);
1404
394k
    finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, style.m_baseSurfaceColor);
1405
394k
    finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, style.m_baseLineColor);
1406
394k
    finalGrad.m_angle = float(90+angle);
1407
394k
    finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Axial;
1408
394k
    angle=type=0;
1409
394k
    break;
1410
254k
  case 3:
1411
254k
    finalGrad.m_stopList.resize(2);
1412
254k
    finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, style.m_baseSurfaceColor);
1413
254k
    finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, style.m_baseLineColor);
1414
254k
    switch (subType) {
1415
48.4k
    case 9:
1416
48.4k
      finalGrad.m_percentCenter=MWAWVec2f(0.25f,0.25f);
1417
48.4k
      break;
1418
4.90k
    case 10:
1419
4.90k
      finalGrad.m_percentCenter=MWAWVec2f(0.25f,0.75f);
1420
4.90k
      break;
1421
42.5k
    case 11:
1422
42.5k
      finalGrad.m_percentCenter=MWAWVec2f(0.75f,0.75f);
1423
42.5k
      break;
1424
3.69k
    case 12:
1425
3.69k
      finalGrad.m_percentCenter=MWAWVec2f(1.f,1.f);
1426
3.69k
      break;
1427
63.3k
    case 13:
1428
63.3k
      finalGrad.m_percentCenter=MWAWVec2f(0.f,0.f);
1429
63.3k
      break;
1430
91.1k
    default:
1431
91.1k
      f << "#subType=" << subType << ",";
1432
91.1k
      break;
1433
127
    case 8: // centered
1434
127
      break;
1435
254k
    }
1436
254k
    finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Rectangular;
1437
254k
    angle=type=0;
1438
254k
    break;
1439
332k
  case 7:
1440
332k
    finalGrad.m_stopList.resize(2);
1441
332k
    finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, style.m_baseSurfaceColor);
1442
332k
    finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, style.m_baseLineColor);
1443
332k
    finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Radial;
1444
332k
    type = 0;
1445
332k
    break;
1446
1.96M
  default:
1447
1.96M
    break;
1448
3.23M
  }
1449
3.23M
  if (type) f << "#type=" << type << ",";
1450
3.23M
  if (angle) f << "#angle=" << angle << ",";
1451
3.23M
  f << "subType=" << subType << ",";
1452
3.23M
  f << "],";
1453
3.23M
  style.m_extra = f.str();
1454
3.23M
  return true;
1455
3.23M
}
1456
1457
int MsWksGraph::getEntryPicture(int zoneId, MWAWEntry &zone, bool autoSend, int order)
1458
53.4M
{
1459
53.4M
  MsWksGraphInternal::Zone pict;
1460
53.4M
  MWAWInputStreamPtr input=m_document.getInput();
1461
53.4M
  long pos = input->tell();
1462
1463
53.4M
  if (!readPictHeader(pict))
1464
12.2M
    return -1;
1465
41.1M
  pict.m_zoneId = zoneId;
1466
41.1M
  pict.m_pos.setBegin(pos);
1467
41.1M
  libmwaw::DebugFile &ascFile = m_document.ascii();
1468
41.1M
  libmwaw::DebugStream f;
1469
41.1M
  int vers = version();
1470
41.1M
  long debData = input->tell();
1471
41.1M
  long dataSize = 0;
1472
41.1M
  int versSize = 0;
1473
41.1M
  switch (pict.m_subType) {
1474
9.18M
  case 0:
1475
10.5M
  case 1:
1476
11.8M
  case 2:
1477
12.2M
  case 3:
1478
12.2M
    dataSize = 1;
1479
12.2M
    break;
1480
726k
  case 4: // arc
1481
726k
    dataSize = 0xd;
1482
726k
    break;
1483
937k
  case 5: { // poly
1484
937k
    input->seek(3, librevenge::RVNG_SEEK_CUR);
1485
937k
    auto N = static_cast<int>(input->readULong(2));
1486
937k
    dataSize = 9+N*8;
1487
937k
    break;
1488
11.8M
  }
1489
560k
  case 7: { // picture
1490
560k
    if (vers >= 3) versSize = 0x14;
1491
560k
    dataSize = 5;
1492
560k
    input->seek(debData+5+versSize-2, librevenge::RVNG_SEEK_SET);
1493
560k
    dataSize += static_cast<int>(input->readULong(2));
1494
560k
    break;
1495
11.8M
  }
1496
1.36M
  case 8: // group
1497
1.36M
    if (vers >= 3) versSize = 4;
1498
1.36M
    dataSize = 0x1b;
1499
1.36M
    break;
1500
9.60M
  case 9: // textbox v<=3
1501
9.60M
    dataSize = 0x21;
1502
9.60M
    if (vers >= 3) dataSize += 0x10;
1503
9.60M
    break;
1504
7.35M
  case 0xa: // chart v4
1505
7.35M
    dataSize = 50;
1506
7.35M
    break;
1507
464k
  case 0xc: // equation v4
1508
464k
    dataSize = 0x11;
1509
464k
    break;
1510
2.66M
  case 0xd: { // bitmap v4
1511
2.66M
    input->seek(debData+0x29, librevenge::RVNG_SEEK_SET);
1512
2.66M
    auto sz = long(input->readULong(4));
1513
2.66M
    dataSize = 0x29+4+sz;
1514
2.66M
    break;
1515
11.8M
  }
1516
3.12M
  case 0xe: { // spreadsheet v4
1517
3.12M
    input->seek(debData+0xa7, librevenge::RVNG_SEEK_SET);
1518
3.12M
    auto pSize = static_cast<int>(input->readULong(2));
1519
3.12M
    if (pSize == 0) return -1;
1520
2.01M
    dataSize = 0xa9+pSize;
1521
2.01M
    if (!input->checkPosition(debData+dataSize))
1522
871k
      return -1;
1523
1524
1.13M
    input->seek(debData+dataSize, librevenge::RVNG_SEEK_SET);
1525
2.51M
    for (int i = 0; i < 2; i++) {
1526
1.92M
      auto sz = long(input->readULong(4));
1527
1.92M
      if (sz<0 || (sz>>28)) return -1;
1528
1.37M
      dataSize += 4 + sz;
1529
1.37M
      input->seek(sz, librevenge::RVNG_SEEK_CUR);
1530
1.37M
    }
1531
592k
    break;
1532
1.13M
  }
1533
592k
  case 0xf: { // textbox v4
1534
164k
    input->seek(debData+0x39, librevenge::RVNG_SEEK_SET);
1535
164k
    dataSize = 0x3b+ long(input->readULong(2));
1536
164k
    break;
1537
1.13M
  }
1538
1.92M
  case 0x10: { // table v4
1539
1.92M
    input->seek(debData+0x57, librevenge::RVNG_SEEK_SET);
1540
1.92M
    dataSize = 0x59+ long(input->readULong(2));
1541
1.92M
    input->seek(debData+dataSize, librevenge::RVNG_SEEK_SET);
1542
1543
6.63M
    for (int i = 0; i < 3; i++) {
1544
5.14M
      auto sz = long(input->readULong(4));
1545
5.14M
      if (sz<0 || ((sz>>28))) return -1;
1546
4.70M
      dataSize += 4 + sz;
1547
4.70M
      input->seek(sz, librevenge::RVNG_SEEK_CUR);
1548
4.70M
    }
1549
1550
1.48M
    break;
1551
1.92M
  }
1552
1.48M
  default:
1553
0
    MWAW_DEBUG_MSG(("MsWksGraph::getEntryPicture: type %d is not umplemented\n", pict.m_subType));
1554
0
    return -1;
1555
41.1M
  }
1556
1557
38.1M
  pict.m_pos.setEnd(debData+dataSize+versSize);
1558
38.1M
  if (!input->checkPosition(pict.m_pos.end()))
1559
9.95M
    return -1;
1560
1561
28.1M
  input->seek(debData, librevenge::RVNG_SEEK_SET);
1562
28.1M
  if (versSize) {
1563
546k
    switch (pict.m_subType) {
1564
144k
    case 7: {
1565
144k
      auto ptr = long(input->readULong(4));
1566
144k
      f << std::hex << "ptr2=" << ptr << std::dec << ",";
1567
144k
      f << "depth?=" << input->readLong(1) << ",";
1568
144k
      float dim[4];
1569
577k
      for (auto &d : dim) d = float(input->readLong(4))/65536.f;
1570
144k
      MWAWBox2f box(MWAWVec2f(dim[1], dim[0]), MWAWVec2f(dim[3], dim[2]));
1571
144k
      f << "bdbox2=" << box << ",";
1572
144k
      break;
1573
0
    }
1574
401k
    default:
1575
401k
      break;
1576
546k
    }
1577
546k
  }
1578
28.1M
  auto val = static_cast<int>(input->readLong(1)); // 0 and sometimes -1
1579
28.1M
  if (val) f << "g0=" << val << ",";
1580
28.1M
  pict.m_dataPos++;
1581
1582
28.1M
  if (pict.m_subType > 0xd) {
1583
970k
    f << ", " << std::hex << input->readULong(4) << std::dec << ", BdMWAWBox2=(";
1584
4.85M
    for (int i = 0; i < 4; i++)
1585
3.88M
      f << float(input->readLong(4))/65536.f << ", ";
1586
970k
    f << ")";
1587
970k
  }
1588
1589
28.1M
  std::shared_ptr<MsWksGraphInternal::Zone> res;
1590
28.1M
  switch (pict.m_subType) {
1591
7.43M
  case 0: { // line
1592
7.43M
    auto form = std::make_shared<MsWksGraphInternal::BasicShape>(pict);
1593
7.43M
    res = form;
1594
7.43M
    form->m_shape = MWAWGraphicShape::line(pict.m_box.min(), pict.m_box.max());
1595
7.43M
    break;
1596
0
  }
1597
417k
  case 1: // rect
1598
1.40M
  case 2: // rectoval
1599
1.72M
  case 3: { // circle
1600
1.72M
    MWAWBox2f bdbox = pict.m_box;
1601
1.72M
    auto form = std::make_shared<MsWksGraphInternal::BasicShape>(pict);
1602
1.72M
    res = form;
1603
1.72M
    form->m_shape.m_bdBox = form->m_shape.m_formBox = bdbox;
1604
1.72M
    form->m_shape.m_type = (pict.m_subType==3) ? MWAWGraphicShape::Circle :
1605
1.72M
                           MWAWGraphicShape::Rectangle;
1606
1.72M
    if (pict.m_subType==2) {
1607
984k
      float sz=10;
1608
984k
      if (bdbox.size().x() > 0 && bdbox.size().x() < 2*sz)
1609
247k
        sz = bdbox.size().x()/2.f;
1610
984k
      if (bdbox.size().y() > 0 && bdbox.size().y() < 2*sz)
1611
192k
        sz = bdbox.size().y()/2.f;
1612
984k
      form->m_shape.m_cornerWidth=MWAWVec2f(sz,sz);
1613
984k
    }
1614
1.72M
    break;
1615
1.40M
  }
1616
404k
  case 4: {
1617
404k
    auto form = std::make_shared<MsWksGraphInternal::BasicShape>(pict);
1618
404k
    res = form;
1619
404k
    auto angle = float(input->readLong(2));
1620
404k
    auto deltaAngle = float(input->readLong(2));
1621
404k
    float angl2 = angle+((deltaAngle>0) ? deltaAngle : -deltaAngle);
1622
404k
    float dim[4]; // real Bdbox
1623
1.61M
    for (auto &d : dim) d = float(input->readLong(2));
1624
404k
    MWAWBox2f realBox(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
1625
404k
    form->m_shape=MWAWGraphicShape::arc(realBox,pict.m_box,MWAWVec2f(450.f-angl2,450.f-angle));
1626
404k
    form->m_box = realBox;
1627
404k
    break;
1628
1.40M
  }
1629
434k
  case 5: {
1630
434k
    auto form = std::make_shared<MsWksGraphInternal::BasicShape>(pict);
1631
434k
    res = form;
1632
434k
    val = static_cast<int>(input->readULong(2));
1633
434k
    bool smooth=false;
1634
434k
    if (val==1)
1635
21.3k
      smooth=true;
1636
413k
    else if (val) f << "#smooth=" << val << ",";
1637
434k
    auto numPt = static_cast<int>(input->readLong(2));
1638
434k
    auto ptr = long(input->readULong(4));
1639
434k
    if (!input->checkPosition(input->tell()+8*numPt))
1640
1
      return -1;
1641
434k
    f << std::hex << "ptr2=" << ptr << std::dec << ",";
1642
434k
    std::vector<MWAWVec2f> vertices;
1643
3.21M
    for (int i = 0; i < numPt; i++) {
1644
2.77M
      float x = float(input->readLong(4))/65336.f;
1645
2.77M
      float y = float(input->readLong(4))/65336.f;
1646
2.77M
      vertices.push_back(MWAWVec2f(x,y));
1647
2.77M
    }
1648
434k
    if (!smooth || numPt <= 2) {
1649
430k
      form->m_shape=MWAWGraphicShape::polygon(pict.m_box);
1650
430k
      form->m_shape.m_vertices = vertices;
1651
430k
      break;
1652
430k
    }
1653
4.05k
    form->m_shape=MWAWGraphicShape::path(pict.m_box);
1654
4.05k
    form->m_shape.m_path.push_back(MWAWGraphicShape::PathData('M', vertices[0]));
1655
1656
4.05k
    MWAWVec2f middle=0.5f*(vertices[1]+vertices[0]);
1657
4.05k
    form->m_shape.m_path.push_back(MWAWGraphicShape::PathData('L', middle));
1658
1.35M
    for (size_t pt=1; pt+1 < size_t(numPt); ++pt) {
1659
1.34M
      middle=0.5f*(vertices[pt+1]+vertices[pt]);
1660
1.34M
      form->m_shape.m_path.push_back(MWAWGraphicShape::PathData('Q', middle, vertices[pt]));
1661
1.34M
    }
1662
4.05k
    form->m_shape.m_path.push_back(MWAWGraphicShape::PathData('L',vertices[size_t(numPt-1)]));
1663
4.05k
    if (vertices[0]==vertices[size_t(numPt)-1])
1664
219
      form->m_shape.m_path.push_back(MWAWGraphicShape::PathData('Z'));
1665
4.05k
    break;
1666
434k
  }
1667
152k
  case 7: {
1668
152k
    val = static_cast<int>(input->readULong(vers >= 3 ? 1 : 2));
1669
152k
    if (val) f << "g1=" << val << ",";
1670
    // skip size (already read)
1671
152k
    pict.m_dataPos = input->tell()+2;
1672
152k
    auto pct = std::make_shared<MsWksGraphInternal::DataPict>(pict);
1673
152k
    res = pct;
1674
152k
    ascFile.skipZone(pct->m_dataPos, pct->m_pos.end()-1);
1675
152k
    break;
1676
434k
  }
1677
459k
  case 8:
1678
459k
    res = readGroup(pict);
1679
459k
    if (!res)
1680
0
      return -1;
1681
459k
    break;
1682
8.33M
  case 9: { // textbox normal
1683
8.33M
    auto justify = MWAWParagraph::JustificationLeft;
1684
8.33M
    val = static_cast<int>(input->readLong(2));
1685
8.33M
    switch (val) {
1686
2.43M
    case 0:
1687
2.43M
      break;
1688
115k
    case 1:
1689
115k
      justify = MWAWParagraph::JustificationCenter;
1690
115k
      break;
1691
14.1k
    case 2:
1692
14.1k
      justify = MWAWParagraph::JustificationFull;
1693
14.1k
      break;
1694
366k
    case -1:
1695
366k
      justify = MWAWParagraph::JustificationRight;
1696
366k
      break;
1697
5.40M
    default:
1698
5.40M
      f << "##align=" << val << ",";
1699
5.40M
      break;
1700
8.33M
    }
1701
8.33M
    if (vers >= 3) {
1702
8.32M
      f << "h=" << input->readLong(4) << ",";
1703
58.2M
      for (int i = 0; i < 6; i++) {
1704
49.9M
        val = static_cast<int>(input->readLong(2));
1705
49.9M
        if (val) f << "g" << i+2 << "=" << val << ",";
1706
49.9M
      }
1707
8.32M
      pict.m_dataPos += 0x10;
1708
8.32M
    }
1709
8.33M
    f << "Fl=[";
1710
41.6M
    for (int i = 0; i < 4; i++) {
1711
33.3M
      val = static_cast<int>(input->readLong(2));
1712
33.3M
      if (val) f << std::hex << val << std::dec << ",";
1713
17.1M
      else f << ",";
1714
33.3M
    }
1715
8.33M
    f << "],";
1716
8.33M
    auto numPos = static_cast<int>(input->readLong(2));
1717
8.33M
    if (numPos < 0) return -1;
1718
7.93M
    f << "numFonts=" << input->readLong(2);
1719
1720
7.93M
    long off[4];
1721
31.7M
    for (auto &d : off) d = long(input->readULong(4));
1722
7.93M
    f << ", Ptrs=[" <<  std::hex << std::setw(8) << off[2] << ", " << std::setw(8) << off[0]
1723
7.93M
      << ", " << std::dec << long(off[1]-off[0])
1724
7.93M
      << ", " << std::dec << long(off[3]-off[0]) << "]";
1725
1726
7.93M
    auto text = std::make_shared<MsWksGraphInternal::TextBox>(pict);
1727
7.93M
    text->m_justify = justify;
1728
7.93M
    text->m_numPositions = numPos;
1729
7.93M
    res = text;
1730
7.93M
    if (!readText(*text)) return -1;
1731
6.45k
    res->m_pos.setEnd(input->tell());
1732
6.45k
    break;
1733
7.93M
  }
1734
6.49M
  case 0xa: { // chart
1735
6.49M
    auto chart  = std::make_shared<MsWksGraphInternal::Chart>(pict);
1736
6.49M
    int chartId = m_state->m_chartId++;
1737
6.49M
    if (!m_tableParser->readChart(chartId, chart->m_style)) {
1738
6.49M
      return -1;
1739
6.49M
    }
1740
836
    m_tableParser->setChartZoneId(chartId, int(m_state->m_zonesList.size()));
1741
836
    chart->m_chartId = chartId;
1742
836
    res = chart;
1743
836
    res->m_pos.setEnd(input->tell());
1744
836
    break;
1745
6.49M
  }
1746
134k
  case 0xc: { // equation
1747
134k
    auto ole = std::make_shared<MsWksGraphInternal::OLEZone>(pict);
1748
134k
    res = ole;
1749
134k
    int dim[2];
1750
268k
    for (auto &d : dim) d = static_cast<int>(input->readLong(4));
1751
134k
    ole->m_dim = MWAWVec2i(dim[0], dim[1]);
1752
134k
    val = static_cast<int>(input->readULong(2)); // always 0x4f4d ?
1753
134k
    f << "g0=" << std::hex << val << std::dec << ",";
1754
134k
    ole->m_oleId=static_cast<int>(input->readULong(4));
1755
134k
    val = static_cast<int>(input->readLong(2)); // always 0?
1756
134k
    if (val) f << "g1=" << val << ",";
1757
134k
    break;
1758
6.49M
  }
1759
1.63M
  case 0xd: { // bitmap
1760
1.63M
    libmwaw::DebugStream f2;
1761
1.63M
    f2 << "Graphd(II): fl(";
1762
1763
1.63M
    long actPos = input->tell();
1764
4.89M
    for (int i = 0; i < 2; i++)
1765
3.26M
      f2 << input->readLong(2) << ", ";
1766
1.63M
    f2 << "), ";
1767
1.63M
    auto nCol = static_cast<int>(input->readLong(2));
1768
1.63M
    auto nRow = static_cast<int>(input->readLong(2));
1769
1.63M
    if (nRow <= 0 || nCol <= 0) return -1;
1770
1771
942k
    f2 << "nRow=" << nRow << ", " << "nCol=" << nCol << ", ";
1772
1773
942k
    f2 << std::hex << input->readULong(4) << std::dec << ", ";
1774
1775
3.76M
    for (int i = 0; i < 3; i++) {
1776
2.82M
      f2 << "bdbox" << i << "=(";
1777
14.1M
      for (int d= 0; d < 4; d++) f2 << input->readLong(2) << ", ";
1778
2.82M
      f2 << "), ";
1779
2.82M
      if (i == 1) f2 << "unk=" << input->readLong(2) << ", ";
1780
2.82M
    }
1781
942k
    auto sizeLine = static_cast<int>(input->readLong(2));
1782
942k
    f2 << "lineSize(?)=" << sizeLine << ", ";
1783
942k
    long bitmapSize = input->readLong(4);
1784
942k
    f2 << "bitmapSize=" << std::hex << bitmapSize << ", ";
1785
1786
942k
    if (bitmapSize <= 0 || (bitmapSize%nRow) != 0) {
1787
      // sometimes, another row is added: only for big picture?
1788
748k
      if (bitmapSize>0 && (bitmapSize%(nRow+1)) == 0) nRow++;
1789
704k
      else if (bitmapSize < nCol*nRow || bitmapSize > 2*nCol*nRow)
1790
704k
        return -1;
1791
7
      else { // maybe a not implemented case
1792
7
        MWAW_DEBUG_MSG(("MsWksGraph::getEntryPicture: bitmap size is a little odd\n"));
1793
7
        f2 << "###";
1794
7
        ascFile.addPos(actPos);
1795
7
        ascFile.addNote(f2.str().c_str());
1796
7
        ascFile.addDelimiter(input->tell(),'|');
1797
7
        break;
1798
7
      }
1799
748k
    }
1800
1801
237k
    auto szCol = int(bitmapSize/nRow);
1802
237k
    if (szCol < nCol) return -1;
1803
1804
12
    ascFile.addPos(actPos);
1805
12
    ascFile.addNote(f2.str().c_str());
1806
1807
12
    pict.m_dataPos = input->tell();
1808
12
    auto pct = std::make_shared<MsWksGraphInternal::DataBitmap>(pict);
1809
12
    pct->m_numRows = nRow;
1810
12
    pct->m_numCols = nCol;
1811
12
    pct->m_dataSize = bitmapSize;
1812
12
    res = pct;
1813
12
    break;
1814
237k
  }
1815
145k
  case 0xe: {
1816
145k
    long actPos = input->tell();
1817
145k
    ascFile.addPos(actPos);
1818
145k
    ascFile.addNote("Graphe(I)");
1819
1820
    // first: the picture ( fixme: kept while we do not parse the spreadsheet )
1821
145k
    input->seek(144, librevenge::RVNG_SEEK_CUR);
1822
145k
    actPos = input->tell();
1823
145k
    ascFile.addPos(actPos);
1824
145k
    ascFile.addNote("Graphe(pict)");
1825
145k
    auto dSize = long(input->readLong(4));
1826
145k
    if (dSize < 0) return -1;
1827
13.5k
    pict.m_dataPos = actPos+4;
1828
1829
13.5k
    auto pct = std::make_shared<MsWksGraphInternal::DataPict>(pict);
1830
13.5k
    pct->m_dataEndPos = actPos+4+dSize;
1831
13.5k
    res = pct;
1832
13.5k
    ascFile.skipZone(pct->m_dataPos, pct->m_dataEndPos-1);
1833
13.5k
    input->seek(actPos+4+dSize, librevenge::RVNG_SEEK_SET);
1834
1835
    // now the spreadsheet ( a classic WKS file )
1836
13.5k
    actPos = input->tell();
1837
13.5k
    dSize = long(input->readULong(4));
1838
13.5k
    if (dSize < 0) return -1;
1839
13.5k
    ascFile.addPos(actPos);
1840
13.5k
    ascFile.addNote("Graphe(sheet)");
1841
13.5k
    ascFile.skipZone(actPos+4, actPos+3+dSize);
1842
#ifdef DEBUG_WITH_FILES
1843
    if (dSize > 0) {
1844
      librevenge::RVNGBinaryData file;
1845
      input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
1846
      input->readDataBlock(dSize, file);
1847
      static int volatile sheetName = 0;
1848
      libmwaw::DebugStream f2;
1849
      f2 << "Sheet-" << ++sheetName << ".wks";
1850
      libmwaw::Debug::dumpFile(file, f2.str().c_str());
1851
    }
1852
#endif
1853
13.5k
    input->seek(actPos+4+dSize, librevenge::RVNG_SEEK_SET);
1854
1855
13.5k
    actPos = input->tell();
1856
13.5k
    ascFile.addPos(actPos);
1857
13.5k
    ascFile.addNote("Graphe(colWidth?)"); // blocksize, unknown+list of 100 w
1858
13.5k
    break;
1859
13.5k
  }
1860
60.6k
  case 0xf: { // new text box v4 (a picture is stored)
1861
60.6k
    if (vers < 4) return -1;
1862
56.5k
    auto textbox = std::make_shared<MsWksGraphInternal::TextBoxv4>(pict);
1863
56.5k
    res = textbox;
1864
56.5k
    textbox->m_ids[1] = long(input->readULong(4));
1865
56.5k
    textbox->m_ids[2] = long(input->readULong(4));
1866
56.5k
    f << "," << std::hex << input->readULong(4)<< std::dec << ",";
1867
    // always 0 ?
1868
395k
    for (int i = 0; i < 6; i++) {
1869
339k
      val = static_cast<int>(input->readLong(2));
1870
339k
      if (val) f << "f" << i << "=" << val << ",";
1871
339k
    }
1872
56.5k
    textbox->m_text.setBegin(input->readLong(4));
1873
56.5k
    textbox->m_text.setEnd(input->readLong(4));
1874
1875
    // always 0 ?
1876
56.5k
    val = static_cast<int>(input->readLong(2));
1877
56.5k
    if (val) f << "f10=" << val << ",";
1878
56.5k
    auto sz = long(input->readULong(4));
1879
56.5k
    if (sz+0x3b != dataSize)
1880
44.2k
      f << "###sz=" << sz << ",";
1881
1882
56.5k
    pict.m_dataPos = input->tell();
1883
56.5k
    if (pict.m_dataPos != pict.m_pos.end()) {
1884
#ifdef DEBUG_WITH_FILES
1885
      librevenge::RVNGBinaryData file;
1886
      input->readDataBlock(pict.m_pos.end()-pict.m_dataPos, file);
1887
      static int volatile textboxName = 0;
1888
      libmwaw::DebugStream f2;
1889
      f2 << "TextBox-" << ++textboxName << ".pct";
1890
      libmwaw::Debug::dumpFile(file, f2.str().c_str());
1891
#endif
1892
44.9k
      ascFile.skipZone(pict.m_dataPos, pict.m_pos.end()-1);
1893
44.9k
    }
1894
56.5k
    break;
1895
60.6k
  }
1896
765k
  case 0x10: { // basic table
1897
765k
    libmwaw::DebugStream f2;
1898
765k
    f2 << "Graph10(II): fl=(";
1899
765k
    long actPos = input->tell();
1900
3.06M
    for (int i = 0; i < 3; i++)
1901
2.29M
      f2 << input->readLong(2) << ", ";
1902
765k
    f2 << "), ";
1903
765k
    auto nRow = static_cast<int>(input->readLong(2));
1904
765k
    auto nCol = static_cast<int>(input->readLong(2));
1905
765k
    f2 << "nRow=" << nRow << ", " << "nCol=" << nCol << ", ";
1906
1907
    // basic name font
1908
765k
    auto nbChar = static_cast<int>(input->readULong(1));
1909
765k
    if (nbChar > 31) return -1;
1910
542k
    std::string fName;
1911
3.80M
    for (int c = 0; c < nbChar; c++)
1912
3.26M
      fName+=char(input->readLong(1));
1913
542k
    f2 << fName << ",";
1914
542k
    input->seek(actPos+10+32, librevenge::RVNG_SEEK_SET);
1915
542k
    auto fSz = static_cast<int>(input->readLong(2));
1916
542k
    if (fSz) f << "fSz=" << fSz << ",";
1917
1918
542k
    ascFile.addDelimiter(input->tell(),'|');
1919
542k
    ascFile.addPos(actPos);
1920
542k
    ascFile.addNote(f2.str().c_str());
1921
542k
    input->seek(actPos+0x40, librevenge::RVNG_SEEK_SET);
1922
1923
    // a pict
1924
542k
    actPos = input->tell();
1925
542k
    ascFile.addPos(actPos);
1926
542k
    ascFile.addNote("Graph10(pict)");
1927
542k
    auto dSize = long(input->readLong(4));
1928
542k
    if (dSize < 0) return -1;
1929
174k
    pict.m_dataPos = actPos+4;
1930
1931
174k
    auto pct = std::make_shared<MsWksGraphInternal::DataPict>(pict);
1932
174k
    pct->m_dataEndPos = actPos+4+dSize;
1933
174k
    res = pct;
1934
174k
    ascFile.skipZone(pct->m_dataPos, pct->m_dataEndPos-1);
1935
174k
    input->seek(actPos+4+dSize, librevenge::RVNG_SEEK_SET);
1936
1937
    // the table
1938
174k
    f << "numRows=" << nRow << ",nCols=" << nCol << ",";
1939
174k
    std::shared_ptr<MsWksGraphInternal::Table> table(new MsWksGraphInternal::Table(pict));
1940
174k
    int tableId = m_state->m_tableId++;
1941
174k
    if (m_tableParser->readTable(nCol, nRow, tableId, table->m_style)) {
1942
118k
      table->m_tableId = tableId;
1943
118k
      res=table;
1944
118k
    }
1945
174k
    break;
1946
542k
  }
1947
0
  default:
1948
0
    ascFile.addDelimiter(debData, '|');
1949
0
    break;
1950
28.1M
  }
1951
1952
10.9M
  if (!res)
1953
7
    res.reset(new MsWksGraphInternal::Zone(pict));
1954
10.9M
  res->m_extra += f.str();
1955
1956
10.9M
  if (order > -1000)
1957
9.42M
    res->m_order = order;
1958
10.9M
  if (!autoSend)
1959
10.1M
    res->m_doNotSend = true;
1960
10.9M
  res->m_fileId = int(m_state->m_zonesList.size());
1961
10.9M
  m_state->m_zonesList.push_back(res);
1962
1963
10.9M
  f.str("");
1964
10.9M
  f << "Entries(Graph" << std::hex << res->m_subType << std::dec << "):" << *res;
1965
10.9M
  ascFile.addPos(pos);
1966
10.9M
  ascFile.addNote(f.str().c_str());
1967
1968
10.9M
  zone = res->m_pos;
1969
10.9M
  zone.setType("Graphic");
1970
10.9M
  input->seek(res->m_pos.end(), librevenge::RVNG_SEEK_SET);
1971
1972
10.9M
  return res->m_fileId;
1973
28.1M
}
1974
1975
void MsWksGraph::computePositions(int zoneId, std::vector<int> const &linesH, std::vector<int> const &pagesH)
1976
41.5k
{
1977
41.5k
  auto numLines = int(linesH.size());
1978
41.5k
  auto nPages = int(pagesH.size());
1979
41.5k
  bool isSpreadsheet=m_parserState->m_type==MWAWParserState::Spreadsheet;
1980
1.12M
  for (auto const &zone : m_state->m_zonesList) {
1981
1.12M
    if (zone->m_zoneId != -1 && zoneId != zone->m_zoneId) continue;
1982
732k
    if (zone->m_line >= 0) {
1983
14.5k
      int h = 0;
1984
14.5k
      if (zone->m_line >= numLines) {
1985
11.9k
        MWAW_DEBUG_MSG(("MsWksGraph::computePositions: linepos is too big\n"));
1986
11.9k
        if (numLines)
1987
5.91k
          h = linesH[size_t(numLines)-1];
1988
11.9k
      }
1989
2.62k
      else
1990
2.62k
        h = linesH[size_t(zone->m_line)];
1991
14.5k
      zone->m_finalDecal = MWAWVec2f(0, float(h));
1992
14.5k
    }
1993
732k
    if (zone->m_page < 0 && (isSpreadsheet || zone->m_page != -2)) {
1994
683k
      float h = zone->m_finalDecal.y();
1995
683k
      float middleH=zone->m_box.center().y();
1996
683k
      h+=middleH;
1997
683k
      int p = 0;
1998
920k
      while (p < nPages) {
1999
331k
        if (h < float(pagesH[size_t(p)])) break;
2000
236k
        h -= float(pagesH[size_t(p++)]);
2001
236k
      }
2002
683k
      zone->m_page = p;
2003
683k
      zone->m_finalDecal.setY(h-middleH);
2004
683k
    }
2005
732k
  }
2006
41.5k
}
2007
2008
int MsWksGraph::getEntryPictureV1(int zoneId, MWAWEntry &zone, bool autoSend)
2009
9.12M
{
2010
9.12M
  MWAWInputStreamPtr input=m_document.getInput();
2011
9.12M
  if (input->isEnd()) return -1;
2012
2013
9.12M
  long pos = input->tell();
2014
9.12M
  if (input->readULong(1) != 1) return -1;
2015
2016
9.12M
  libmwaw::DebugFile &ascFile = m_document.ascii();
2017
9.12M
  libmwaw::DebugStream f;
2018
9.12M
  auto ptr = long(input->readULong(2));
2019
9.12M
  auto flag = static_cast<int>(input->readULong(1));
2020
9.12M
  long size = long(input->readULong(2))+6;
2021
9.12M
  if (size < 22) return -1;
2022
2023
  // check if we can go to the next zone
2024
7.43M
  if (!input->checkPosition(pos+size)) return -1;
2025
5.31M
  std::shared_ptr<MsWksGraphInternal::DataPict> pict(new MsWksGraphInternal::DataPict());
2026
5.31M
  pict->m_zoneId = zoneId;
2027
5.31M
  pict->m_subType = 0x100;
2028
5.31M
  pict->m_pos.setBegin(pos);
2029
5.31M
  pict->m_pos.setLength(size);
2030
2031
5.31M
  if (ptr) f << std::hex << "ptr0=" << ptr << ",";
2032
5.31M
  if (flag) f << std::hex << "fl=" << flag << ",";
2033
2034
5.31M
  ptr = input->readLong(4);
2035
5.31M
  if (ptr)
2036
4.99M
    f << "ptr1=" << std::hex << ptr << std::dec << ";";
2037
5.31M
  pict->m_line = static_cast<int>(input->readLong(2));
2038
5.31M
  auto val = static_cast<int>(input->readLong(2)); // almost always equal to m_linePOs
2039
5.31M
  if (val !=  pict->m_line)
2040
3.70M
    f <<  "linePos2=" << std::hex << val << std::dec << ",";
2041
5.31M
  int dim[4]; // pictbox
2042
21.2M
  for (auto &d : dim) d = static_cast<int>(input->readLong(2));
2043
5.31M
  pict->m_box = MWAWBox2f(MWAWVec2f(float(dim[1]), float(dim[0])), MWAWVec2f(float(dim[3]),float(dim[2])));
2044
2045
5.31M
  MWAWVec2i pictMin(pict->m_box.min()), pictSize(pict->m_box.size());
2046
5.31M
  if (pictSize.x() < 0 || pictSize.y() < 0) return -1;
2047
2048
3.20M
  if (pictSize.x() > 3000 || pictSize.y() > 3000 ||
2049
3.17M
      pictMin.x() < -200 || pictMin.y() < -200) return -1;
2050
32.2k
  pict->m_dataPos = input->tell();
2051
2052
32.2k
  zone = pict->m_pos;
2053
32.2k
  zone.setType("GraphEntry");
2054
2055
32.2k
  pict->m_extra = f.str();
2056
32.2k
  if (!autoSend)
2057
0
    pict->m_doNotSend=true;
2058
32.2k
  pict->m_fileId = int(m_state->m_zonesList.size());
2059
32.2k
  m_state->m_zonesList.push_back(pict);
2060
32.2k
  f.str("");
2061
32.2k
  f << "Entries(GraphEntry):" << *pict;
2062
2063
32.2k
  ascFile.skipZone(pict->m_dataPos, pict->m_pos.end()-1);
2064
32.2k
  ascFile.addPos(pos);
2065
32.2k
  ascFile.addNote(f.str().c_str());
2066
2067
32.2k
  input->seek(pict->m_pos.end(), librevenge::RVNG_SEEK_SET);
2068
32.2k
  return pict->m_fileId;
2069
3.20M
}
2070
2071
// a list of picture
2072
bool MsWksGraph::readRB(MWAWInputStreamPtr input, MWAWEntry const &entry, int kind)
2073
2.52M
{
2074
2.52M
  libmwaw::DebugFile &ascFile = m_document.ascii();
2075
2.52M
  libmwaw::DebugStream f;
2076
2077
2.52M
  long beginRB, endRB;
2078
2.52M
  long pos=input->tell();
2079
2.52M
  f << "Entries(" << entry.name() << "):";
2080
2.52M
  const int vers=version();
2081
2.52M
  switch (kind) {
2082
3.89k
  case 0:
2083
3.89k
    pos=beginRB=entry.begin();
2084
3.89k
    endRB=entry.end();
2085
3.89k
    break;
2086
2.30M
  case 2:
2087
2.30M
    if (input->readLong(1)!=3) return false;
2088
2.30M
    f << "id=" << input->readLong(1) << ",";
2089
2.30M
    MWAW_FALLTHROUGH;
2090
2.52M
  case 1: {
2091
2.52M
    unsigned long dSz=input->readULong(4);
2092
2.52M
    beginRB=input->tell();
2093
2.52M
    if (dSz&0x80000000) {
2094
893k
      f << "flags[high],";
2095
893k
      dSz &= 0x7FFFFFFF;
2096
893k
    }
2097
2.52M
    endRB=beginRB+long(dSz);
2098
2.52M
    break;
2099
2.30M
  }
2100
0
  default:
2101
0
    MWAW_DEBUG_MSG(("MsWksGraph::readRB: unknown kind\n"));
2102
0
    return false;
2103
2.52M
  }
2104
2105
2.52M
  long const headerSize=vers<3 ? 0x150 : 0x164;
2106
2.52M
  if (endRB-beginRB+2 < headerSize || !input->checkPosition(endRB)) return false;
2107
2108
40.3k
  MsWksGraphInternal::RBZone zone;
2109
40.3k
  if (vers==4)
2110
9.45k
    zone.m_isMain = entry.name()=="RBDR";
2111
40.3k
  zone.m_id = entry.id();
2112
2113
40.3k
  input->seek(beginRB, librevenge::RVNG_SEEK_SET);
2114
40.3k
  f << input->readLong(4) << ", ";
2115
201k
  for (int i = 0; i < 4; i++) {
2116
161k
    long val = input->readLong(4);
2117
161k
    if (val) f << "#t" << i << "=" << val << ", ";
2118
161k
  }
2119
40.3k
  f << "type?=" << std::hex << input->readLong(2) << std::dec << ", ";
2120
40.3k
  f << "numPage=" << input->readLong(2) << ", ";
2121
484k
  for (int i = 0; i < 11; i++) {
2122
444k
    long val = input->readLong(2);
2123
444k
    if (!val) continue;
2124
224k
    if (i >= 8 && (val < -100 || val > 100)) f << "###";
2125
224k
    f << "f" << i << "=" << val << ", ";
2126
224k
  }
2127
40.3k
  f << ", unk=(";
2128
121k
  for (int i = 0; i < 2; i++)
2129
80.7k
    f << input->readLong(4) << ",";
2130
40.3k
  f << "), ";
2131
403k
  for (int i = 0; i < 9; i++) {
2132
363k
    long val = input->readLong(2);
2133
363k
    if (val) f << "#u" << i << "=" << val << ", ";
2134
363k
  }
2135
40.3k
  f << std::hex << "sz?=" << input->readLong(4) << std::dec << ", ";
2136
121k
  for (int i = 0; i < 2; i++) {
2137
80.7k
    long val = input->readLong(2);
2138
80.7k
    if (val) f << "#v" << i << "=" << val << ", ";
2139
80.7k
  }
2140
2141
40.3k
  f << "unk1=(";
2142
403k
  for (int i = 0; i < 9; i++) {
2143
363k
    long val = input->readLong(2);
2144
363k
    if (val) f << val << ",";
2145
183k
    else f << "_,";
2146
363k
  }
2147
40.3k
  f << "), ";
2148
40.3k
  if (vers>=3) {
2149
18.9k
    long aPos=input->tell();
2150
18.9k
    std::string oleName;
2151
81.4k
    while (input->tell() < beginRB+headerSize-2) {
2152
81.4k
      auto val  = char(input->readLong(1));
2153
81.4k
      if (val == 0) break;
2154
67.1k
      oleName+= val;
2155
67.1k
      if (oleName.length() >= 10) break;
2156
67.1k
    }
2157
18.9k
    if (!oleName.empty()) {
2158
11.3k
      zone.m_frame = oleName;
2159
11.3k
      f << "ole='" << oleName << "', ";
2160
11.3k
    }
2161
18.9k
    ascFile.addDelimiter(input->tell(),'|');
2162
18.9k
    input->seek(aPos+20, librevenge::RVNG_SEEK_SET);
2163
18.9k
  }
2164
40.3k
  ascFile.addPos(pos);
2165
40.3k
  ascFile.addNote(f.str().c_str());
2166
2167
40.3k
  pos=input->tell();
2168
40.3k
  f.str("");
2169
40.3k
  f << entry.name() << "-II:";
2170
4.80M
  for (int i=0; i<118; ++i) {
2171
4.76M
    auto val = static_cast<int>(input->readLong(2));
2172
4.76M
    if (val) f << "g" << i << "=" << std::hex << val << std::dec << ",";
2173
4.76M
  }
2174
  // can happens at least with vers=2 and this means that the size is not set
2175
40.3k
  if (endRB-beginRB+2 == headerSize)
2176
19.5k
    endRB=-1;
2177
40.3k
  auto N = static_cast<int>(input->readLong(2));
2178
40.3k
  f << "N=" << N << ",";
2179
40.3k
  ascFile.addPos(pos);
2180
40.3k
  ascFile.addNote(f.str().c_str());
2181
2182
40.3k
  if (N == 0) return true;
2183
2184
30.8k
  if (endRB>0)
2185
13.6k
    input->pushLimit(endRB);
2186
30.8k
  size_t actId = m_state->m_zonesList.size();
2187
128k
  for (int i = 0; i < N; i++) {
2188
115k
    pos = input->tell();
2189
115k
    MWAWEntry pictZone;
2190
115k
    if (getEntryPicture(vers==4 ? 0 : entry.id(), pictZone)>=0)
2191
97.4k
      continue;
2192
18.1k
    MWAW_DEBUG_MSG(("MsWksDocument::readGroup: can not find the end of group\n"));
2193
18.1k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2194
18.1k
    break;
2195
115k
  }
2196
30.8k
  if (endRB>0)
2197
13.6k
    input->popLimit();
2198
160k
  for (size_t z = actId; z < m_state->m_zonesList.size(); z++) {
2199
129k
    auto pictZone = m_state->m_zonesList[z];
2200
129k
    if (!pictZone) continue;
2201
129k
    zone.m_idList.push_back(int(z));
2202
129k
    if (!zone.m_isMain)
2203
3.51k
      pictZone->m_page = -2;
2204
129k
  }
2205
30.8k
  if (endRB>0 && input->tell() < endRB) {
2206
10.3k
    f.str("");
2207
10.3k
    f << entry.name() << "-end:###";
2208
10.3k
    MWAW_DEBUG_MSG(("MsWksGraph::readRB: find some extra data\n"));
2209
10.3k
    ascFile.addPos(input->tell());
2210
10.3k
    ascFile.addNote(f.str().c_str());
2211
10.3k
  }
2212
30.8k
  if (endRB>0)
2213
13.6k
    input->seek(endRB, librevenge::RVNG_SEEK_SET);
2214
30.8k
  checkTextBoxLinks(zone);
2215
30.8k
  int zId = zone.getId();
2216
30.8k
  if (m_state->m_RBsMap.find(zId) != m_state->m_RBsMap.end()) {
2217
17.8k
    MWAW_DEBUG_MSG(("MsWksGraph::readRB: zone %d is already filled\n", zId));
2218
    // ok, let's merge the two zone
2219
17.8k
    auto &orig=m_state->m_RBsMap.find(zId)->second;
2220
17.8k
    orig.m_idList.insert(orig.m_idList.end(), zone.m_idList.begin(), zone.m_idList.end());
2221
17.8k
    if (orig.m_frame.empty()) orig.m_frame=zone.m_frame;
2222
17.8k
  }
2223
13.0k
  else
2224
13.0k
    m_state->m_RBsMap[zId]=zone;
2225
30.8k
  return true;
2226
40.3k
}
2227
2228
void MsWksGraph::checkTextBoxLinks(MsWksGraphInternal::RBZone &rbZone)
2229
30.8k
{
2230
30.8k
  auto const &listIds = rbZone.m_idList;
2231
30.8k
  std::string const &fName = rbZone.m_frame;
2232
30.8k
  auto numZones = int(m_state->m_zonesList.size());
2233
30.8k
  std::set<long> textIds;
2234
30.8k
  std::map<long, long> prevLinks, nextLinks;
2235
30.8k
  bool ok = true;
2236
129k
  for (auto id : listIds) {
2237
129k
    if (id < 0 || id >= numZones) continue;
2238
129k
    auto zone = m_state->m_zonesList[size_t(id)];
2239
129k
    if (zone->type() != MsWksGraphInternal::Zone::Textv4)
2240
126k
      continue;
2241
2.40k
    static_cast<MsWksGraphInternal::TextBoxv4 &>(*zone).m_frame = fName;
2242
2.40k
    if (textIds.find(zone->m_ids[0]) != textIds.end()) {
2243
11
      MWAW_DEBUG_MSG(("MsWksGraph::checkTextBoxLinks: id %lX already exists\n", static_cast<long unsigned int>(zone->m_ids[0])));
2244
11
      ok = false;
2245
11
      break;
2246
11
    }
2247
2.39k
    textIds.insert(zone->m_ids[0]);
2248
2.39k
    if (zone->m_ids[1]>0)
2249
1.10k
      prevLinks.insert(std::map<long, long>::value_type(zone->m_ids[0],zone->m_ids[1]));
2250
2.39k
    if (zone->m_ids[2]>0)
2251
1.12k
      nextLinks.insert(std::map<long, long>::value_type(zone->m_ids[0],zone->m_ids[2]));
2252
2.39k
  }
2253
30.8k
  size_t numLinks = nextLinks.size();
2254
30.8k
  for (auto const &link : nextLinks) {
2255
653
    if (prevLinks.find(link.second)==prevLinks.end() ||
2256
639
        prevLinks.find(link.second)->second!=link.first) {
2257
639
      MWAW_DEBUG_MSG(("MsWksGraph::checkTextBoxLinks: can not find prevLinks: %lX<->%lX already exists\n", static_cast<long unsigned int>(link.first), static_cast<long unsigned int>(link.second)));
2258
639
      ok = false;
2259
639
      break;
2260
639
    }
2261
    // check loops
2262
14
    size_t w = 0;
2263
14
    long actText = link.second;
2264
46
    while (1) {
2265
46
      if (nextLinks.find(actText)==nextLinks.end())
2266
0
        break;
2267
46
      actText = nextLinks.find(actText)->second;
2268
46
      if (w++ > numLinks) {
2269
14
        MWAW_DEBUG_MSG(("MsWksGraph::checkTextBoxLinks:find a loop for id %lX\n", static_cast<long unsigned int>(link.first)));
2270
14
        ok = false;
2271
14
        break;
2272
14
      }
2273
46
    }
2274
14
  }
2275
30.8k
  if (!ok) {
2276
654
    MWAW_DEBUG_MSG(("MsWksGraph::checkTextBoxLinks: problem find with text links\n"));
2277
4.16k
    for (auto const &zone : m_state->m_zonesList) {
2278
4.16k
      if (zone->type() != MsWksGraphInternal::Zone::Textv4)
2279
2.77k
        continue;
2280
1.39k
      zone->m_ids[1] = zone->m_ids[2] = 0;
2281
1.39k
    }
2282
654
  }
2283
30.8k
}
2284
2285
bool MsWksGraph::readPictureV4(MWAWInputStreamPtr /*input*/, MWAWEntry const &entry)
2286
0
{
2287
0
  if (!entry.hasType("PICT")) {
2288
0
    MWAW_DEBUG_MSG(("MsWksGraph::readPictureV4: unknown type='%s'\n", entry.type().c_str()));
2289
0
    return false;
2290
0
  }
2291
0
  entry.setParsed(true);
2292
2293
0
  MsWksGraphInternal::Zone pict;
2294
0
  pict.m_pos = entry;
2295
0
  pict.m_dataPos = entry.begin();
2296
0
  pict.m_page = -2;
2297
0
  pict.m_zoneId = -1;
2298
2299
0
  auto pct = std::make_shared<MsWksGraphInternal::DataPict>(pict);
2300
0
  std::shared_ptr<MsWksGraphInternal::Zone>res(pct);
2301
0
  m_document.ascii().skipZone(entry.begin(), entry.end()-1);
2302
2303
0
  auto zId = int(m_state->m_zonesList.size());
2304
0
  res->m_fileId = zId;
2305
0
  m_state->m_zonesList.push_back(res);
2306
2307
0
  return true;
2308
0
}
2309
2310
////////////////////////////////////////////////////////////
2311
//
2312
// Low level
2313
//
2314
////////////////////////////////////////////////////////////
2315
2316
// read/send a group
2317
void MsWksGraph::sendGroup(int id, MWAWPosition const &pos)
2318
252k
{
2319
252k
  if (id<0 || id>=int(m_state->m_zonesList.size()) || !m_state->m_zonesList[size_t(id)] ||
2320
252k
      m_state->m_zonesList[size_t(id)]->type()!=MsWksGraphInternal::Zone::Group) {
2321
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendGroup: can not find group %d\n", id));
2322
0
    return;
2323
0
  }
2324
252k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2325
252k
  if (!listener) return;
2326
252k
  auto &group=static_cast<MsWksGraphInternal::GroupZone &>(*m_state->m_zonesList[size_t(id)]);
2327
252k
  group.m_isSent = true;
2328
252k
  if (listener->getType()==MWAWListener::Graphic) {
2329
220k
    sendGroup(group, m_parserState->m_graphicListener);
2330
220k
    return;
2331
220k
  }
2332
31.8k
  if (!canCreateGraphic(group)) {
2333
23.2k
    if (pos.m_anchorTo == MWAWPosition::Char || pos.m_anchorTo == MWAWPosition::CharBaseLine) {
2334
737
      std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2335
737
      (new MsWksGraphInternal::SubDocument(*this, m_document.getInput(), MsWksGraphInternal::SubDocument::Group, id));
2336
737
      listener->insertTextBox(pos, subdoc);
2337
737
      return;
2338
737
    }
2339
22.5k
    MWAWPosition childPos(pos);
2340
22.5k
    childPos.setSize(MWAWVec2f(0,0));
2341
22.5k
    sendGroupChild(id, childPos);
2342
22.5k
    return;
2343
23.2k
  }
2344
8.57k
  MWAWGraphicEncoder graphicEncoder;
2345
8.57k
  MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, group.m_box, &graphicEncoder));
2346
8.57k
  graphicListener->startDocument();
2347
8.57k
  sendGroup(group, graphicListener);
2348
8.57k
  graphicListener->endDocument();
2349
8.57k
  MWAWEmbeddedObject picture;
2350
8.57k
  if (graphicEncoder.getBinaryResult(picture))
2351
8.57k
    listener->insertPicture(pos, picture);
2352
8.57k
}
2353
2354
void MsWksGraph::sendGroupChild(int id, MWAWPosition const &pos)
2355
23.2k
{
2356
23.2k
  if (id<0 || id>=int(m_state->m_zonesList.size()) || !m_state->m_zonesList[size_t(id)] ||
2357
23.2k
      m_state->m_zonesList[size_t(id)]->type()!=MsWksGraphInternal::Zone::Group) {
2358
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendGroupChild: can not find group %d\n", id));
2359
0
    return;
2360
0
  }
2361
23.2k
  MWAWListenerPtr listener=m_parserState->getMainListener();
2362
23.2k
  if (!listener) return;
2363
23.2k
  auto &group=static_cast<MsWksGraphInternal::GroupZone &>(*m_state->m_zonesList[size_t(id)]);
2364
23.2k
  group.m_isSent = true;
2365
2366
23.2k
  MWAWInputStreamPtr input=m_document.getInput();
2367
23.2k
  size_t numZones=m_state->m_zonesList.size();
2368
23.2k
  size_t numChild=group.m_childs.size(), childNotSent=0;
2369
23.2k
  int numDataToMerge=0;
2370
23.2k
  MWAWBox2f partialBdBox;
2371
23.2k
  MWAWPosition partialPos(pos);
2372
23.2k
  bool isDraw=listener->getType()==MWAWListener::Graphic;
2373
219k
  for (size_t c=0; c < numChild; ++c) {
2374
201k
    int cId = group.m_childs[c];
2375
201k
    if (cId < 0 || cId >= int(numZones) || !m_state->m_zonesList[size_t(cId)])
2376
0
      continue;
2377
201k
    auto const &child=*(m_state->m_zonesList[size_t(cId)]);
2378
201k
    bool isLast=false;
2379
201k
    bool canMerge=false;
2380
201k
    if (isDraw)
2381
0
      canMerge=false;
2382
201k
    else if (child.type()==MsWksGraphInternal::Zone::Shape || child.type()==MsWksGraphInternal::Zone::Text) {
2383
164k
      MWAWBox2f origBdBox=child.getLocalBox();
2384
164k
      MWAWVec2f decal = child.m_decal[0] + child.m_decal[1];
2385
164k
      MWAWBox2f localBdBox(origBdBox[0]+decal, origBdBox[1]+decal);
2386
164k
      if (numDataToMerge == 0)
2387
17.3k
        partialBdBox=localBdBox;
2388
146k
      else
2389
146k
        partialBdBox=partialBdBox.getUnion(localBdBox);
2390
164k
      canMerge=true;
2391
164k
    }
2392
37.2k
    else if (child.type()==MsWksGraphInternal::Zone::Group &&
2393
30.4k
             canCreateGraphic(static_cast<MsWksGraphInternal::GroupZone const &>(child))) {
2394
11.6k
      if (numDataToMerge == 0)
2395
4.42k
        partialBdBox=child.getLocalBox();
2396
7.24k
      else
2397
7.24k
        partialBdBox=partialBdBox.getUnion(child.getLocalBox());
2398
11.6k
      canMerge=true;
2399
11.6k
    }
2400
201k
    if (canMerge) {
2401
175k
      ++numDataToMerge;
2402
175k
      if (c+1 < numChild)
2403
169k
        continue;
2404
6.15k
      isLast=true;
2405
6.15k
    }
2406
2407
31.7k
    if (numDataToMerge>1) {
2408
12.3k
      MWAWGraphicEncoder graphicEncoder;
2409
12.3k
      MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, partialBdBox, &graphicEncoder));
2410
12.3k
      graphicListener->startDocument();
2411
12.3k
      size_t lastChild = isLast ? c : c-1;
2412
178k
      for (size_t ch=childNotSent; ch <= lastChild; ++ch) {
2413
166k
        int localCId = group.m_childs[ch];
2414
166k
        if (localCId < 0 || localCId >= int(numZones) || !m_state->m_zonesList[size_t(localCId)])
2415
0
          continue;
2416
166k
        auto const &localChild=*(m_state->m_zonesList[size_t(localCId)]);
2417
166k
        MWAWBox2f origBdBox=localChild.getLocalBox(false);
2418
166k
        MWAWVec2f decal=localChild.m_decal[0]+localChild.m_decal[1];
2419
166k
        MWAWPosition pictPos(origBdBox[0]+decal, origBdBox.size(), librevenge::RVNG_POINT);
2420
166k
        pictPos.m_anchorTo=MWAWPosition::Page;
2421
166k
        pictPos.m_wrapping =  MWAWPosition::WBackground;
2422
166k
        if (localChild.type()==MsWksGraphInternal::Zone::Group)
2423
11.1k
          sendGroup(static_cast<MsWksGraphInternal::GroupZone const &>(localChild), graphicListener);
2424
155k
        else if (localChild.type()==MsWksGraphInternal::Zone::Shape) {
2425
154k
          auto const &shape=static_cast<MsWksGraphInternal::BasicShape const &>(localChild);
2426
154k
          graphicListener->insertShape(pictPos, shape.m_shape, shape.getStyle());
2427
154k
        }
2428
669
        else if (localChild.type()==MsWksGraphInternal::Zone::Text) {
2429
669
          std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2430
669
          (new MsWksGraphInternal::SubDocument(const_cast<MsWksGraph &>(*this), input, MsWksGraphInternal::SubDocument::TextBox, localCId));
2431
          // a textbox can not have border
2432
669
          MWAWGraphicStyle style(localChild.m_style);
2433
669
          style.m_lineWidth=0;
2434
669
          graphicListener->insertTextBox(pictPos, subdoc, style);
2435
669
        }
2436
166k
      }
2437
12.3k
      graphicListener->endDocument();
2438
12.3k
      MWAWEmbeddedObject picture;
2439
12.3k
      if (graphicEncoder.getBinaryResult(picture)) {
2440
12.3k
        partialPos.setOrigin(pos.origin()+partialBdBox[0]-group.m_box[0]);
2441
12.3k
        partialPos.setSize(partialBdBox.size());
2442
12.3k
        listener->insertPicture(partialPos, picture);
2443
12.3k
        if (isLast)
2444
5.26k
          break;
2445
7.09k
        childNotSent=c;
2446
7.09k
      }
2447
12.3k
    }
2448
    // time to send back the data
2449
61.5k
    for (; childNotSent <= c; ++childNotSent)
2450
35.0k
      send(group.m_childs[childNotSent],pos);
2451
26.5k
    numDataToMerge=0;
2452
26.5k
  }
2453
23.2k
}
2454
2455
bool MsWksGraph::canCreateGraphic(MsWksGraphInternal::GroupZone const &group) const
2456
409k
{
2457
409k
  if (m_parserState->getMainListener()->getType()==MWAWListener::Graphic) return false;
2458
409k
  auto numZones = int(m_state->m_zonesList.size());
2459
1.72M
  for (auto cId : group.m_childs) {
2460
1.72M
    if (cId < 0 || cId >= numZones || !m_state->m_zonesList[size_t(cId)])
2461
0
      continue;
2462
1.72M
    auto const &child=*(m_state->m_zonesList[size_t(cId)]);
2463
1.72M
    if (child.m_page!=group.m_page)
2464
27.2k
      return false;
2465
1.70M
    switch (child.type()) {
2466
1.33M
    case MsWksGraphInternal::Zone::Shape:
2467
1.33M
    case MsWksGraphInternal::Zone::Text:
2468
1.33M
      break;
2469
347k
    case MsWksGraphInternal::Zone::Group:
2470
347k
      if (!canCreateGraphic(static_cast<MsWksGraphInternal::GroupZone const &>(child)))
2471
184k
        return false;
2472
163k
      break;
2473
163k
    case MsWksGraphInternal::Zone::Bitmap:
2474
0
    case MsWksGraphInternal::Zone::ChartZone:
2475
0
    case MsWksGraphInternal::Zone::OLE:
2476
14.7k
    case MsWksGraphInternal::Zone::Pict:
2477
14.7k
    case MsWksGraphInternal::Zone::TableZone:
2478
14.7k
    case MsWksGraphInternal::Zone::Textv4:
2479
14.7k
    case MsWksGraphInternal::Zone::Unknown:
2480
#if !defined(__clang__)
2481
    default:
2482
#endif
2483
14.7k
      return false;
2484
1.70M
    }
2485
1.70M
  }
2486
183k
  return true;
2487
409k
}
2488
2489
void MsWksGraph::sendGroup(MsWksGraphInternal::GroupZone const &group, MWAWGraphicListenerPtr &listener) const
2490
285k
{
2491
285k
  if (!listener || !listener->isDocumentStarted()) {
2492
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendGroup: the listener is bad\n"));
2493
0
    return;
2494
0
  }
2495
285k
  auto numZones = int(m_state->m_zonesList.size());
2496
285k
  MWAWInputStreamPtr input=m_document.getInput();
2497
1.03M
  for (auto cId : group.m_childs) {
2498
1.03M
    if (cId < 0 || cId >= numZones || !m_state->m_zonesList[size_t(cId)])
2499
0
      continue;
2500
1.03M
    auto const &child=*(m_state->m_zonesList[size_t(cId)]);
2501
1.03M
    MWAWVec2f decal=child.m_decal[0]+child.m_decal[1];
2502
1.03M
    MWAWPosition pictPos(child.m_box[0]+decal, child.m_box.size(), librevenge::RVNG_POINT);
2503
1.03M
    pictPos.m_anchorTo=MWAWPosition::Page;
2504
1.03M
    pictPos.m_wrapping =  MWAWPosition::WBackground;
2505
2506
1.03M
    if (child.type()==MsWksGraphInternal::Zone::Group)
2507
44.9k
      sendGroup(static_cast<MsWksGraphInternal::GroupZone const &>(child), listener);
2508
992k
    else if (child.type()==MsWksGraphInternal::Zone::Shape) {
2509
887k
      auto const &shape=static_cast<MsWksGraphInternal::BasicShape const &>(child);
2510
887k
      listener->insertShape(pictPos, shape.m_shape, shape.getStyle());
2511
887k
    }
2512
104k
    else if (child.type()==MsWksGraphInternal::Zone::Text) {
2513
2.12k
      std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2514
2.12k
      (new MsWksGraphInternal::SubDocument(const_cast<MsWksGraph &>(*this), input, MsWksGraphInternal::SubDocument::TextBox, cId));
2515
      // a textbox can not have border
2516
2.12k
      MWAWGraphicStyle style(child.m_style);
2517
2.12k
      style.m_lineWidth=0;
2518
2.12k
      listener->insertTextBox(pictPos, subdoc, style);
2519
2.12k
    }
2520
102k
    else {
2521
102k
      MWAW_DEBUG_MSG(("MsWksGraph::sendGroup: find some unexpected child\n"));
2522
102k
    }
2523
1.03M
  }
2524
285k
}
2525
2526
std::shared_ptr<MsWksGraphInternal::GroupZone> MsWksGraph::readGroup(MsWksGraphInternal::Zone &header)
2527
459k
{
2528
459k
  std::shared_ptr<MsWksGraphInternal::GroupZone> group(new MsWksGraphInternal::GroupZone(header));
2529
459k
  libmwaw::DebugStream f;
2530
459k
  MWAWInputStreamPtr input=m_document.getInput();
2531
459k
  input->seek(header.m_dataPos, librevenge::RVNG_SEEK_SET);
2532
459k
  float dim[4];
2533
1.83M
  for (auto &d : dim) d = float(input->readLong(4));
2534
459k
  group->m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[2],dim[3]));
2535
459k
  group->m_finalDecal=MWAWVec2f(0,0);
2536
459k
  long ptr[2];
2537
919k
  for (auto &p : ptr) p = long(input->readULong(4));
2538
459k
  f << "ptr0=" << std::hex << ptr[0] << std::dec << ",";
2539
459k
  if (ptr[0] != ptr[1])
2540
396k
    f << "ptr1=" << std::hex << ptr[1] << std::dec << ",";
2541
459k
  if (version() >= 3) {
2542
401k
    auto val = static_cast<int>(input->readULong(4));
2543
401k
    if (val) f << "g1=" << val << ",";
2544
401k
  }
2545
2546
459k
  input->seek(header.m_pos.end()-2, librevenge::RVNG_SEEK_SET);
2547
459k
  auto N = static_cast<int>(input->readULong(2));
2548
1.20M
  for (int i = 0; i < N; i++) {
2549
965k
    long pos = input->tell();
2550
965k
    MWAWEntry childZone;
2551
965k
    int childId = getEntryPicture(header.m_zoneId, childZone, false);
2552
965k
    if (childId < 0) {
2553
216k
      MWAW_DEBUG_MSG(("MsWksGraph::readGroup: can not find child\n"));
2554
216k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2555
216k
      f << "#child,";
2556
216k
      break;
2557
216k
    }
2558
749k
    group->m_childs.push_back(childId);
2559
749k
  }
2560
459k
  group->m_extra += f.str();
2561
459k
  group->m_pos.setEnd(input->tell());
2562
459k
  return group;
2563
459k
}
2564
2565
// read/send a textbox zone
2566
bool MsWksGraph::readText(MsWksGraphInternal::TextBox &textBox)
2567
7.93M
{
2568
7.93M
  if (textBox.m_numPositions < 0) return false; // can an empty text exist
2569
2570
7.93M
  libmwaw::DebugFile &ascFile = m_document.ascii();
2571
7.93M
  libmwaw::DebugStream f;
2572
7.93M
  f << "Entries(SmallText):";
2573
7.93M
  MWAWInputStreamPtr input=m_document.getInput();
2574
7.93M
  long pos = input->tell();
2575
7.93M
  if (!input->checkPosition(pos+4*(textBox.m_numPositions+1))) return false;
2576
2577
  // first read the set of (positions, font)
2578
6.68M
  f << "pos=[";
2579
6.68M
  int nbFonts = 0;
2580
19.2M
  for (int i = 0; i <= textBox.m_numPositions; i++) {
2581
13.9M
    auto fPos = static_cast<int>(input->readLong(2));
2582
13.9M
    auto form = static_cast<int>(input->readLong(2));
2583
13.9M
    f << fPos << ":" << form << ", ";
2584
2585
13.9M
    if (fPos < 0 || form < -1) return false;
2586
12.5M
    if ((form == -1 && i != textBox.m_numPositions) ||
2587
12.3M
        (!textBox.m_positions.empty() && fPos < textBox.m_positions.back())) {
2588
2.98M
      MWAW_DEBUG_MSG(("MsWksGraph::readText: find odd positions\n"));
2589
2.98M
      f << "#";
2590
2.98M
      continue;
2591
2.98M
    }
2592
2593
9.61M
    textBox.m_positions.push_back(fPos);
2594
9.61M
    textBox.m_formats.push_back(form);
2595
9.61M
    if (form >= nbFonts) nbFonts = form+1;
2596
9.61M
  }
2597
5.34M
  f << "] ";
2598
5.34M
  ascFile.addPos(pos);
2599
5.34M
  ascFile.addNote(f.str().c_str());
2600
2601
5.34M
  pos = input->tell();
2602
5.34M
  f.str("");
2603
5.34M
  f << "SmallText:Fonts ";
2604
2605
  // actualPos, -1, only exists if actualPos!= 0 ? We ignored it.
2606
5.34M
  input->readLong(2);
2607
5.34M
  if (input->readLong(2) != -1)
2608
4.09M
    input->seek(pos,librevenge::RVNG_SEEK_SET);
2609
1.25M
  else {
2610
1.25M
    ascFile.addPos(pos);
2611
1.25M
    ascFile.addNote("SmallText:char Pos");
2612
1.25M
    pos = input->tell();
2613
1.25M
  }
2614
5.34M
  f.str("");
2615
2616
5.34M
  long endFontPos = input->tell();
2617
5.34M
  auto sizeOfData = long(input->readULong(4));
2618
5.34M
  int numFonts = (sizeOfData%0x12 == 0) ? int(sizeOfData/0x12) : 0;
2619
2620
5.34M
  if (numFonts >= nbFonts) {
2621
2.88M
    endFontPos = input->tell()+4+sizeOfData;
2622
2623
2.88M
    ascFile.addPos(pos);
2624
2.88M
    ascFile.addNote("SmallText: Fonts");
2625
2626
12.4M
    for (int i = 0; i < numFonts; i++) {
2627
11.7M
      pos = input->tell();
2628
11.7M
      MWAWFont font;
2629
11.7M
      if (!readFont(font)) {
2630
2.25M
        input->seek(endFontPos, librevenge::RVNG_SEEK_SET);
2631
2.25M
        break;
2632
2.25M
      }
2633
9.53M
      textBox.m_fontsList.push_back(font);
2634
2635
9.53M
      f.str("");
2636
9.53M
      f << "SmallText:Font"<< i
2637
9.53M
        << "(" << font.getDebugString(m_parserState->m_fontConverter) << "),";
2638
2639
9.53M
      ascFile.addPos(pos);
2640
9.53M
      ascFile.addNote(f.str().c_str());
2641
9.53M
      pos = input->tell();
2642
9.53M
    }
2643
2.88M
  }
2644
5.34M
  int nChar = textBox.m_positions.back()-1;
2645
5.34M
  if (nbFonts > int(textBox.m_fontsList.size())) {
2646
3.93M
    MWAW_DEBUG_MSG(("MsWksGraph::readText: can not read the fonts\n"));
2647
3.93M
    ascFile.addPos(pos);
2648
3.93M
    ascFile.addNote("SmallText:###");
2649
3.93M
    input->seek(endFontPos,librevenge::RVNG_SEEK_SET);
2650
3.93M
    textBox.m_fontsList.resize(0);
2651
3.93M
    textBox.m_positions.resize(0);
2652
3.93M
    textBox.m_numPositions = 0;
2653
3.93M
  }
2654
2655
  // now, syntax is : long(size) + size char
2656
  //      - 0x16 - 0 - 0 - Fonts (default fonts)
2657
  //      - 0x08 followed by two long, maybe interesting to look
2658
  //      - 0x0c (or 0x18) seems followed by small int
2659
  //      - nbChar : the strings (final)
2660
2661
5.34M
  f.str("");
2662
5.34M
  f << "SmallText:";
2663
8.34M
  while (1) {
2664
8.34M
    if (input->isEnd()) return false;
2665
2666
5.34M
    pos = input->tell();
2667
5.34M
    sizeOfData = long(input->readULong(4));
2668
5.34M
    if (sizeOfData == nChar) {
2669
137k
      bool ok = true;
2670
      // ok we try to read the string
2671
137k
      std::string chaine("");
2672
857k
      for (long i = 0; i < sizeOfData; i++) {
2673
851k
        auto c = static_cast<unsigned char>(input->readULong(1));
2674
851k
        if (c == 0) {
2675
130k
          ok = false;
2676
130k
          break;
2677
130k
        }
2678
720k
        chaine += char(c);
2679
720k
      }
2680
2681
137k
      if (!ok)
2682
130k
        input->seek(pos+4,librevenge::RVNG_SEEK_SET);
2683
6.45k
      else {
2684
6.45k
        textBox.m_text = chaine;
2685
6.45k
        f << "=" << chaine;
2686
6.45k
        ascFile.addPos(pos);
2687
6.45k
        ascFile.addNote(f.str().c_str());
2688
6.45k
        return true;
2689
6.45k
      }
2690
137k
    }
2691
2692
5.33M
    if (sizeOfData <= 100+nChar && (sizeOfData%2==0)) {
2693
2.99M
      if (input->seek(sizeOfData, librevenge::RVNG_SEEK_CUR) != 0) return false;
2694
2.99M
      f << "#";
2695
2.99M
      ascFile.addPos(pos);
2696
2.99M
      ascFile.addNote(f.str().c_str());
2697
2.99M
      f.str("");
2698
2.99M
      f << "SmallText:Text";
2699
2.99M
      continue;
2700
2.99M
    }
2701
2702
    // fixme: we can try to find the next string
2703
2.34M
    MWAW_DEBUG_MSG(("MsWksGraph::readText: problem reading text\n"));
2704
2.34M
    f << "#";
2705
2.34M
    ascFile.addPos(pos);
2706
2.34M
    ascFile.addNote(f.str().c_str());
2707
2708
2.34M
    break;
2709
5.33M
  }
2710
2.34M
  return false;
2711
5.34M
}
2712
2713
bool MsWksGraph::readFont(MWAWFont &font)
2714
11.7M
{
2715
11.7M
  int vers = version();
2716
11.7M
  MWAWInputStreamPtr input=m_document.getInput();
2717
11.7M
  long pos = input->tell();
2718
11.7M
  libmwaw::DebugStream f;
2719
11.7M
  if (!input->checkPosition(pos+18))
2720
2.25M
    return false;
2721
9.53M
  font = MWAWFont();
2722
38.1M
  for (int i = 0; i < 3; i++) {
2723
28.6M
    auto val = static_cast<int>(input->readLong(2));
2724
28.6M
    if (val)
2725
17.6M
      f << "f" << i << "=" << val << ",";
2726
28.6M
  }
2727
9.53M
  font.setFont(static_cast<int>(input->readULong(2)));
2728
9.53M
  auto flags = static_cast<int>(input->readULong(1));
2729
9.53M
  uint32_t flag = 0;
2730
9.53M
  if (flags & 0x1) flag |= MWAWFont::boldBit;
2731
9.53M
  if (flags & 0x2) flag |= MWAWFont::italicBit;
2732
9.53M
  if (flags & 0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
2733
9.53M
  if (flags & 0x8) flag |= MWAWFont::embossBit;
2734
9.53M
  if (flags & 0x10) flag |= MWAWFont::shadowBit;
2735
9.53M
  if (flags & 0x20) {
2736
2.56M
    if (vers==1)
2737
221k
      font.set(MWAWFont::Script(20,librevenge::RVNG_PERCENT,80));
2738
2.34M
    else
2739
2.34M
      font.set(MWAWFont::Script::super100());
2740
2.56M
  }
2741
9.53M
  if (flags & 0x40) {
2742
2.17M
    if (vers==1)
2743
19.6k
      font.set(MWAWFont::Script(-20,librevenge::RVNG_PERCENT,80));
2744
2.15M
    else
2745
2.15M
      font.set(MWAWFont::Script::sub100());
2746
2.17M
  }
2747
9.53M
  if (flags & 0x80) f << "#smaller,";
2748
9.53M
  font.setFlags(flag);
2749
2750
9.53M
  auto val = static_cast<int>(input->readULong(1));
2751
9.53M
  if (val) f << "#flags2=" << val << ",";
2752
9.53M
  font.setSize(float(input->readULong(2)));
2753
2754
9.53M
  unsigned char color[3];
2755
28.6M
  for (auto &c : color) c = static_cast<unsigned char>(input->readULong(2)>>8);
2756
9.53M
  font.setColor(MWAWColor(color[0],color[1],color[2]));
2757
9.53M
  font.m_extra = f.str();
2758
9.53M
  return true;
2759
11.7M
}
2760
2761
void MsWksGraph::sendTextBox(int zoneId, MWAWListenerPtr listener)
2762
24.7k
{
2763
24.7k
  if (!listener || !listener->canWriteText()) {
2764
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: can not find get access to the listener\n"));
2765
0
    return;
2766
0
  }
2767
24.7k
  if (zoneId < 0 || zoneId >= int(m_state->m_zonesList.size())) {
2768
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: can not find textbox %d\n", zoneId));
2769
0
    return;
2770
0
  }
2771
24.7k
  auto zone = m_state->m_zonesList[size_t(zoneId)];
2772
24.7k
  if (!zone) return;
2773
24.7k
  auto &textBox = static_cast<MsWksGraphInternal::TextBox &>(*zone);
2774
24.7k
  listener->setFont(MWAWFont(20,12));
2775
24.7k
  MWAWParagraph para;
2776
24.7k
  para.m_justify=textBox.m_justify;
2777
24.7k
  listener->setParagraph(para);
2778
24.7k
  auto numFonts = int(textBox.m_fontsList.size());
2779
24.7k
  int actFormatPos = 0;
2780
24.7k
  auto numFormats = int(textBox.m_formats.size());
2781
24.7k
  if (numFormats != int(textBox.m_positions.size())) {
2782
22.4k
    MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: positions and formats have different length\n"));
2783
22.4k
    if (numFormats > int(textBox.m_positions.size()))
2784
22.4k
      numFormats = int(textBox.m_positions.size());
2785
22.4k
  }
2786
151k
  for (size_t i = 0; i < textBox.m_text.length(); i++) {
2787
126k
    if (actFormatPos < numFormats && textBox.m_positions[size_t(actFormatPos)]==int(i)) {
2788
57
      int id = textBox.m_formats[size_t(actFormatPos++)];
2789
57
      if (id < 0 || id >= numFonts) {
2790
0
        MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: can not find a font\n"));
2791
0
      }
2792
57
      else
2793
57
        listener->setFont(textBox.m_fontsList[size_t(id)]);
2794
57
    }
2795
126k
    auto c = static_cast<unsigned char>(textBox.m_text[i]);
2796
126k
    switch (c) {
2797
9.42k
    case 0x9:
2798
9.42k
      MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: find some tab\n"));
2799
9.42k
      listener->insertChar(' ');
2800
9.42k
      break;
2801
44.0k
    case 0xd:
2802
44.0k
      if (i+1 != textBox.m_text.length())
2803
43.7k
        listener->insertEOL();
2804
44.0k
      break;
2805
3.71k
    case 0x19:
2806
3.71k
      listener->insertField(MWAWField(MWAWField::Title));
2807
3.71k
      break;
2808
7.76k
    case 0x18:
2809
7.76k
      listener->insertField(MWAWField(MWAWField::PageNumber));
2810
7.76k
      break;
2811
2.47k
    case 0x16:
2812
2.47k
      MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: find some time\n"));
2813
2.47k
      listener->insertField(MWAWField(MWAWField::Time));
2814
2.47k
      break;
2815
4.28k
    case 0x17:
2816
4.28k
      MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: find some date\n"));
2817
4.28k
      listener->insertField(MWAWField(MWAWField::Date));
2818
4.28k
      break;
2819
2.69k
    case 0x14: // fixme
2820
2.69k
      MWAW_DEBUG_MSG(("MsWksGraph::sendTextBox: footnote are not implemented\n"));
2821
2.69k
      break;
2822
52.3k
    default:
2823
52.3k
      listener->insertCharacter(c);
2824
52.3k
      break;
2825
126k
    }
2826
126k
  }
2827
24.7k
}
2828
2829
void MsWksGraph::send(int id, MWAWPosition const &pos)
2830
3.17M
{
2831
3.17M
  if (id < 0 || id >= int(m_state->m_zonesList.size())) {
2832
0
    MWAW_DEBUG_MSG(("MsWksGraph::send: can not find zone %d\n", id));
2833
0
    return;
2834
0
  }
2835
3.17M
  MWAWListenerPtr listener=m_parserState->getMainListener();
2836
3.17M
  if (!listener) return;
2837
3.17M
  auto zone = m_state->m_zonesList[size_t(id)];
2838
3.17M
  zone->m_isSent = true;
2839
2840
3.17M
  MWAWPosition pictPos(pos);
2841
3.17M
  if (pos.size()[0]<=0 || pos.size()[1]<=0)
2842
2.69M
    pictPos = zone->getPosition(pos.m_anchorTo);
2843
3.17M
  if (pictPos.m_anchorTo == MWAWPosition::Page)
2844
1.28M
    pictPos.setOrigin(pictPos.origin()+m_state->m_leftTopPos);
2845
2846
3.17M
  MWAWInputStreamPtr input=m_document.getInput();
2847
3.17M
  bool isDraw=listener->getType()==MWAWListener::Graphic;
2848
3.17M
  switch (zone->type()) {
2849
21.9k
  case MsWksGraphInternal::Zone::Text: {
2850
21.9k
    auto &textbox = static_cast<MsWksGraphInternal::TextBox &>(*zone);
2851
21.9k
    MWAWBox2f box(MWAWVec2f(0,0),textbox.m_box.size());
2852
21.9k
    std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2853
21.9k
    (new MsWksGraphInternal::SubDocument(*this, input, MsWksGraphInternal::SubDocument::TextBox, id));
2854
    // a textbox can not have border
2855
21.9k
    MWAWGraphicStyle style(textbox.m_style);
2856
21.9k
    style.m_lineWidth=0;
2857
21.9k
    if (isDraw) {
2858
18.2k
      listener->insertTextBox(pictPos, subdoc, style);
2859
18.2k
      return;
2860
18.2k
    }
2861
3.65k
    MWAWPosition textPos(box[0], box.size(), librevenge::RVNG_POINT);
2862
3.65k
    MWAWGraphicEncoder graphicEncoder;
2863
3.65k
    MWAWGraphicListener graphicListener(*m_parserState, box, &graphicEncoder);
2864
3.65k
    graphicListener.startDocument();
2865
3.65k
    textPos.m_anchorTo=MWAWPosition::Page;
2866
3.65k
    textPos.m_wrapping=pos.m_wrapping;
2867
3.65k
    graphicListener.insertTextBox(textPos, subdoc, style);
2868
3.65k
    graphicListener.endDocument();
2869
3.65k
    MWAWEmbeddedObject picture;
2870
3.65k
    if (graphicEncoder.getBinaryResult(picture))
2871
3.65k
      listener->insertPicture(pictPos, picture);
2872
3.65k
    return;
2873
21.9k
  }
2874
13.2k
  case MsWksGraphInternal::Zone::TableZone: {
2875
13.2k
    auto &table = static_cast<MsWksGraphInternal::Table &>(*zone);
2876
13.2k
    if (isDraw) {
2877
13.2k
      listener->openFrame(pictPos, zone->m_style);
2878
13.2k
      m_tableParser->sendTable(table.m_tableId);
2879
13.2k
      listener->closeFrame();
2880
13.2k
      return;
2881
13.2k
    }
2882
0
    std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2883
0
    (new MsWksGraphInternal::SubDocument(*this, input, MsWksGraphInternal::SubDocument::Table, table.m_tableId));
2884
0
    listener->insertTextBox(pictPos, subdoc, zone->m_style);
2885
0
    return;
2886
13.2k
  }
2887
364
  case MsWksGraphInternal::Zone::ChartZone: {
2888
364
    auto &chart = static_cast<MsWksGraphInternal::Chart &>(*zone);
2889
364
    std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2890
364
    (new MsWksGraphInternal::SubDocument(*this, input, MsWksGraphInternal::SubDocument::Chart, chart.m_chartId));
2891
364
    listener->insertTextBox(pictPos, subdoc, zone->m_style);
2892
364
    return;
2893
13.2k
  }
2894
252k
  case MsWksGraphInternal::Zone::Group:
2895
252k
    sendGroup(id, pictPos);
2896
252k
    return;
2897
0
  case MsWksGraphInternal::Zone::Bitmap: {
2898
0
    auto &bmap = static_cast<MsWksGraphInternal::DataBitmap &>(*zone);
2899
0
    MWAWEmbeddedObject picture;
2900
0
    if (!bmap.getPictureData(input, picture,m_document.getPalette(4)))
2901
0
      break;
2902
0
    m_document.ascii().skipZone(bmap.m_dataPos, bmap.m_pos.end()-1);
2903
0
    listener->insertPicture(pictPos, picture, zone->m_style);
2904
0
    return;
2905
0
  }
2906
2.52M
  case MsWksGraphInternal::Zone::Shape: {
2907
2.52M
    auto &shape = static_cast<MsWksGraphInternal::BasicShape &>(*zone);
2908
2.52M
    listener->insertShape(pictPos, shape.m_shape, shape.getStyle());
2909
2.52M
    return;
2910
0
  }
2911
106k
  case MsWksGraphInternal::Zone::Pict: {
2912
106k
    MWAWEmbeddedObject picture;
2913
106k
    if (!zone->getBinaryData(input, picture))
2914
66.0k
      break;
2915
40.8k
    listener->insertPicture(pictPos, picture, zone->m_style);
2916
40.8k
    return;
2917
106k
  }
2918
174k
  case MsWksGraphInternal::Zone::Textv4: {
2919
174k
    auto &textbox = static_cast<MsWksGraphInternal::TextBoxv4 &>(*zone);
2920
174k
    std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
2921
174k
    (new MsWksGraphInternal::SubDocument(*this, input, MsWksGraphInternal::SubDocument::TextBoxv4, textbox.m_text, textbox.m_frame));
2922
174k
    MWAWGraphicStyle style;
2923
174k
    zone->fillFrame(style);
2924
    // a textbox can not have a border
2925
174k
    style.m_lineWidth=0;
2926
174k
    if (zone->m_ids[1] > 0) {
2927
15.0k
      librevenge::RVNGString fName;
2928
15.0k
      fName.sprintf("Frame%ld", zone->m_ids[0]);
2929
15.0k
      style.m_frameName=fName.cstr();
2930
15.0k
    }
2931
174k
    if (zone->m_ids[2] > 0) {
2932
0
      librevenge::RVNGString fName;
2933
0
      fName.sprintf("Frame%ld", zone->m_ids[2]);
2934
0
      style.m_frameNextName=fName.cstr();
2935
0
    }
2936
174k
    listener->insertTextBox(pictPos, subdoc, style);
2937
174k
    return;
2938
106k
  }
2939
77.5k
  case MsWksGraphInternal::Zone::OLE: {
2940
77.5k
    auto &ole = static_cast<MsWksGraphInternal::OLEZone &>(*zone);
2941
77.5k
    m_document.sendOLE(ole.m_oleId, pictPos, zone->m_style);
2942
77.5k
    return;
2943
106k
  }
2944
0
  case MsWksGraphInternal::Zone::Unknown:
2945
#if !defined(__clang__)
2946
  default:
2947
#endif
2948
0
    break;
2949
3.17M
  }
2950
2951
66.0k
  MWAW_DEBUG_MSG(("MsWksGraph::send: can not send zone %d\n", id));
2952
66.0k
}
2953
2954
void MsWksGraph::sendAll(int zoneId, bool mainZone)
2955
1.65M
{
2956
1.65M
  MWAWPosition undefPos;
2957
7.83M
  for (size_t i = 0; i < m_state->m_zonesList.size(); i++) {
2958
6.18M
    auto zone = m_state->m_zonesList[i];
2959
6.18M
    if (zoneId >= 0 && zoneId!=zone->m_zoneId)
2960
2.45M
      continue;
2961
3.72M
    if (zone->m_doNotSend || (zone->m_isSent && mainZone))
2962
1.18M
      continue;
2963
2.54M
    undefPos.m_anchorTo = mainZone ? MWAWPosition::Page : MWAWPosition::Paragraph;
2964
2.54M
    send(int(i), undefPos);
2965
2.54M
  }
2966
1.65M
}
2967
2968
void MsWksGraph::sendObjects(MsWksGraph::SendData const &what)
2969
4.70M
{
2970
4.70M
  MWAWListenerPtr listener=m_parserState->getMainListener();
2971
4.70M
  if (!listener) {
2972
0
    MWAW_DEBUG_MSG(("MsWksGraph::sendObjects: listener is not set\n"));
2973
0
    return;
2974
0
  }
2975
2976
4.70M
  bool first = true;
2977
4.70M
  auto numZones = int(m_state->m_zonesList.size());
2978
4.70M
  std::vector<int> listIds;
2979
4.70M
  MsWksGraphInternal::RBZone *rbZone=nullptr;
2980
4.70M
  switch (what.m_type) {
2981
0
  case MsWksGraph::SendData::ALL:
2982
0
    listIds.resize(size_t(numZones));
2983
0
    for (int i = 0; i < numZones; i++) listIds[size_t(i)]=i;
2984
0
    break;
2985
3.65M
  case MsWksGraph::SendData::RBDR:
2986
4.70M
  case MsWksGraph::SendData::RBIL: {
2987
4.70M
    int zId = what.m_type==MsWksGraph::SendData::RBDR ? -1 : what.m_id;
2988
4.70M
    if (m_state->m_RBsMap.find(zId)!=m_state->m_RBsMap.end())
2989
3.89M
      rbZone = &m_state->m_RBsMap.find(zId)->second;
2990
4.70M
    break;
2991
3.65M
  }
2992
#if !defined(__clang__)
2993
  default:
2994
    break;
2995
#endif
2996
4.70M
  }
2997
4.70M
  if (rbZone)
2998
3.89M
    listIds=rbZone->m_idList;
2999
4.70M
  bool isText=m_parserState->m_type==MWAWParserState::Text;
3000
4.70M
  if (isText && what.m_type==MsWksGraph::SendData::RBIL) {
3001
0
    if (!rbZone) {
3002
0
      MWAW_DEBUG_MSG(("MsWksGraph::sendObjects: can find RBIL zone %d\n", what.m_id));
3003
0
      return;
3004
0
    }
3005
0
    if (listIds.size() != 1) {
3006
0
      if (what.m_anchor == MWAWPosition::Char ||
3007
0
          what.m_anchor == MWAWPosition::CharBaseLine) {
3008
0
        std::shared_ptr<MsWksGraphInternal::SubDocument> subdoc
3009
0
        (new MsWksGraphInternal::SubDocument(*this, m_document.getInput(), MsWksGraphInternal::SubDocument::RBILZone, what.m_id));
3010
0
        MWAWPosition pictPos(MWAWVec2f(0,0), MWAWVec2f(what.m_size), librevenge::RVNG_POINT);
3011
0
        pictPos.setRelativePosition(MWAWPosition::Char,
3012
0
                                    MWAWPosition::XLeft, MWAWPosition::YTop);
3013
0
        pictPos.m_wrapping =  MWAWPosition::WBackground;
3014
0
        listener->insertTextBox(pictPos, subdoc);
3015
0
        return;
3016
0
      }
3017
0
    }
3018
0
  }
3019
4.70M
  MWAWPosition undefPos;
3020
4.70M
  undefPos.m_anchorTo = what.m_anchor;
3021
19.8M
  for (auto id : listIds) {
3022
19.8M
    if (id < 0 || id >= numZones) continue;
3023
19.8M
    auto zone = m_state->m_zonesList[size_t(id)];
3024
19.8M
    if (!zone || zone->m_doNotSend) continue;
3025
18.7M
    if (zone->m_isSent) {
3026
7.69M
      if (what.m_type == MsWksGraph::SendData::ALL ||
3027
7.69M
          (isText && what.m_anchor == MWAWPosition::Page)) continue;
3028
7.69M
    }
3029
18.7M
    if (what.m_anchor == MWAWPosition::Page) {
3030
18.7M
      if (what.m_page > 0 && zone->m_page+1 != what.m_page) continue;
3031
580k
      else if (what.m_page==0 && zone->m_page < 0) continue;
3032
580k
      else if (what.m_page==-2 && zone->m_page >=0) continue;
3033
580k
      undefPos=zone->getPosition(MWAWPosition::Page);
3034
580k
    }
3035
3036
580k
    if (isText && first) {
3037
0
      first = false;
3038
0
      if (what.m_anchor == MWAWPosition::Page && !listener->isSectionOpened() && !listener->isParagraphOpened())
3039
0
        listener->insertChar(' ');
3040
0
    }
3041
580k
    send(int(id), undefPos);
3042
580k
  }
3043
4.70M
}
3044
3045
void MsWksGraph::flushExtra()
3046
57.4k
{
3047
57.4k
  MWAWPosition undefPos;
3048
57.4k
  undefPos.m_anchorTo=MWAWPosition::Char;
3049
1.18M
  for (size_t i = 0; i < m_state->m_zonesList.size(); i++) {
3050
1.12M
    auto zone = m_state->m_zonesList[i];
3051
1.12M
    if (!zone || zone->m_isSent || zone->m_doNotSend) continue;
3052
8.89k
    send(int(i), undefPos);
3053
8.89k
  }
3054
57.4k
}
3055
3056
////////////////////////////////////////////////////////////
3057
// style
3058
////////////////////////////////////////////////////////////
3059
MsWksGraph::Style::~Style()
3060
127M
{
3061
127M
}
3062
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: