Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/QuattroGraph.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwps
3
 * Version: MPL 2.0 / LGPLv2.1+
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * Major Contributor(s):
10
 * Copyright (C) 2006, 2007 Andrew Ziem
11
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
12
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 *
14
 * For minor contributions see the git repository.
15
 *
16
 * Alternatively, the contents of this file may be used under the terms
17
 * of the GNU Lesser General Public License Version 2.1 or later
18
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
19
 * applicable instead of those above.
20
 */
21
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include <cmath>
26
#include <sstream>
27
#include <limits>
28
#include <map>
29
#include <stack>
30
31
#include <librevenge-stream/librevenge-stream.h>
32
33
#include "libwps_internal.h"
34
#include "libwps_tools_win.h"
35
36
#include "WKSContentListener.h"
37
#include "WKSSubDocument.h"
38
39
#include "WPSEntry.h"
40
#include "WPSFont.h"
41
#include "WPSGraphicShape.h"
42
#include "WPSGraphicStyle.h"
43
#include "WPSOLEObject.h"
44
#include "WPSParagraph.h"
45
#include "WPSPosition.h"
46
#include "WPSStream.h"
47
48
#include "Quattro.h"
49
50
#include "QuattroGraph.h"
51
52
namespace QuattroGraphInternal
53
{
54
//! a dialog header
55
struct Dialog
56
{
57
  //! constructor
58
  explicit Dialog()
59
12.7k
    : m_cellBox()
60
12.7k
  {
61
63.6k
    for (auto &f : m_flags1) f=0;
62
114k
    for (auto &f : m_flags2) f=0;
63
12.7k
  }
64
  //! operator<<
65
  friend std::ostream &operator<<(std::ostream &o, Dialog const &gr);
66
  //! the cell's position
67
  WPSBox2i m_cellBox;
68
  //! some flags
69
  int m_flags1[5];
70
  //! final flag
71
  int m_flags2[9];
72
};
73
74
std::ostream &operator<<(std::ostream &o, Dialog const &dlg)
75
0
{
76
0
  if (dlg.m_cellBox!=WPSBox2i()) o << "cellBox=" << dlg.m_cellBox << ",";
77
0
  o << "fl1=[";
78
0
  for (auto f : dlg.m_flags1)
79
0
  {
80
0
    if (f)
81
0
      o << std::hex << f << std::dec << ",";
82
0
    else
83
0
      o << "_,";
84
0
  }
85
0
  o << "],";
86
0
  o << "fl2=[";
87
0
  for (auto f : dlg.m_flags2)
88
0
  {
89
0
    if (f)
90
0
      o << std::hex << f << std::dec << ",";
91
0
    else
92
0
      o << "_,";
93
0
  }
94
0
  o << "],";
95
0
  return o;
96
0
}
97
98
//! a shape header of a QuattroGraph
99
struct ShapeHeader
100
{
101
  //! constructor
102
  ShapeHeader()
103
204k
    : m_type(0)
104
204k
    , m_box()
105
204k
    , m_id(0)
106
204k
    , m_style()
107
204k
    , m_extra()
108
204k
  {
109
2.86M
    for (auto &f : m_flags) f=0;
110
1.02M
    for (auto &v : m_values) v=0;
111
819k
    for (auto &v : m_values2) v=0;
112
204k
  }
113
  //! destructor
114
  virtual ~ShapeHeader();
115
  //! returns true if the shape is a textbox
116
  virtual bool isTextbox() const
117
94.6k
  {
118
94.6k
    return false;
119
94.6k
  }
120
  //! operator<<
121
  friend std::ostream &operator<<(std::ostream &o, ShapeHeader const &sh);
122
  //! the type
123
  int m_type;
124
  //! the bdbox
125
  WPSBox2i m_box;
126
  //! an id?
127
  int m_id;
128
  //! the graphic style
129
  WPSGraphicStyle m_style;
130
  //! optional values
131
  int m_values[5];
132
  //! some flags
133
  int m_flags[14];
134
135
  //
136
  // style
137
  //
138
139
  //! style values
140
  int m_values2[4];
141
  //! error message
142
  std::string m_extra;
143
};
144
145
ShapeHeader::~ShapeHeader()
146
204k
{
147
204k
}
148
149
std::ostream &operator<<(std::ostream &o, ShapeHeader const &sh)
150
0
{
151
0
  o << "type=" << sh.m_type << ",";
152
0
  o << "box=" << sh.m_box << ",";
153
0
  if (sh.m_id) o << "id=" << sh.m_id << ",";
154
0
  o << sh.m_style << ",";
155
0
  int wh=0;
156
0
  for (auto v : sh.m_values)
157
0
  {
158
0
    if (v) o << "f" << wh << "=" << v << ",";
159
0
    ++wh;
160
0
  }
161
0
  o << "unkn[";
162
0
  for (auto f : sh.m_flags)
163
0
  {
164
0
    if (f)
165
0
      o << std::hex << f << std::dec << ",";
166
0
    else
167
0
      o << ",";
168
0
  }
169
0
  o << "],";
170
0
  wh=0;
171
0
  for (auto v : sh.m_values2)
172
0
  {
173
0
    if (v) o << "g" << wh << "=" << v << ",";
174
0
    ++wh;
175
0
  }
176
0
  o << sh.m_extra << ",";
177
0
  return o;
178
0
}
179
180
//! Internal: a shape of a QuattroGraph
181
struct Shape final : public ShapeHeader
182
{
183
  //! constructor
184
  Shape()
185
186k
    : ShapeHeader()
186
186k
    , m_shape()
187
186k
  {
188
186k
  }
189
  //! destructor
190
  ~Shape() final;
191
  //! the graphic shape
192
  WPSGraphicShape m_shape;
193
};
194
195
Shape::~Shape()
196
186k
{
197
186k
}
198
199
//! Internal: a shape of a QuattroGraph
200
struct Textbox final : public ShapeHeader
201
{
202
  //! constructor
203
  Textbox()
204
18.1k
    : ShapeHeader()
205
18.1k
    , m_entry()
206
18.1k
    , m_font()
207
18.1k
    , m_paragraph()
208
18.1k
  {
209
18.1k
  }
210
  //! destructor
211
  ~Textbox() final;
212
  //! returns true
213
  bool isTextbox() const final
214
15.0k
  {
215
15.0k
    return true;
216
15.0k
  }
217
  //! the text entry
218
  WPSEntry m_entry;
219
  //! the font
220
  WPSFont m_font;
221
  //! the paragraph style
222
  WPSParagraph m_paragraph;
223
};
224
225
Textbox::~Textbox()
226
18.1k
{
227
18.1k
}
228
229
//! Internal: a graph of a QuattroGraph
230
struct Graph
231
{
232
  //! the posible type
233
  enum Type { Button, Chart, Frame, OLE/* or bitmap */, Image, Shape, Textbox, Unknown };
234
  //! constructor
235
  explicit Graph(std::shared_ptr<WPSStream> const &stream, Type type=Unknown)
236
184k
    : m_type(type)
237
184k
    , m_size()
238
184k
    , m_cellBox()
239
184k
    , m_cellBoxDecal()
240
184k
    , m_label()
241
184k
    , m_ole()
242
184k
    , m_linkName()
243
184k
    , m_shape()
244
184k
    , m_textbox()
245
184k
    , m_stream(stream)
246
184k
  {
247
739k
    for (auto &f : m_flags1) f=0;
248
1.29M
    for (auto &f : m_flags2) f=0;
249
924k
    for (auto &v : m_values) v=0;
250
184k
  }
251
  //! operator<<
252
  friend std::ostream &operator<<(std::ostream &o, Graph const &gr);
253
  //! the type
254
  Type m_type;
255
  //! the size
256
  Vec2f m_size;
257
  //! the cell's position
258
  WPSBox2i m_cellBox;
259
  //! the decal position(LT, RB)
260
  WPSBox2f m_cellBoxDecal;
261
  //! some flags
262
  int m_flags1[4];
263
  //! final flag
264
  int m_flags2[7];
265
  //! some values
266
  int m_values[5];
267
268
  //! the label(button)
269
  librevenge::RVNGString m_label;
270
271
  //! the OLE's data
272
  WPSEmbeddedObject m_ole;
273
  //! the OLE's link name
274
  librevenge::RVNGString m_linkName;
275
276
  //! the graphic shape
277
  std::shared_ptr<QuattroGraphInternal::Shape> m_shape;
278
  //! the textbox
279
  std::shared_ptr<QuattroGraphInternal::Textbox> m_textbox;
280
281
  //! the main stream
282
  std::shared_ptr<WPSStream> m_stream;
283
};
284
285
std::ostream &operator<<(std::ostream &o, Graph const &gr)
286
0
{
287
0
  if (gr.m_size!=Vec2f()) o << "size=" << gr.m_size << ",";
288
0
  if (gr.m_cellBox!=WPSBox2i()) o << "cellBox=" << gr.m_cellBox << ",";
289
0
  if (gr.m_cellBoxDecal!=WPSBox2f()) o << "cellBox[decal]=" << gr.m_cellBoxDecal << ",";
290
0
  o << "fl1=[";
291
0
  for (auto f : gr.m_flags1)
292
0
  {
293
0
    if (f)
294
0
      o << std::hex << f << std::dec << ",";
295
0
    else
296
0
      o << "_,";
297
0
  }
298
0
  o << "],";
299
0
  o << "fl2=[";
300
0
  for (auto f : gr.m_flags2)
301
0
  {
302
0
    if (f)
303
0
      o << std::hex << f << std::dec << ",";
304
0
    else
305
0
      o << "_,";
306
0
  }
307
0
  o << "],";
308
0
  for (int i=0; i<5; ++i)
309
0
  {
310
0
    if (gr.m_values[i])
311
0
      o << "f" << i << "=" << gr.m_values[i] << ",";
312
0
  }
313
0
  return o;
314
0
}
315
316
//! the state of QuattroGraph
317
struct State
318
{
319
  //! constructor
320
  State()
321
47.8k
    : m_version(-1)
322
47.8k
    , m_actualSheet(-1)
323
47.8k
    , m_sheetIdToGraphMap()
324
47.8k
    , m_actualGraph()
325
47.8k
    , m_linkNameToObjectMap()
326
47.8k
  {
327
47.8k
  }
328
  //! store a graph
329
  void storeGraph(std::shared_ptr<Graph> graph)
330
75.6k
  {
331
75.6k
    if (!graph)
332
0
    {
333
0
      WPS_DEBUG_MSG(("QuattroGraphInternal::storeGraph: no graph\n"));
334
0
      return;
335
0
    }
336
75.6k
    m_actualGraph=graph;
337
75.6k
    if (m_actualSheet<0)
338
22.7k
    {
339
22.7k
      WPS_DEBUG_MSG(("QuattroGraphInternal::storeGraph: can not find the current sheet\n"));
340
22.7k
      return;
341
22.7k
    }
342
52.8k
    m_sheetIdToGraphMap.insert(std::multimap<int, std::shared_ptr<Graph> >::value_type(m_actualSheet, graph));
343
52.8k
  }
344
  //! returns the pattern corresponding to a pattern id between 0 and 24
345
  static bool getPattern(int id, WPSGraphicStyle::Pattern &pattern);
346
  //! the file version
347
  int m_version;
348
  //! the actual sheet id
349
  int m_actualSheet;
350
  //! a multimap sheetId to graph
351
  std::multimap<int, std::shared_ptr<Graph> > m_sheetIdToGraphMap;
352
  //! the actual graph
353
  std::shared_ptr<Graph> m_actualGraph;
354
  //! a map link name to object
355
  std::map<librevenge::RVNGString,WPSEmbeddedObject> m_linkNameToObjectMap;
356
};
357
358
bool State::getPattern(int id, WPSGraphicStyle::Pattern &pat)
359
19.2k
{
360
19.2k
  if (id<0 || id>24)
361
16.1k
  {
362
16.1k
    WPS_DEBUG_MSG(("QuattroInternal::State::getPattern(): unknown pattern id: %d\n",id));
363
16.1k
    return false;
364
16.1k
  }
365
3.08k
  static const uint16_t  patterns[]=
366
3.08k
  {
367
3.08k
    0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0x0000, 0x00ff, 0x0000, 0x0101, 0x0101, 0x0101, 0x0101, // 0-3
368
3.08k
    0x8844, 0x2211, 0x8844, 0x2211, 0x8811, 0x2244, 0x8811, 0x2244, 0xff01, 0x0101, 0x0101, 0x0101, 0x040a, 0x11a0, 0x40a0, 0x110a, // 4-7
369
3.08k
    0x44aa, 0x1100, 0x44aa, 0x1100, 0xffff, 0x0000, 0xffff, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x060c, 0x1830, 0x60c0, 0x8103, // 8-9
370
3.08k
    0xc060, 0x3018, 0x0c06, 0x0381, 0xc864, 0x3219, 0x8c46, 0x2391, 0xff11, 0xff11, 0xff11, 0xff11, 0xcccc, 0x3333, 0xcccc, 0x3333,
371
3.08k
    0xcc33, 0xcc33, 0xcc33, 0xcc33, 0x0110, 0x0110, 0x0110, 0x0110, 0x1144, 0x1144, 0x1144, 0x1144, 0x070e, 0x9ee9, 0xe070, 0xb99b,
372
3.08k
    0x0101, 0x01ff, 0x1010, 0x10ff, 0x4080, 0x0103, 0x8448, 0x3020, 0x2011, 0x0204, 0x0811, 0x8040, 0x00aa, 0x00aa, 0x00aa, 0x00aa,
373
3.08k
    0xaa55, 0xaa55, 0xaa55, 0xaa55
374
3.08k
  };
375
3.08k
  pat.m_dim=Vec2i(8,8);
376
3.08k
  uint16_t const *ptr=&patterns[4*id];
377
3.08k
  pat.m_data.resize(8);
378
15.4k
  for (size_t i=0; i < 8; i+=2)
379
12.3k
  {
380
12.3k
    uint16_t val=*(ptr++);
381
12.3k
    pat.m_data[i]=static_cast<unsigned char>((val>>8) & 0xFF);
382
12.3k
    pat.m_data[i+1]=static_cast<unsigned char>(val & 0xFF);
383
12.3k
  }
384
3.08k
  return true;
385
19.2k
}
386
387
//! Internal: the subdocument of a QuattroGraphInternal
388
class SubDocument final : public WKSSubDocument
389
{
390
public:
391
  //! constructor for a textbox document
392
  SubDocument(QuattroGraph &graphParser, std::shared_ptr<Textbox> const &textbox, std::shared_ptr<WPSStream> const &stream)
393
415
    : WKSSubDocument(RVNGInputStreamPtr(), &graphParser.m_mainParser)
394
415
    , m_graphParser(graphParser)
395
415
    , m_textbox(textbox)
396
415
    , m_stream(stream)
397
415
    , m_text() {}
398
  //! constructor for a text entry
399
  SubDocument(QuattroGraph &graphParser, librevenge::RVNGString const &text)
400
877
    : WKSSubDocument(RVNGInputStreamPtr(), &graphParser.m_mainParser)
401
877
    , m_graphParser(graphParser)
402
877
    , m_textbox()
403
877
    , m_stream()
404
877
    , m_text(text) {}
405
  //! destructor
406
1.29k
  ~SubDocument() final {}
407
408
  //! operator==
409
  bool operator==(std::shared_ptr<WPSSubDocument> const &doc) const final
410
0
  {
411
0
    if (!doc || !WKSSubDocument::operator==(doc))
412
0
      return false;
413
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(doc.get());
414
0
    if (!sDoc) return false;
415
0
    if (&m_graphParser != &sDoc->m_graphParser) return false;
416
0
    if (m_textbox.get() != sDoc->m_textbox.get()) return false;
417
0
    if (m_stream.get() != sDoc->m_stream.get()) return false;
418
0
    return m_text == sDoc->m_text;
419
0
  }
420
421
  //! the parser function
422
  void parse(std::shared_ptr<WKSContentListener> &listener, libwps::SubDocumentType subDocumentType) final;
423
  //! the graph parser
424
  QuattroGraph &m_graphParser;
425
  //! the textbox data
426
  std::shared_ptr<Textbox> m_textbox;
427
  //! the file stream
428
  std::shared_ptr<WPSStream> m_stream;
429
  //! the main text
430
  librevenge::RVNGString m_text;
431
};
432
433
void SubDocument::parse(std::shared_ptr<WKSContentListener> &listener, libwps::SubDocumentType)
434
1.29k
{
435
1.29k
  if (!listener.get())
436
0
  {
437
0
    WPS_DEBUG_MSG(("QuattroGraphInternal::SubDocument::parse: no listener\n"));
438
0
    return;
439
0
  }
440
1.29k
  if (!dynamic_cast<WKSContentListener *>(listener.get()))
441
0
  {
442
0
    WPS_DEBUG_MSG(("QuattroGraphInternal::SubDocument::parse: bad listener\n"));
443
0
    return;
444
0
  }
445
1.29k
  if (m_textbox && m_stream)
446
415
  {
447
415
    auto input=m_stream->m_input;
448
415
    long actPos=input->tell();
449
415
    m_graphParser.send(*m_textbox, m_stream);
450
415
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
451
415
    return;
452
415
  }
453
877
  WPSParagraph para;
454
877
  para.m_justify=libwps::JustificationCenter;
455
877
  listener->setParagraph(para);
456
877
  if (!m_text.empty())
457
877
    listener->insertUnicodeString(m_text);
458
877
}
459
460
}
461
462
// constructor, destructor
463
QuattroGraph::QuattroGraph(QuattroParser &parser)
464
23.9k
  : m_listener()
465
23.9k
  , m_mainParser(parser)
466
23.9k
  , m_state(new QuattroGraphInternal::State())
467
23.9k
{
468
23.9k
}
469
470
QuattroGraph::~QuattroGraph()
471
23.9k
{
472
23.9k
}
473
474
void QuattroGraph::cleanState()
475
23.9k
{
476
23.9k
  m_state.reset(new QuattroGraphInternal::State());
477
23.9k
}
478
479
void QuattroGraph::updateState()
480
23.8k
{
481
23.8k
}
482
483
int QuattroGraph::version() const
484
146k
{
485
146k
  if (m_state->m_version<0)
486
2.47k
    m_state->m_version=m_mainParser.version();
487
146k
  return m_state->m_version;
488
146k
}
489
490
void QuattroGraph::storeObjects(std::map<librevenge::RVNGString,WPSEmbeddedObject> const &nameToObjectMap)
491
168
{
492
168
  m_state->m_linkNameToObjectMap=nameToObjectMap;
493
168
}
494
495
std::vector<Vec2i> QuattroGraph::getGraphicCellsInSheet(int sheetId) const
496
641k
{
497
641k
  std::vector<Vec2i> list;
498
641k
  auto it=m_state->m_sheetIdToGraphMap.find(sheetId);
499
693k
  while (it!=m_state->m_sheetIdToGraphMap.end() && it->first==sheetId)
500
51.7k
  {
501
51.7k
    auto const &graph=it++->second;
502
51.7k
    if (graph && graph->m_type!=graph->Shape && graph->m_type!=graph->Textbox)
503
40.0k
      list.push_back(graph->m_cellBox[0]);
504
51.7k
  }
505
641k
  return list;
506
641k
}
507
508
////////////////////////////////////////////////////////////
509
// low level
510
511
////////////////////////////////////////////////////////////
512
// zones
513
////////////////////////////////////////////////////////////
514
bool QuattroGraph::readHeader(QuattroGraphInternal::Graph &header, std::shared_ptr<WPSStream> stream, long endPos)
515
101k
{
516
101k
  auto input=stream->m_input;
517
101k
  long pos = input->tell();
518
101k
  if (endPos-pos<49)
519
0
  {
520
0
    WPS_DEBUG_MSG(("QuattroGraph::readHeader: the zone is too short\n"));
521
0
    return false;
522
0
  }
523
405k
  for (auto &fl : header.m_flags1) fl=int(libwps::readU16(input));
524
101k
  int dim[4];
525
405k
  for (auto &d: dim) d=libwps::readU16(input);
526
101k
  header.m_cellBox=WPSBox2i(Vec2i(dim[0],dim[1]),Vec2i(dim[2],dim[3]));
527
101k
  float fDim[4];
528
405k
  for (auto &d: fDim) d=float(libwps::read16(input))/20.f;
529
101k
  header.m_cellBoxDecal=WPSBox2f(Vec2f(fDim[0],fDim[1]),Vec2f(fDim[2],fDim[3]));
530
303k
  for (int i=0; i<2; ++i) fDim[i]=float(libwps::read32(input))/20.f;
531
101k
  header.m_size=Vec2f(fDim[0],fDim[1]);
532
708k
  for (auto &fl : header.m_flags2) fl=int(libwps::readU8(input));
533
506k
  for (auto &v : header.m_values) v=int(libwps::read16(input));
534
101k
  return true;
535
101k
}
536
537
bool QuattroGraph::readShapeHeader(QuattroGraphInternal::ShapeHeader &shape, std::shared_ptr<WPSStream> stream, long endPos)
538
146k
{
539
146k
  int const vers=version();
540
146k
  auto input=stream->m_input;
541
146k
  long pos = input->tell();
542
146k
  int const endSize=15+(vers==1003 ? 3 : 0);
543
146k
  if (endPos-pos<42+(vers==1003 ? 4 : 0))
544
0
  {
545
0
    WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: the zone is too short\n"));
546
0
    return false;
547
0
  }
548
146k
  libwps::DebugStream f;
549
146k
  shape.m_type=int(libwps::readU16(input)); // v1: 6f, v2: 73, v3: 9e
550
146k
  int wFl=0;
551
734k
  for (int i=0; i<4; ++i)
552
587k
    shape.m_flags[wFl++]=int(libwps::readU16(input));
553
146k
  int dim[4];
554
587k
  for (auto &d: dim) d=int(libwps::read16(input));
555
146k
  shape.m_box=WPSBox2i(Vec2i(dim[0],dim[1]),Vec2i(dim[2],dim[3]));
556
881k
  for (int i=0; i<(vers>=1003 ? 7 : 5); ++i)
557
734k
    shape.m_flags[wFl++]=int(libwps::readU16(input));
558
146k
  shape.m_id=int(libwps::readU16(input));
559
146k
  auto &style=shape.m_style;
560
146k
  WPSColor surfaceColor[2];
561
146k
  unsigned char col[4];
562
587k
  for (auto &c : col) c=libwps::readU8(input);
563
146k
  surfaceColor[0]=WPSColor(col[0],col[1],col[2]);
564
587k
  for (auto &c : col) c=libwps::readU8(input);
565
146k
  style.m_lineColor=WPSColor(col[0],col[1],col[2]);
566
146k
  shape.m_flags[wFl++]=int(libwps::readU16(input));
567
146k
  int hasData[2];
568
293k
  for (auto &d : hasData) d=int(libwps::readU8(input));
569
146k
  if (hasData[0]==1 && endPos-input->tell()>=3+endSize)
570
1.67k
  {
571
1.67k
    shape.m_values[0]=int(libwps::read8(input));
572
1.67k
    shape.m_values[1]=int(libwps::read16(input));
573
1.67k
  }
574
145k
  else if (hasData[0])
575
28.6k
  {
576
28.6k
    WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: find unexpected data0 %d\n", hasData[0]));
577
28.6k
    return false;
578
28.6k
  }
579
118k
  if (hasData[1]==1 && endPos-input->tell()>=6+endSize)
580
1.37k
  {
581
5.48k
    for (int i=0; i<3; ++i)
582
4.11k
      shape.m_values[i+2]=int(libwps::read16(input));
583
1.37k
  }
584
116k
  else if (hasData[1])
585
8.65k
  {
586
8.65k
    WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: find unexpected data1 %d\n", hasData[1]));
587
8.65k
    return false;
588
8.65k
  }
589
590
  // end data
591
109k
  shape.m_values2[0]=int(libwps::readU8(input));
592
109k
  if (vers>=1003)
593
60
  {
594
180
    for (int i=0; i<2; ++i)
595
120
    {
596
120
      int val=i==1 ? int(libwps::read8(input)) : int(libwps::read16(input));
597
120
      shape.m_values2[1+i]=val;
598
120
    }
599
60
  }
600
109k
  int patternId=int(libwps::readU16(input)); // 154: solid
601
109k
  int lineStyle=int(libwps::readU16(input));
602
109k
  switch (lineStyle)
603
109k
  {
604
409
  case 1: // solid
605
409
    break;
606
1.12k
  case 2: // dash
607
1.12k
    style.m_lineDashWidth.push_back(float(4));
608
1.12k
    style.m_lineDashWidth.push_back(float(1));
609
1.12k
    break;
610
231
  case 3: // dots
611
231
    style.m_lineDashWidth.resize(2,float(1));
612
231
    break;
613
3.41k
  case 4: // dash/dots
614
3.41k
    style.m_lineDashWidth.resize(4,float(1));
615
3.41k
    style.m_lineDashWidth[0]=float(4);
616
3.41k
    break;
617
57
  case 5: //
618
57
    style.m_lineDashWidth.resize(6,float(1));
619
57
    style.m_lineDashWidth[0]=float(4);
620
57
    break;
621
162
  case 6: // empty
622
162
    style.m_lineWidth=0;
623
162
    break;
624
104k
  default:
625
104k
    WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: find unknown line style\n"));
626
104k
    f << "line[style]=##" << lineStyle << ",";
627
104k
    break;
628
109k
  }
629
438k
  for (auto &c : col) c=libwps::readU8(input);
630
109k
  surfaceColor[1]=WPSColor(col[0],col[1],col[2]);
631
109k
  int lineWidth=int(libwps::readU16(input));
632
109k
  if (style.m_lineWidth>0) style.m_lineWidth=float(lineWidth);
633
  // 0: none, 1: pattern, 5: gradient(wb3), 1001: bitmap
634
109k
  int fillType=int(libwps::readU16(input));
635
109k
  shape.m_values2[3]=int(libwps::readU16(input));
636
109k
  bool isTextbox=shape.isTextbox();
637
109k
  if (fillType==0)
638
85.5k
  {
639
85.5k
    WPSGraphicStyle::Pattern pattern;
640
85.5k
    if (patternId==0) // none
641
65.8k
      ;
642
19.6k
    else if (patternId==1)
643
242
    {
644
242
      if (isTextbox)
645
78
        style.setBackgroundColor(surfaceColor[1]);
646
164
      else
647
164
        style.setSurfaceColor(surfaceColor[1]);
648
242
    }
649
19.4k
    else if (patternId==154)
650
158
    {
651
158
      if (isTextbox)
652
23
        style.setBackgroundColor(surfaceColor[0]);
653
135
      else
654
135
        style.setSurfaceColor(surfaceColor[0]);
655
158
    }
656
19.2k
    else if (m_state->getPattern(patternId, pattern))
657
3.08k
    {
658
9.24k
      for (int i=0; i<2; ++i)
659
6.16k
        pattern.m_colors[i]=surfaceColor[i];
660
3.08k
      if (isTextbox)
661
295
      {
662
295
        WPSColor finalColor;
663
295
        if (pattern.getAverageColor(finalColor))
664
295
          style.setBackgroundColor(finalColor);
665
295
      }
666
2.78k
      else
667
2.78k
        style.setPattern(pattern);
668
3.08k
    }
669
16.1k
    else
670
16.1k
      f << "###pat[id]=" << patternId << ",";
671
85.5k
  }
672
24.1k
  else
673
24.1k
  {
674
24.1k
    if (!readFillData(shape.m_style, fillType, stream, endPos))
675
23.9k
      return false;
676
135
    if (fillType>=1 && fillType<=6)
677
5
    {
678
5
      f << "gradient=" << fillType << ",";
679
5
      if (isTextbox)
680
1
        style.setBackgroundColor(WPSColor::barycenter(0.5f, surfaceColor[0], 0.5f, surfaceColor[1]));
681
4
      else
682
4
      {
683
4
        style.m_gradientType=fillType<=4 ? WPSGraphicStyle::G_Linear : WPSGraphicStyle::G_Axial;
684
4
        style.m_gradientStopList.clear();
685
4
        style.m_gradientStopList.push_back(WPSGraphicStyle::GradientStop(0.0, surfaceColor[1]));
686
4
        style.m_gradientStopList.push_back(WPSGraphicStyle::GradientStop(1.0, surfaceColor[0]));
687
4
        int const rot[]= {0, 90, -90, 0, 180, 90, 0};
688
4
        style.m_gradientAngle=float(rot[fillType]);
689
4
      }
690
5
    }
691
130
    else
692
130
    {
693
130
      if (!surfaceColor[0].isBlack()) f << "surf[col0]=" << surfaceColor[0] << ",";
694
130
      if (!surfaceColor[1].isWhite()) f << "surf[col1]=" << surfaceColor[1] << ",";
695
130
      f << "fill[type]=" << fillType << ",";
696
130
      f << "pat[id]=" << patternId << ",";
697
130
      if ((fillType&0xfff)==1)
698
6
      {
699
6
        f << "###bitmap[" << std::hex << fillType << std::dec << "],";
700
6
        f << "crop[type]=" << (fillType>>12) << ",";
701
6
        stream->m_ascii.addDelimiter(input->tell(),'|');
702
6
        shape.m_extra=f.str();
703
6
        WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: find a bitmap, unimplemented!!!\n"));
704
6
        return false;
705
6
      }
706
124
      f << "###fill[type]=" << std::hex << fillType << std::dec << ",";
707
124
      WPS_DEBUG_MSG(("QuattroGraph::readShapeHeader: unexpected fill type %d\n", fillType));
708
124
    }
709
135
  }
710
85.6k
  shape.m_extra=f.str();
711
85.6k
  return true;
712
109k
}
713
714
bool QuattroGraph::readFillData(WPSGraphicStyle &/*style*/, int fillType, std::shared_ptr<WPSStream> stream, long endPos)
715
27.6k
{
716
27.6k
  if (fillType==0) return true;
717
27.6k
  RVNGInputStreamPtr input = stream->m_input;
718
27.6k
  libwps::DebugFile &ascFile=stream->m_ascii;
719
27.6k
  libwps::DebugStream f;
720
27.6k
  long pos = input->tell();
721
27.6k
  if (fillType<0)
722
0
  {
723
0
    WPS_DEBUG_MSG(("QuattroGraph::readFillData: unexpected fillType\n"));
724
0
    return false;
725
0
  }
726
27.6k
  if (pos+4>endPos || libwps::readU16(input)!=0x2e4)
727
27.4k
  {
728
27.4k
    WPS_DEBUG_MSG(("QuattroGraph::readFillData: the zone length seems bad\n"));
729
27.4k
    return false;
730
27.4k
  }
731
189
  f << "Entries(FillData)[" << std::hex << fillType << std::dec << ":";
732
189
  int dSz=int(libwps::readU16(input));
733
189
  if (pos+4+dSz>endPos)
734
44
  {
735
44
    WPS_DEBUG_MSG(("QuattroGraph::readFillData: can not read the data size\n"));
736
44
    return false;
737
44
  }
738
145
  if (dSz)
739
27
  {
740
27
    ascFile.addDelimiter(input->tell(),'|');
741
27
    input->seek(pos+4+dSz, librevenge::RVNG_SEEK_SET);
742
27
  }
743
145
  ascFile.addPos(pos);
744
145
  ascFile.addNote(f.str().c_str());
745
145
  if ((fillType&0xf000)==0 || (fillType&0xfff)!=1)
746
134
    return true;
747
11
  pos=input->tell();
748
11
  if (pos+68>endPos)
749
3
  {
750
3
    WPS_DEBUG_MSG(("QuattroGraph::readFillData: can not read the bitmap name\n"));
751
3
    return false;
752
3
  }
753
8
  f.str("");
754
8
  f << "FillData[bitmap]:";
755
8
  int val=int(libwps::readU16(input));
756
8
  if (val!=10) f << "f0=" << val << ",";
757
8
  val=int(libwps::readU16(input));
758
8
  if (val) f << "crop[type]=" << val << ",";
759
8
  librevenge::RVNGString name;
760
8
  if (!m_mainParser.readCString(stream,name,64))
761
0
    f << "###name,";
762
8
  else
763
8
    f << name.cstr() << ",";
764
8
  input->seek(pos+68, librevenge::RVNG_SEEK_SET);
765
8
  ascFile.addPos(pos);
766
8
  ascFile.addNote(f.str().c_str());
767
768
8
  pos=input->tell();
769
8
  if (pos+10>endPos)
770
2
  {
771
2
    WPS_DEBUG_MSG(("QuattroGraph::readFillData: can not read the bitmap data\n"));
772
2
    return false;
773
2
  }
774
6
  f.str("");
775
6
  f << "FillData[extra]:";
776
6
  val=int(libwps::readU16(input));
777
6
  if (val!=0x4000) f << "f0=" << val << ",";
778
6
  val=int(libwps::readU16(input));
779
6
  if (val!=0x1c93) f << "f1=" << std::hex << val << std::dec << ",";
780
6
  int dim[2];
781
12
  for (auto &d:dim) d=int(libwps::readU16(input));
782
6
  f << "dim=" << Vec2i(dim[0],dim[1]) << ",";
783
6
  ascFile.addPos(pos);
784
6
  ascFile.addNote(f.str().c_str());
785
786
6
  return true;
787
8
}
788
789
bool QuattroGraph::readBeginEnd(std::shared_ptr<WPSStream> stream, int sheetId)
790
29.8k
{
791
29.8k
  RVNGInputStreamPtr input = stream->m_input;
792
29.8k
  libwps::DebugFile &ascFile=stream->m_ascii;
793
29.8k
  libwps::DebugStream f;
794
29.8k
  long pos = input->tell();
795
29.8k
  auto type = int(libwps::readU16(input)&0x7fff);
796
797
29.8k
  if (type != 0x321 && type != 0x322)
798
0
  {
799
0
    WPS_DEBUG_MSG(("QuattroGraph::readBeginEnd: not a begin/end zone\n"));
800
0
    return false;
801
0
  }
802
29.8k
  auto sz = long(libwps::readU16(input));
803
29.8k
  int const expectedSize=(type==0x321 ? 0 : 2);
804
29.8k
  m_state->m_actualGraph.reset();
805
29.8k
  m_state->m_actualSheet=type==0x321 ? sheetId : -1;
806
29.8k
  if (sz!=expectedSize)
807
450
  {
808
450
    WPS_DEBUG_MSG(("QuattroGraph::readBeginEnd: size seems very bad\n"));
809
450
    f << "###";
810
450
    ascFile.addPos(pos);
811
450
    ascFile.addNote(f.str().c_str());
812
450
    return true;
813
450
  }
814
29.4k
  if (type==0x322)   // always 0
815
5.69k
  {
816
5.69k
    auto val=int(libwps::read16(input));
817
5.69k
    if (val) f << "f0=" << val << ",";
818
5.69k
  }
819
29.4k
  ascFile.addPos(pos);
820
29.4k
  ascFile.addNote(f.str().c_str());
821
29.4k
  return true;
822
29.8k
}
823
824
bool QuattroGraph::readFrame(std::shared_ptr<WPSStream> stream)
825
15.9k
{
826
15.9k
  RVNGInputStreamPtr input = stream->m_input;
827
15.9k
  libwps::DebugFile &ascFile=stream->m_ascii;
828
15.9k
  libwps::DebugStream f;
829
15.9k
  long pos = input->tell();
830
15.9k
  auto type = int(libwps::readU16(input)&0x7fff);
831
832
15.9k
  if (type != 0x385)
833
0
  {
834
0
    WPS_DEBUG_MSG(("QuattroGraph::readFrame: not a frame zone\n"));
835
0
    return false;
836
0
  }
837
15.9k
  auto sz = long(libwps::readU16(input));
838
15.9k
  long endPos=pos+4+sz;
839
15.9k
  auto frame=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::Frame);
840
15.9k
  m_state->m_actualGraph.reset();
841
15.9k
  if (sz<57 || !readHeader(*frame,stream,endPos))
842
2.76k
  {
843
2.76k
    if (sz)
844
71
    {
845
71
      WPS_DEBUG_MSG(("QuattroGraph::readFrame: size seems very bad\n"));
846
71
      f << "###";
847
71
    }
848
2.76k
    ascFile.addPos(pos);
849
2.76k
    ascFile.addNote(f.str().c_str());
850
2.76k
    return true;
851
2.76k
  }
852
13.1k
  f << *frame;
853
13.1k
  m_state->storeGraph(frame);
854
13.1k
  auto sSz=int(libwps::readU16(input));
855
13.1k
  librevenge::RVNGString text;
856
13.1k
  if (input->tell()+sSz+6>endPos || !m_mainParser.readCString(stream,text,sSz))
857
8.28k
  {
858
8.28k
    WPS_DEBUG_MSG(("QuattroGraph::readFrame: can not read string1\n"));
859
8.28k
    f << "##sSz,";
860
8.28k
    ascFile.addPos(pos);
861
8.28k
    ascFile.addNote(f.str().c_str());
862
8.28k
    return true;
863
8.28k
  }
864
4.90k
  f << "name=" << text.cstr() << ",";
865
19.6k
  for (int i=0; i<3; ++i)   // g0=1, g2=2001
866
14.7k
  {
867
14.7k
    auto val=int(libwps::readU16(input));
868
14.7k
    if (val)
869
8.00k
      f << "g" << i << "=" << std::hex << val << std::dec << ",";
870
14.7k
  }
871
4.90k
  if (input->tell()!=endPos)
872
4.80k
  {
873
4.80k
    ascFile.addDelimiter(input->tell(),'|');
874
4.80k
    WPS_DEBUG_MSG(("QuattroGraph::readFrame: find extra data\n"));
875
4.80k
    f << "##extra,";
876
4.80k
  }
877
4.90k
  ascFile.addPos(pos);
878
4.90k
  ascFile.addNote(f.str().c_str());
879
4.90k
  return true;
880
13.1k
}
881
882
bool QuattroGraph::readFrameOLE(std::shared_ptr<WPSStream> stream)
883
85.8k
{
884
85.8k
  RVNGInputStreamPtr input = stream->m_input;
885
85.8k
  libwps::DebugFile &ascFile=stream->m_ascii;
886
85.8k
  libwps::DebugStream f;
887
85.8k
  long pos = input->tell();
888
85.8k
  auto type = int(libwps::readU16(input)&0x7fff);
889
890
85.8k
  if (type != 0x381)
891
0
  {
892
0
    WPS_DEBUG_MSG(("QuattroGraph::readFrameOLE: not a frame zone\n"));
893
0
    return false;
894
0
  }
895
85.8k
  auto sz = long(libwps::readU16(input));
896
85.8k
  long endPos=pos+4+sz;
897
85.8k
  auto frame=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::OLE);
898
85.8k
  m_state->m_actualGraph.reset();
899
85.8k
  if (sz<59 || !readHeader(*frame,stream,endPos))
900
43.6k
  {
901
43.6k
    if (sz)
902
41.0k
    {
903
41.0k
      WPS_DEBUG_MSG(("QuattroGraph::readFrameOLE: size seems very bad\n"));
904
41.0k
      f << "###";
905
41.0k
    }
906
43.6k
    ascFile.addPos(pos);
907
43.6k
    ascFile.addNote(f.str().c_str());
908
43.6k
    return true;
909
43.6k
  }
910
42.1k
  f << *frame;
911
42.1k
  m_state->storeGraph(frame);
912
42.1k
  auto sSz=int(libwps::readU16(input));
913
42.1k
  librevenge::RVNGString text;
914
42.1k
  if (input->tell()+sSz+4>endPos || !m_mainParser.readCString(stream,text,sSz))
915
24.3k
  {
916
24.3k
    WPS_DEBUG_MSG(("QuattroGraph::readFrameOLE: can not read string1\n"));
917
24.3k
    f << "##sSz,";
918
24.3k
    ascFile.addPos(pos);
919
24.3k
    ascFile.addNote(f.str().c_str());
920
24.3k
    return true;
921
24.3k
  }
922
17.8k
  frame->m_linkName=text;
923
17.8k
  f << "name=" << text.cstr() << ",";
924
89.2k
  for (int i=0; i<4; ++i)   // g0=11, g2=d00, g4=7500
925
71.3k
  {
926
71.3k
    auto val=int(libwps::readU16(input));
927
71.3k
    if (val)
928
47.8k
      f << "g" << i << "=" << std::hex << val << std::dec << ",";
929
71.3k
  }
930
17.8k
  if (input->tell()!=endPos)
931
13.8k
  {
932
13.8k
    ascFile.addDelimiter(input->tell(),'|');
933
13.8k
    WPS_DEBUG_MSG(("QuattroGraph::readFrameOLE: find extra data\n"));
934
13.8k
    f << "##extra,";
935
13.8k
  }
936
17.8k
  ascFile.addPos(pos);
937
17.8k
  ascFile.addNote(f.str().c_str());
938
17.8k
  return true;
939
42.1k
}
940
941
bool QuattroGraph::readOLEData(std::shared_ptr<WPSStream> stream)
942
12.0k
{
943
12.0k
  RVNGInputStreamPtr input = stream->m_input;
944
12.0k
  libwps::DebugFile &ascFile=stream->m_ascii;
945
12.0k
  libwps::DebugStream f;
946
12.0k
  long pos = input->tell();
947
12.0k
  auto type = int(libwps::readU16(input)&0x7fff);
948
949
12.0k
  if (type != 0x38b)
950
0
  {
951
0
    WPS_DEBUG_MSG(("QuattroGraph::readOLEData: not a OLE zone\n"));
952
0
    return false;
953
0
  }
954
12.0k
  auto sz = long(libwps::readU16(input));
955
12.0k
  long endPos=sz<0xFF00 ? pos+4+sz : stream->m_eof;
956
12.0k
  if (sz<38)
957
2.45k
  {
958
2.45k
    if (sz)
959
24
    {
960
24
      WPS_DEBUG_MSG(("QuattroGraph::readOLEData: size seems very bad\n"));
961
24
      f << "###";
962
24
    }
963
2.45k
    ascFile.addPos(pos);
964
2.45k
    ascFile.addNote(f.str().c_str());
965
2.45k
    return true;
966
2.45k
  }
967
9.62k
  auto frame=m_state->m_actualGraph;
968
9.62k
  if (frame && frame->m_type!=frame->Frame)
969
424
    frame.reset();
970
9.62k
  if (frame)
971
919
    frame->m_type=frame->OLE;
972
8.70k
  else
973
8.70k
  {
974
8.70k
    WPS_DEBUG_MSG(("QuattroGraph::readOLEData: can not find current frame\n"));
975
8.70k
  }
976
57.7k
  for (int i=0; i<5; ++i)
977
48.1k
  {
978
48.1k
    int val=int(libwps::readU16(input));
979
48.1k
    int const expected[]= {0x1a,0x8068,0x2001,0,0};
980
48.1k
    if (val!=expected[i])
981
45.2k
      f << "f" << i << "=" << std::hex << val << std::dec << ",";
982
48.1k
  }
983
9.62k
  long actPos=input->tell();
984
9.62k
  auto sSz=int(libwps::readU16(input));
985
9.62k
  librevenge::RVNGString text;
986
9.62k
  if (actPos+2+sSz+12+1+12>endPos || !m_mainParser.readCString(stream,text,sSz))
987
1.00k
  {
988
1.00k
    WPS_DEBUG_MSG(("QuattroGraph::readOLEData: can not read the name\n"));
989
1.00k
    f << "##sSz,";
990
1.00k
    ascFile.addPos(pos);
991
1.00k
    ascFile.addNote(f.str().c_str());
992
1.00k
    return true;
993
1.00k
  }
994
8.62k
  f << "name=" << text.cstr() << ",";
995
8.62k
  input->seek(actPos+2+sSz, librevenge::RVNG_SEEK_SET);
996
8.62k
  ascFile.addPos(pos);
997
8.62k
  ascFile.addNote(f.str().c_str());
998
999
8.62k
  pos=input->tell();
1000
8.62k
  WPSEmbeddedObject dummyObject;
1001
8.62k
  if (!WPSOLEObject::readOLE(stream, frame ? frame->m_ole : dummyObject,endPos))
1002
1.87k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1003
8.62k
  if (input->tell()!=endPos)
1004
8.55k
  {
1005
8.55k
    WPS_DEBUG_MSG(("QuattroGraph::readOLEData: find extra data\n"));
1006
8.55k
    ascFile.addPos(input->tell());
1007
8.55k
    ascFile.addNote("Object:###extra");
1008
8.55k
  }
1009
8.62k
  return true;
1010
9.62k
}
1011
1012
bool QuattroGraph::readButton(std::shared_ptr<WPSStream> stream)
1013
15.7k
{
1014
15.7k
  RVNGInputStreamPtr input = stream->m_input;
1015
15.7k
  libwps::DebugFile &ascFile=stream->m_ascii;
1016
15.7k
  libwps::DebugStream f;
1017
15.7k
  long pos = input->tell();
1018
15.7k
  auto type = int(libwps::readU16(input)&0x7fff);
1019
1020
15.7k
  if (type != 0x386)
1021
0
  {
1022
0
    WPS_DEBUG_MSG(("QuattroGraph::readButton: not a button zone\n"));
1023
0
    return false;
1024
0
  }
1025
15.7k
  auto sz = long(libwps::readU16(input));
1026
15.7k
  long endPos=pos+4+sz;
1027
15.7k
  m_state->m_actualGraph.reset();
1028
15.7k
  auto button=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::Button);
1029
15.7k
  if (sz<67 || !readHeader(*button,stream,endPos))
1030
11.8k
  {
1031
11.8k
    if (sz)
1032
99
    {
1033
99
      WPS_DEBUG_MSG(("QuattroGraph::readButton: size seems very bad\n"));
1034
99
      f << "###";
1035
99
    }
1036
11.8k
    ascFile.addPos(pos);
1037
11.8k
    ascFile.addNote(f.str().c_str());
1038
11.8k
    return true;
1039
11.8k
  }
1040
3.94k
  f << *button; // fl1=[7f|81,0x8063,0x2000,0];
1041
3.94k
  ascFile.addPos(pos);
1042
3.94k
  ascFile.addNote(f.str().c_str());
1043
1044
3.94k
  pos=input->tell();
1045
3.94k
  f.str("");
1046
3.94k
  f << "Object-A:";
1047
3.94k
  auto sSz=int(libwps::readU16(input));
1048
3.94k
  librevenge::RVNGString text;
1049
3.94k
  if (pos+2+sSz>endPos || !m_mainParser.readCString(stream,text,sSz))
1050
977
  {
1051
977
    WPS_DEBUG_MSG(("QuattroGraph::readButton: can not read string1 bad\n"));
1052
977
    f << "##sSz,";
1053
977
    ascFile.addPos(pos);
1054
977
    ascFile.addNote(f.str().c_str());
1055
977
    return true;
1056
977
  }
1057
2.97k
  input->seek(pos+2+sSz, librevenge::RVNG_SEEK_SET);
1058
2.97k
  f << "name=" << text.cstr() << ",";
1059
17.8k
  for (int i=0; i<5; ++i)
1060
14.8k
  {
1061
14.8k
    auto val=int(libwps::readU16(input));
1062
14.8k
    if (val) f << "f" << i << "=" << val << ",";
1063
14.8k
  }
1064
2.97k
  auto val=int(libwps::readU8(input));
1065
2.97k
  if (val) f << "f5=" << val << ",";
1066
2.97k
  ascFile.addPos(pos);
1067
2.97k
  ascFile.addNote(f.str().c_str());
1068
2.97k
  pos=input->tell();
1069
2.97k
  f.str("");
1070
2.97k
  f << "Object-B:";
1071
2.97k
  auto dType=int(libwps::readU8(input));
1072
2.97k
  if (dType==1) f << "complex,";
1073
2.91k
  else if (dType)
1074
376
  {
1075
376
    WPS_DEBUG_MSG(("QuattroGraph::readButton: find unknown type\n"));
1076
376
    f << "##dType=" << dType << ",";
1077
376
  }
1078
7.41k
  for (int st=0; st<2; ++st)
1079
5.29k
  {
1080
5.29k
    sSz=int(libwps::readU16(input));
1081
5.29k
    if (pos+2+sSz>endPos || !m_mainParser.readCString(stream,text,sSz))
1082
854
    {
1083
854
      WPS_DEBUG_MSG(("QuattroGraph::readButton: can not read string2 bad\n"));
1084
854
      f << "##sSz,";
1085
854
      ascFile.addPos(pos);
1086
854
      ascFile.addNote(f.str().c_str());
1087
854
      return true;
1088
854
    }
1089
4.44k
    if (text.empty()) continue;
1090
1.04k
    f << (st==0 ? "macros" : "label") << "=" << text.cstr() << ",";
1091
1.04k
    if (st==1)
1092
1.02k
      button->m_label=text;
1093
1.04k
  }
1094
2.11k
  if (dType==0)
1095
1.89k
  {
1096
1.89k
    if (input->tell()!=endPos)
1097
1.35k
    {
1098
1.35k
      WPS_DEBUG_MSG(("QuattroGraph::readButton: find extra data\n"));
1099
1.35k
      f << "##extra,";
1100
1.35k
      ascFile.addDelimiter(input->tell(),'|');
1101
1.35k
    }
1102
1.89k
    m_state->storeGraph(button);
1103
1.89k
  }
1104
2.11k
  ascFile.addPos(pos);
1105
2.11k
  ascFile.addNote(f.str().c_str());
1106
1107
2.11k
  if (dType && input->tell()!=endPos)
1108
148
  {
1109
148
    ascFile.addPos(input->tell());
1110
148
    ascFile.addNote("Object-C:");
1111
148
  }
1112
2.11k
  return true;
1113
2.97k
}
1114
1115
bool QuattroGraph::readImage(std::shared_ptr<WPSStream> stream)
1116
4.70k
{
1117
4.70k
  RVNGInputStreamPtr input = stream->m_input;
1118
4.70k
  libwps::DebugFile &ascFile=stream->m_ascii;
1119
4.70k
  libwps::DebugStream f;
1120
4.70k
  long pos = input->tell();
1121
4.70k
  auto type = int(libwps::readU16(input)&0x7fff);
1122
1123
4.70k
  if (type != 0x382)
1124
0
  {
1125
0
    WPS_DEBUG_MSG(("QuattroGraph::readImage: unknown id\n"));
1126
0
    return false;
1127
0
  }
1128
4.70k
  auto sz = long(libwps::readU16(input));
1129
4.70k
  long endPos=pos+4+sz;
1130
4.70k
  auto zone382=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::Image);
1131
4.70k
  m_state->m_actualGraph.reset();
1132
4.70k
  if (sz<53 || !readHeader(*zone382,stream,endPos))
1133
4.32k
  {
1134
4.32k
    if (sz)
1135
2.50k
    {
1136
2.50k
      WPS_DEBUG_MSG(("QuattroGraph::readImage: size seems very bad\n"));
1137
2.50k
      f << "###";
1138
2.50k
    }
1139
4.32k
    ascFile.addPos(pos);
1140
4.32k
    ascFile.addNote(f.str().c_str());
1141
4.32k
    return true;
1142
4.32k
  }
1143
374
  f << *zone382;
1144
374
  auto sSz=int(libwps::readU16(input));
1145
374
  librevenge::RVNGString text;
1146
374
  if (input->tell()+sSz+2>endPos || !m_mainParser.readCString(stream,text,sSz))
1147
152
  {
1148
152
    WPS_DEBUG_MSG(("QuattroGraph::readImage: can not read string1\n"));
1149
152
    f << "##sSz,";
1150
152
    ascFile.addPos(pos);
1151
152
    ascFile.addNote(f.str().c_str());
1152
152
    return true;
1153
152
  }
1154
222
  f << text.cstr() << ","; // find Bitmap5, followed by
1155
  // 20000000070001000080000000ffffff0000000100000000070064e96729a1e87328af2b0700628597334100
1156
  // c767040064e96729b7e87328af2b04008bce67354800
1157
  // c7670500673575ce0400
1158
  // 2d002d00: a picture dimension ?
1159
  // eb010000: the gif's size
1160
  // the gif
1161
222
  if (input->tell()!=endPos)
1162
222
  {
1163
222
    ascFile.addDelimiter(input->tell(),'|');
1164
222
  }
1165
222
  static bool first=true;
1166
222
  if (first)
1167
4
  {
1168
4
    first=false;
1169
4
    WPS_DEBUG_MSG(("QuattroGraph::readImage: this file contains a zone 382, there will not be recovered\n"));
1170
4
  }
1171
222
  ascFile.addPos(pos);
1172
222
  ascFile.addNote(f.str().c_str());
1173
222
  return true;
1174
374
}
1175
1176
bool QuattroGraph::readBitmap(std::shared_ptr<WPSStream> stream)
1177
8.45k
{
1178
8.45k
  RVNGInputStreamPtr input = stream->m_input;
1179
8.45k
  libwps::DebugFile &ascFile=stream->m_ascii;
1180
8.45k
  libwps::DebugStream f;
1181
8.45k
  long pos = input->tell();
1182
8.45k
  auto type = int(libwps::readU16(input)&0x7fff);
1183
1184
8.45k
  if (type != 0x383)
1185
0
  {
1186
0
    WPS_DEBUG_MSG(("QuattroGraph::readBitmap: unknown id\n"));
1187
0
    return false;
1188
0
  }
1189
8.45k
  auto sz = long(libwps::readU16(input));
1190
8.45k
  long endPos=pos+4+sz;
1191
8.45k
  auto bitmap=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::OLE);
1192
8.45k
  m_state->m_actualGraph.reset();
1193
8.45k
  if (sz<67 || !readHeader(*bitmap,stream,endPos))
1194
3.63k
  {
1195
3.63k
    if (sz)
1196
87
    {
1197
87
      WPS_DEBUG_MSG(("QuattroGraph::readBitmap: size seems very bad\n"));
1198
87
      f << "###";
1199
87
    }
1200
3.63k
    ascFile.addPos(pos);
1201
3.63k
    ascFile.addNote(f.str().c_str());
1202
3.63k
    return true;
1203
3.63k
  }
1204
4.82k
  f << *bitmap;
1205
4.82k
  auto sSz=int(libwps::readU16(input));
1206
4.82k
  librevenge::RVNGString text;
1207
4.82k
  if (input->tell()+sSz+16>endPos || !m_mainParser.readCString(stream,text,sSz))
1208
1.04k
  {
1209
1.04k
    WPS_DEBUG_MSG(("QuattroGraph::readBitmap: can not read string1\n"));
1210
1.04k
    f << "##sSz,";
1211
1.04k
    ascFile.addPos(pos);
1212
1.04k
    ascFile.addNote(f.str().c_str());
1213
1.04k
    return true;
1214
1.04k
  }
1215
3.78k
  f << text.cstr() << ",";
1216
3.78k
  f << "unkn=[";
1217
34.0k
  for (int i=0; i<8; ++i)
1218
30.2k
  {
1219
30.2k
    auto val=int(libwps::readU16(input));
1220
30.2k
    if (val)
1221
13.6k
      f << std::hex << val << std::dec << ",";
1222
16.6k
    else
1223
16.6k
      f << "_,";
1224
30.2k
  }
1225
3.78k
  f << "],";
1226
3.78k
  ascFile.addPos(pos);
1227
3.78k
  ascFile.addNote(f.str().c_str());
1228
1229
3.78k
  WPSEmbeddedObject object;
1230
3.78k
  pos=input->tell();
1231
3.78k
  if (!WPSOLEObject::readWMF(stream, bitmap->m_ole, endPos))
1232
3.33k
  {
1233
3.33k
    WPS_DEBUG_MSG(("QuattroGraph::readBitmap: can not find the wmf file\n"));
1234
3.33k
    ascFile.addPos(pos);
1235
3.33k
    ascFile.addNote("Object:###");
1236
3.33k
  }
1237
443
  else
1238
443
    m_state->storeGraph(bitmap);
1239
1240
3.78k
  return true;
1241
4.82k
}
1242
1243
bool QuattroGraph::readChart(std::shared_ptr<WPSStream> stream)
1244
23.0k
{
1245
23.0k
  RVNGInputStreamPtr input = stream->m_input;
1246
23.0k
  libwps::DebugFile &ascFile=stream->m_ascii;
1247
23.0k
  libwps::DebugStream f;
1248
23.0k
  long pos = input->tell();
1249
23.0k
  auto type = int(libwps::readU16(input)&0x7fff);
1250
1251
23.0k
  if (type != 0x384)
1252
0
  {
1253
0
    WPS_DEBUG_MSG(("QuattroGraph::readChart: unknown id\n"));
1254
0
    return false;
1255
0
  }
1256
23.0k
  auto sz = long(libwps::readU16(input));
1257
23.0k
  long endPos=pos+4+sz;
1258
23.0k
  auto chart=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::Chart);
1259
23.0k
  m_state->m_actualGraph.reset();
1260
23.0k
  if (sz<57 || !readHeader(*chart,stream,endPos))
1261
17.0k
  {
1262
17.0k
    if (sz)
1263
24
    {
1264
24
      WPS_DEBUG_MSG(("QuattroGraph::readChart: size seems very bad\n"));
1265
24
      f << "###";
1266
24
    }
1267
17.0k
    ascFile.addPos(pos);
1268
17.0k
    ascFile.addNote(f.str().c_str());
1269
17.0k
    return true;
1270
17.0k
  }
1271
5.99k
  f << *chart;
1272
5.99k
  auto sSz=int(libwps::readU16(input));
1273
5.99k
  librevenge::RVNGString text;
1274
5.99k
  if (input->tell()+sSz+6>endPos || !m_mainParser.readCString(stream,text,sSz))
1275
3.21k
  {
1276
3.21k
    WPS_DEBUG_MSG(("QuattroGraph::readChart: can not read string1\n"));
1277
3.21k
    f << "##sSz,";
1278
3.21k
    ascFile.addPos(pos);
1279
3.21k
    ascFile.addNote(f.str().c_str());
1280
3.21k
    return true;
1281
3.21k
  }
1282
2.77k
  f << text.cstr() << ","; // find Inserted1-21
1283
8.32k
  for (int i=0; i<2; ++i)   // f0=1|30
1284
5.55k
  {
1285
5.55k
    auto val=int(libwps::read16(input));
1286
5.55k
    if (val) f << "f" << i << "=" << val << ",";
1287
5.55k
  }
1288
2.77k
  sSz=int(libwps::readU16(input));
1289
2.77k
  if (input->tell()+sSz>endPos || !m_mainParser.readCString(stream,text,sSz))
1290
1.42k
  {
1291
1.42k
    WPS_DEBUG_MSG(("QuattroGraph::readChart: can not read string1\n"));
1292
1.42k
    f << "##sSz2,";
1293
1.42k
    ascFile.addPos(pos);
1294
1.42k
    ascFile.addNote(f.str().c_str());
1295
1.42k
    return true;
1296
1.42k
  }
1297
1.34k
  f << "name=" << text.cstr() << ",";
1298
1.34k
  if (input->tell()!=endPos)
1299
1.30k
  {
1300
1.30k
    WPS_DEBUG_MSG(("QuattroGraph::readChart: find extra data\n"));
1301
1.30k
    f << "##extra,";
1302
1.30k
    ascFile.addDelimiter(input->tell(),'|');
1303
1.30k
  }
1304
1.34k
  static bool first=true;
1305
1.34k
  if (first)
1306
5
  {
1307
5
    first=false;
1308
5
    WPS_DEBUG_MSG(("QuattroGraph::readChart: this file contains some charts, there will not be recovered\n"));
1309
5
  }
1310
1.34k
  ascFile.addPos(pos);
1311
1.34k
  ascFile.addNote(f.str().c_str());
1312
1.34k
  return true;
1313
2.77k
}
1314
1315
////////////////////////////////////////////////////////////
1316
// shape, line, ...
1317
////////////////////////////////////////////////////////////
1318
bool QuattroGraph::readShape(std::shared_ptr<WPSStream> stream)
1319
31.0k
{
1320
31.0k
  RVNGInputStreamPtr input = stream->m_input;
1321
31.0k
  libwps::DebugFile &ascFile=stream->m_ascii;
1322
31.0k
  libwps::DebugStream f;
1323
31.0k
  long pos = input->tell();
1324
31.0k
  auto type = int(libwps::readU16(input)&0x7fff);
1325
1326
31.0k
  if (type != 0x4d3)
1327
0
  {
1328
0
    WPS_DEBUG_MSG(("QuattroGraph::readShape: not a shape zone\n"));
1329
0
    return false;
1330
0
  }
1331
31.0k
  auto sz = long(libwps::readU16(input));
1332
31.0k
  long endPos=pos+4+sz;
1333
31.0k
  auto shape=std::make_shared<QuattroGraphInternal::Graph>(stream,QuattroGraphInternal::Graph::Shape);
1334
31.0k
  m_state->m_actualGraph.reset();
1335
31.0k
  if (sz<59 || !readHeader(*shape,stream,endPos))
1336
318
  {
1337
318
    if (sz)
1338
258
    {
1339
258
      WPS_DEBUG_MSG(("QuattroGraph::readShape: size seems very bad\n"));
1340
258
      f << "###";
1341
258
    }
1342
318
    ascFile.addPos(pos);
1343
318
    ascFile.addNote(f.str().c_str());
1344
318
    return true;
1345
318
  }
1346
30.7k
  f << *shape;
1347
30.7k
  auto sSz=int(libwps::readU16(input));
1348
30.7k
  librevenge::RVNGString text;
1349
30.7k
  if (input->tell()+sSz+8>endPos || !m_mainParser.readCString(stream,text,sSz))
1350
12.8k
  {
1351
12.8k
    WPS_DEBUG_MSG(("QuattroGraph::readShape: can not read string1\n"));
1352
12.8k
    f << "##sSz,";
1353
12.8k
    ascFile.addPos(pos);
1354
12.8k
    ascFile.addNote(f.str().c_str());
1355
12.8k
    return true;
1356
12.8k
  }
1357
17.9k
  shape->m_linkName=text;
1358
17.9k
  f << "name=" << text.cstr() << ",";
1359
89.5k
  for (int i=0; i<4; ++i)   // f2=1b(oval) 37(line),41(rect), 56(rect oval), 58(arrow)
1360
71.6k
  {
1361
71.6k
    int val=int(libwps::read16(input));
1362
71.6k
    int const expected[]= {0x20,0,0,0x2001};
1363
71.6k
    if (val!=expected[i])
1364
54.5k
      f << "f" << i << "=" << val << ",";
1365
71.6k
  }
1366
17.9k
  m_state->storeGraph(shape);
1367
17.9k
  if (input->tell()!=endPos)
1368
17.3k
  {
1369
17.3k
    ascFile.addDelimiter(input->tell(),'|');
1370
17.3k
    f << "##extra,";
1371
17.3k
    WPS_DEBUG_MSG(("QuattroGraph::readShape: find extra data\n"));
1372
17.3k
  }
1373
17.9k
  ascFile.addPos(pos);
1374
17.9k
  ascFile.addNote(f.str().c_str());
1375
17.9k
  return true;
1376
30.7k
}
1377
1378
bool QuattroGraph::readLine(std::shared_ptr<WPSStream> stream)
1379
167k
{
1380
167k
  RVNGInputStreamPtr input = stream->m_input;
1381
167k
  libwps::DebugFile &ascFile=stream->m_ascii;
1382
167k
  libwps::DebugStream f;
1383
167k
  long pos = input->tell();
1384
167k
  auto type = int(libwps::readU16(input)&0x7fff);
1385
167k
  if (type!=0x35a && type!=0x37b)
1386
0
  {
1387
0
    WPS_DEBUG_MSG(("QuattroGraph::readLine: not a line zone\n"));
1388
0
    return false;
1389
0
  }
1390
167k
  auto parent=m_state->m_actualGraph;
1391
167k
  m_state->m_actualGraph.reset();
1392
167k
  auto sz = long(libwps::readU16(input));
1393
167k
  long endPos=pos+4+sz;
1394
167k
  auto shape=std::make_shared<QuattroGraphInternal::Shape>();
1395
167k
  if (sz<58 || !readShapeHeader(*shape, stream, endPos-1) || input->tell()+1>endPos)
1396
102k
  {
1397
102k
    if (sz)
1398
101k
    {
1399
101k
      WPS_DEBUG_MSG(("QuattroGraph::readLine: the size seems very bad\n"));
1400
101k
      f << shape << ",";
1401
101k
      f << "###";
1402
101k
    }
1403
102k
    ascFile.addPos(pos);
1404
102k
    ascFile.addNote(f.str().c_str());
1405
102k
    return true;
1406
102k
  }
1407
65.4k
  f << *shape << ",";
1408
65.4k
  ascFile.addPos(pos);
1409
65.4k
  ascFile.addNote(f.str().c_str());
1410
1411
65.4k
  pos=input->tell();
1412
65.4k
  f.str("");
1413
65.4k
  f << "GrLine:";
1414
65.4k
  int val=int(libwps::readU8(input));
1415
65.4k
  f << "type=" << val << ",";
1416
65.4k
  if (input->tell()!=endPos)
1417
1.72k
  {
1418
1.72k
    ascFile.addDelimiter(input->tell(),'|');
1419
1.72k
    f << "##extra,";
1420
1.72k
    WPS_DEBUG_MSG(("QuattroGraph::readLine: find extra data\n"));
1421
1.72k
  }
1422
65.4k
  shape->m_style.m_arrows[1]=type==0x37b;
1423
65.4k
  switch (val&3)
1424
65.4k
  {
1425
87
  case 1:
1426
87
    shape->m_shape=WPSGraphicShape::line(Vec2f(float(shape->m_box[1][0]),float(shape->m_box[0][1])),
1427
87
                                         Vec2f(float(shape->m_box[0][0]),float(shape->m_box[1][1])));
1428
87
    break;
1429
6.10k
  case 2:
1430
6.10k
    shape->m_shape=WPSGraphicShape::line(Vec2f(shape->m_box[1]),Vec2f(shape->m_box[0]));
1431
6.10k
    break;
1432
10.0k
  case 3:
1433
10.0k
    shape->m_shape=WPSGraphicShape::line(Vec2f(float(shape->m_box[0][0]),float(shape->m_box[1][1])),
1434
10.0k
                                         Vec2f(float(shape->m_box[1][0]),float(shape->m_box[0][1])));
1435
10.0k
    break;
1436
49.2k
  case 0:
1437
49.2k
  default:
1438
49.2k
    shape->m_shape=WPSGraphicShape::line(Vec2f(shape->m_box[0]),Vec2f(shape->m_box[1]));
1439
49.2k
    break;
1440
65.4k
  }
1441
65.4k
  if (parent && parent->m_type==parent->Shape)
1442
296
    parent->m_shape=shape;
1443
1444
65.4k
  ascFile.addPos(pos);
1445
65.4k
  ascFile.addNote(f.str().c_str());
1446
65.4k
  return true;
1447
65.4k
}
1448
1449
bool QuattroGraph::readRect(std::shared_ptr<WPSStream> stream)
1450
7.42k
{
1451
7.42k
  RVNGInputStreamPtr input = stream->m_input;
1452
7.42k
  libwps::DebugFile &ascFile=stream->m_ascii;
1453
7.42k
  libwps::DebugStream f;
1454
7.42k
  long pos = input->tell();
1455
7.42k
  auto type = int(libwps::readU16(input)&0x7fff);
1456
1457
7.42k
  auto parent=m_state->m_actualGraph;
1458
7.42k
  m_state->m_actualGraph.reset();
1459
7.42k
  if (type!=0x33e && type!=0x364 && type!=0x379)
1460
0
  {
1461
0
    WPS_DEBUG_MSG(("QuattroGraph::readRect: not a rect zone\n"));
1462
0
    return false;
1463
0
  }
1464
7.42k
  auto sz = long(libwps::readU16(input));
1465
7.42k
  long endPos=pos+4+sz;
1466
7.42k
  auto shape=std::make_shared<QuattroGraphInternal::Shape>();
1467
7.42k
  if (sz<57 || !readShapeHeader(*shape, stream, endPos))
1468
4.16k
  {
1469
4.16k
    if (sz)
1470
3.11k
    {
1471
3.11k
      WPS_DEBUG_MSG(("QuattroGraph::readRect: the size seems very bad\n"));
1472
3.11k
      f << *shape << ",";
1473
3.11k
      f << "###";
1474
3.11k
    }
1475
4.16k
    ascFile.addPos(pos);
1476
4.16k
    ascFile.addNote(f.str().c_str());
1477
4.16k
    return true;
1478
4.16k
  }
1479
3.25k
  f << *shape << ",";
1480
3.25k
  switch (type)
1481
3.25k
  {
1482
2.56k
  case 0x33e:
1483
2.56k
    shape->m_shape=WPSGraphicShape::circle(WPSBox2f(shape->m_box));
1484
2.56k
    break;
1485
599
  case 0x364:
1486
599
    shape->m_shape=WPSGraphicShape::rectangle(WPSBox2f(shape->m_box));
1487
599
    break;
1488
0
  default:
1489
95
  case 0x379:
1490
95
    shape->m_shape=WPSGraphicShape::rectangle(WPSBox2f(shape->m_box), Vec2f(20,20));
1491
95
    break;
1492
3.25k
  }
1493
3.25k
  if (parent && parent->m_type==parent->Shape)
1494
111
    parent->m_shape=shape;
1495
3.25k
  if (input->tell()!=endPos)
1496
3.25k
  {
1497
3.25k
    ascFile.addDelimiter(input->tell(),'|');
1498
3.25k
    f << "##extra,";
1499
3.25k
    WPS_DEBUG_MSG(("QuattroGraph::readRect: find extra data\n"));
1500
3.25k
  }
1501
3.25k
  ascFile.addPos(pos);
1502
3.25k
  ascFile.addNote(f.str().c_str());
1503
3.25k
  return true;
1504
3.25k
}
1505
1506
bool QuattroGraph::readPolygon(std::shared_ptr<WPSStream> stream)
1507
11.7k
{
1508
11.7k
  RVNGInputStreamPtr input = stream->m_input;
1509
11.7k
  libwps::DebugFile &ascFile=stream->m_ascii;
1510
11.7k
  libwps::DebugStream f;
1511
11.7k
  long pos = input->tell();
1512
11.7k
  auto type = int(libwps::readU16(input)&0x7fff);
1513
11.7k
  if (type!=0x35b && type!=0x35c && type!=0x37c && type!=0x388)
1514
0
  {
1515
0
    WPS_DEBUG_MSG(("QuattroGraph::readPolygon: not a polygon zone\n"));
1516
0
    return false;
1517
0
  }
1518
11.7k
  auto parent=m_state->m_actualGraph;
1519
11.7k
  m_state->m_actualGraph.reset();
1520
11.7k
  auto sz = long(libwps::readU16(input));
1521
11.7k
  long endPos=pos+4+sz;
1522
11.7k
  auto shape=std::make_shared<QuattroGraphInternal::Shape>();
1523
11.7k
  if (sz<57 || !readShapeHeader(*shape, stream, endPos-6) || input->tell()+6>endPos)
1524
7.84k
  {
1525
7.84k
    if (sz)
1526
2.68k
    {
1527
2.68k
      WPS_DEBUG_MSG(("QuattroGraph::readPolygon: the size seems very bad\n"));
1528
2.68k
      f << *shape << ",";
1529
2.68k
      f << "###";
1530
2.68k
    }
1531
7.84k
    ascFile.addPos(pos);
1532
7.84k
    ascFile.addNote(f.str().c_str());
1533
7.84k
    return true;
1534
7.84k
  }
1535
3.91k
  f << *shape << ",";
1536
3.91k
  ascFile.addPos(pos);
1537
3.91k
  ascFile.addNote(f.str().c_str());
1538
1539
3.91k
  pos=input->tell();
1540
3.91k
  f.str("");
1541
3.91k
  f << "GrPolygon:";
1542
3.91k
  int N=int(libwps::readU16(input));
1543
3.91k
  if ((endPos-pos-2)/4!=N+1)
1544
1.87k
  {
1545
1.87k
    WPS_DEBUG_MSG(("QuattroGraph::readPolygon: the number of points seems very bad\n"));
1546
1.87k
    f << "###N=" << N << ",";
1547
1.87k
    ascFile.addPos(pos);
1548
1.87k
    ascFile.addNote(f.str().c_str());
1549
1.87k
    return true;
1550
1.87k
  }
1551
2.04k
  if (type==0x35c || type==0x37c) // FIXME
1552
2.04k
    shape->m_shape=WPSGraphicShape::polyline(WPSBox2f(shape->m_box));
1553
8
  else
1554
8
    shape->m_shape=WPSGraphicShape::polygon(WPSBox2f(shape->m_box));
1555
2.04k
  f << "pts=[";
1556
10.2k
  for (int i=0; i<=N; ++i)
1557
8.24k
  {
1558
8.24k
    int pt[2];
1559
16.4k
    for (auto &p : pt) p=int(libwps::read16(input));
1560
8.24k
    shape->m_shape.m_vertices.push_back(Vec2f(float(pt[0]),float(pt[1])));
1561
8.24k
    f << shape->m_shape.m_vertices.back() << ",";
1562
8.24k
  }
1563
2.04k
  f << "],";
1564
2.04k
  if (parent && parent->m_type==parent->Shape)
1565
5
    parent->m_shape=shape;
1566
2.04k
  ascFile.addPos(pos);
1567
2.04k
  ascFile.addNote(f.str().c_str());
1568
2.04k
  return true;
1569
3.91k
}
1570
1571
bool QuattroGraph::readTextBox(std::shared_ptr<WPSStream> stream)
1572
18.1k
{
1573
18.1k
  RVNGInputStreamPtr input = stream->m_input;
1574
18.1k
  libwps::DebugFile &ascFile=stream->m_ascii;
1575
18.1k
  libwps::DebugStream f;
1576
18.1k
  long pos = input->tell();
1577
18.1k
  auto type = int(libwps::readU16(input)&0x7fff);
1578
1579
18.1k
  if (type!=0x36f)
1580
0
  {
1581
0
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: not a text box zone\n"));
1582
0
    return false;
1583
0
  }
1584
18.1k
  auto parent=m_state->m_actualGraph;
1585
18.1k
  m_state->m_actualGraph.reset();
1586
18.1k
  auto sz = long(libwps::readU16(input));
1587
18.1k
  long endPos=pos+4+sz;
1588
18.1k
  auto textbox=std::make_shared<QuattroGraphInternal::Textbox>();
1589
18.1k
  if (sz<57 || !readShapeHeader(*textbox, stream, endPos-3) || input->tell()+3>endPos)
1590
5.29k
  {
1591
5.29k
    if (sz)
1592
4.91k
    {
1593
4.91k
      WPS_DEBUG_MSG(("QuattroGraph::readTextBox: the size seems very bad\n"));
1594
4.91k
      f << *textbox << ",";
1595
4.91k
      f << "###";
1596
4.91k
    }
1597
5.29k
    ascFile.addPos(pos);
1598
5.29k
    ascFile.addNote(f.str().c_str());
1599
5.29k
    return true;
1600
5.29k
  }
1601
12.8k
  f << *textbox << ",";
1602
12.8k
  ascFile.addPos(pos);
1603
12.8k
  ascFile.addNote(f.str().c_str());
1604
1605
12.8k
  pos=input->tell();
1606
12.8k
  f.str("");
1607
12.8k
  f << "GrTextBox[text]:";
1608
12.8k
  int val=int(libwps::readU8(input));
1609
12.8k
  if (val) f << "f0=" << std::hex << val << std::dec << ",";
1610
12.8k
  int N=int(libwps::readU16(input));
1611
12.8k
  if (pos+3+N+10>endPos)
1612
1.07k
  {
1613
1.07k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: can not read the text zone\n"));
1614
1.07k
    f << "###";
1615
1.07k
    ascFile.addPos(pos);
1616
1.07k
    ascFile.addNote(f.str().c_str());
1617
1.07k
    return true;
1618
1.07k
  }
1619
11.7k
  textbox->m_entry.setBegin(pos+3);
1620
11.7k
  textbox->m_entry.setLength(N);
1621
11.7k
  std::string text;
1622
76.5k
  for (int i=0; i<N; ++i) text+=char(libwps::readU8(input));
1623
11.7k
  f << text;
1624
11.7k
  ascFile.addPos(pos);
1625
11.7k
  ascFile.addNote(f.str().c_str());
1626
1627
11.7k
  pos=input->tell();
1628
11.7k
  f.str("");
1629
11.7k
  f << "GrTextBox[format]:";
1630
11.7k
  if (pos+80>endPos)
1631
1.09k
  {
1632
1.09k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: can not read the format zone\n"));
1633
1.09k
    f << "###";
1634
1.09k
    ascFile.addPos(pos);
1635
1.09k
    ascFile.addNote(f.str().c_str());
1636
1.09k
    return true;
1637
1.09k
  }
1638
10.6k
  auto &font = textbox->m_font;;
1639
10.6k
  font.m_size=double(libwps::readU16(input));
1640
10.6k
  int flags=int(libwps::readU16(input));
1641
10.6k
  uint32_t attributes = 0;
1642
10.6k
  if (flags & 1) attributes |= WPS_BOLD_BIT;
1643
10.6k
  if (flags & 2) attributes |= WPS_ITALICS_BIT;
1644
10.6k
  if (flags & 4) attributes |= WPS_UNDERLINE_BIT;
1645
10.6k
  if (flags & 0x20) attributes |= WPS_STRIKEOUT_BIT;
1646
10.6k
  font.m_attributes=attributes;
1647
10.6k
  flags&=0xffd8;
1648
10.6k
  if (flags)
1649
3.78k
    f << "#font[flag]=" << std::hex << flags << std::dec << ",";
1650
10.6k
  librevenge::RVNGString name;
1651
10.6k
  if (!m_mainParser.readCString(stream, name, 32))
1652
0
    f << "###name,";
1653
10.6k
  else
1654
10.6k
    font.m_name=name;
1655
10.6k
  input->seek(pos+35, librevenge::RVNG_SEEK_SET);
1656
10.6k
  val=int(libwps::readU8(input)); // 0|5|8|58|ff
1657
10.6k
  if (val) f << "f0=" << std::hex << val << std::dec << ",";
1658
10.6k
  unsigned char col[4];
1659
10.6k
  WPSColor colors[2];
1660
10.6k
  for (auto &color : colors)
1661
21.3k
  {
1662
85.3k
    for (auto &c : col) c=libwps::readU8(input);
1663
21.3k
    color=WPSColor(col[0],col[1],col[2]);
1664
21.3k
  }
1665
10.6k
  int fillType=int(libwps::readU16(input));
1666
10.6k
  if (fillType==0)
1667
5.91k
  {
1668
5.91k
    font.m_color=colors[0];
1669
5.91k
  }
1670
4.75k
  else if (fillType>=1 && fillType<=6)
1671
1.39k
    font.m_color=WPSColor::barycenter(0.5f, colors[0], 0.5f, colors[1]);
1672
3.36k
  else if ((fillType&0x8060)==0x8060)
1673
306
  {
1674
306
    font.m_color=colors[0];
1675
306
    f << "#3d[effect]=" << (fillType&0x7f9f) << ",";
1676
306
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: find unimplemented 3d color\n"));
1677
306
  }
1678
3.05k
  else
1679
3.05k
  {
1680
3.05k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: find unimplemented fillType color\n"));
1681
3.05k
    f << "###fill[type]=" << std::hex << fillType << std::dec << ",";
1682
3.05k
  }
1683
10.6k
  f << font;
1684
10.6k
  val=int(libwps::read16(input));
1685
10.6k
  if (val) f << "f1=" << val << ",";
1686
10.6k
  val=int(libwps::read16(input));
1687
10.6k
  if (val) f << "box[width]=" << val << ","; // maybe type
1688
10.6k
  val=int(libwps::read16(input));
1689
10.6k
  switch (val)
1690
10.6k
  {
1691
6.60k
  case 0: // left
1692
6.60k
    break;
1693
840
  case 1:
1694
840
    textbox->m_paragraph.m_justify=libwps::JustificationCenter;
1695
840
    f << "center,";
1696
840
    break;
1697
38
  case 2:
1698
38
    textbox->m_paragraph.m_justify=libwps::JustificationRight;
1699
38
    f << "right,";
1700
38
    break;
1701
3.18k
  default:
1702
3.18k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: unknown alignment\n"));
1703
3.18k
    f << "###align=" << val << ",";
1704
3.18k
    break;
1705
10.6k
  }
1706
53.3k
  for (int i=0; i<4; ++i) // f3=1, f2=small number, f3=-1,f4=-1
1707
42.6k
  {
1708
42.6k
    val=int(libwps::read16(input));
1709
42.6k
    if (!val) continue;
1710
22.8k
    f << "f" << i+2 << "=" << val << ",";
1711
22.8k
  }
1712
10.6k
  val=int(libwps::read16(input));
1713
10.6k
  if (val!=300) f << "tab[width]=" << float(val)/10.f << ","; // unsure about the unit 300=1inch, 390=1,3125 inch
1714
10.6k
  val=int(libwps::read16(input));
1715
10.6k
  if (val) f << "g1=" << val << ",";
1716
10.6k
  int sSz=int(libwps::readU16(input));
1717
10.6k
  if (input->tell()+sSz+14>endPos)
1718
2.54k
  {
1719
2.54k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: can not read the last string\n"));
1720
2.54k
    f << "###";
1721
2.54k
    ascFile.addPos(pos);
1722
2.54k
    ascFile.addNote(f.str().c_str());
1723
2.54k
    return true;
1724
2.54k
  }
1725
8.12k
  text="";
1726
36.5k
  for (int i=0; i<sSz; ++i) text+=char(libwps::readU8(input));
1727
8.12k
  if (!text.empty()) f << text << ",";
1728
64.9k
  for (int i=0; i<7; ++i)   // h0=0|2|1d,h3=0|2, h5=0|16a, h6=0|922c
1729
56.8k
  {
1730
56.8k
    val=int(libwps::read16(input));
1731
56.8k
    if (val) f << "h" << i << "=" << val << ",";
1732
56.8k
  }
1733
8.12k
  long actPos=input->tell();
1734
8.12k
  if (fillType && !readFillData(textbox->m_style, fillType, stream, endPos))
1735
3.49k
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
1736
8.12k
  if (input->tell()!=endPos)
1737
8.06k
  {
1738
8.06k
    ascFile.addDelimiter(input->tell(),'|');
1739
8.06k
    f << "##extra,";
1740
8.06k
    WPS_DEBUG_MSG(("QuattroGraph::readTextBox: find extra data\n"));
1741
8.06k
  }
1742
8.12k
  if (parent && parent->m_type==parent->Shape)
1743
470
  {
1744
470
    parent->m_type=parent->Textbox;
1745
470
    parent->m_textbox=textbox;
1746
470
  }
1747
8.12k
  ascFile.addPos(pos);
1748
8.12k
  ascFile.addNote(f.str().c_str());
1749
8.12k
  return true;
1750
10.6k
}
1751
////////////////////////////////////////////////////////////
1752
// dialog
1753
////////////////////////////////////////////////////////////
1754
bool QuattroGraph::readHeader(QuattroGraphInternal::Dialog &header, std::shared_ptr<WPSStream> stream, long endPos)
1755
4.68k
{
1756
4.68k
  auto input=stream->m_input;
1757
4.68k
  long pos = input->tell();
1758
4.68k
  if (endPos-pos<22)
1759
0
  {
1760
0
    WPS_DEBUG_MSG(("QuattroGraph::readHeader: the zone is too short\n"));
1761
0
    return false;
1762
0
  }
1763
23.4k
  for (auto &fl : header.m_flags1) fl=int(libwps::readU16(input));
1764
4.68k
  int dim[4];
1765
18.7k
  for (auto &d: dim) d=libwps::readU16(input);
1766
4.68k
  header.m_cellBox=WPSBox2i(Vec2i(dim[0],dim[1]),Vec2i(dim[2],dim[3]));
1767
42.1k
  for (auto &fl : header.m_flags2) fl=int(libwps::readU8(input));
1768
4.68k
  return true;
1769
4.68k
}
1770
1771
bool QuattroGraph::readDialog(std::shared_ptr<WPSStream> stream)
1772
4.27k
{
1773
4.27k
  RVNGInputStreamPtr input = stream->m_input;
1774
4.27k
  libwps::DebugFile &ascFile=stream->m_ascii;
1775
4.27k
  libwps::DebugStream f;
1776
4.27k
  long pos = input->tell();
1777
4.27k
  auto type = int(libwps::readU16(input)&0x7fff);
1778
1779
4.27k
  if (type != 0x35e)
1780
0
  {
1781
0
    WPS_DEBUG_MSG(("QuattroGraph::readDialog: unknown id\n"));
1782
0
    return false;
1783
0
  }
1784
4.27k
  auto sz = long(libwps::readU16(input));
1785
4.27k
  long endPos=pos+4+sz;
1786
4.27k
  QuattroGraphInternal::Dialog dialog;
1787
4.27k
  if (sz<65 || !readHeader(dialog,stream,endPos))
1788
265
  {
1789
265
    if (sz)
1790
134
    {
1791
134
      WPS_DEBUG_MSG(("QuattroGraph::readDialog: size seems very bad\n"));
1792
134
      f << "###";
1793
134
    }
1794
265
    ascFile.addPos(pos);
1795
265
    ascFile.addNote(f.str().c_str());
1796
265
    return true;
1797
265
  }
1798
4.00k
  f << dialog << ",";
1799
4.00k
  int val;
1800
16.0k
  for (int i=0; i<3; ++i)   // f1=0|-256, f2=-1
1801
12.0k
  {
1802
12.0k
    val=int(libwps::read16(input));
1803
12.0k
    if (val)
1804
7.08k
      f << "f" << i << "=" << val <<",";
1805
12.0k
  }
1806
16.0k
  for (int i=0; i<3; ++i)   // 0
1807
12.0k
  {
1808
12.0k
    val=int(libwps::read16(input));
1809
12.0k
    if (val)
1810
5.25k
      f << "f" << i+4 << "=" << val <<",";
1811
12.0k
  }
1812
4.00k
  val=int(libwps::readU16(input));
1813
4.00k
  if (val!=0x100)
1814
3.59k
    f << "f7=" << std::hex << val << std::dec << ",";
1815
4.00k
  auto sSz=int(libwps::readU16(input));
1816
4.00k
  librevenge::RVNGString text;
1817
4.00k
  if (input->tell()+sSz+7+15>endPos || !m_mainParser.readCString(stream,text,sSz))
1818
1.19k
  {
1819
1.19k
    WPS_DEBUG_MSG(("QuattroGraph::readDialog: can not read string1\n"));
1820
1.19k
    f << "##sSz,";
1821
1.19k
    ascFile.addPos(pos);
1822
1.19k
    ascFile.addNote(f.str().c_str());
1823
1.19k
    return true;
1824
1.19k
  }
1825
2.80k
  f << text.cstr() << ","; // find Dialog1...
1826
2.80k
  val=int(libwps::readU8(input));
1827
2.80k
  if (val!=0x1)
1828
1.93k
    f << "f9=" << val << ",";
1829
2.80k
  sSz=int(libwps::readU16(input));
1830
2.80k
  if (sSz<4 || input->tell()+sSz+15>endPos || (sz>4 && !m_mainParser.readCString(stream,text,sSz-4)))
1831
2.28k
  {
1832
2.28k
    WPS_DEBUG_MSG(("QuattroGraph::readDialog: can not read string1\n"));
1833
2.28k
    f << "##sSz2,";
1834
2.28k
    ascFile.addPos(pos);
1835
2.28k
    ascFile.addNote(f.str().c_str());
1836
2.28k
    return true;
1837
2.28k
  }
1838
525
  if (!text.empty()) // find Enter ...
1839
52
    f << text.cstr() << ",";
1840
1.57k
  for (int i=0; i<2; ++i)   // 0
1841
1.05k
  {
1842
1.05k
    val=int(libwps::read16(input));
1843
1.05k
    if (!val) continue;
1844
495
    f << "g" << i << "=" << val << ",";
1845
495
  }
1846
525
  if (input->tell()!=endPos) // then some flags
1847
525
    ascFile.addDelimiter(input->tell(),'|');
1848
525
  static bool first=true;
1849
525
  if (first)
1850
4
  {
1851
4
    first=false;
1852
4
    WPS_DEBUG_MSG(("QuattroGraph::readDialog: this file contains some dialogs, there will not be recovered\n"));
1853
4
  }
1854
525
  ascFile.addPos(pos);
1855
525
  ascFile.addNote(f.str().c_str());
1856
525
  return true;
1857
2.80k
}
1858
1859
bool QuattroGraph::readDialogUnknown(std::shared_ptr<WPSStream> stream)
1860
8.45k
{
1861
8.45k
  RVNGInputStreamPtr input = stream->m_input;
1862
8.45k
  libwps::DebugFile &ascFile=stream->m_ascii;
1863
8.45k
  libwps::DebugStream f;
1864
8.45k
  long pos = input->tell();
1865
8.45k
  auto type = int(libwps::readU16(input)&0x7fff);
1866
1867
8.45k
  if (type<0x330 || type>0x380)
1868
0
  {
1869
0
    WPS_DEBUG_MSG(("QuattroGraph::readDialogUnknown: unknown id\n"));
1870
0
    return false;
1871
0
  }
1872
8.45k
  auto sz = long(libwps::readU16(input));
1873
8.45k
  long endPos=pos+4+sz;
1874
8.45k
  QuattroGraphInternal::Dialog dialog;
1875
8.45k
  if (sz<38 || !readHeader(dialog,stream,endPos))
1876
7.78k
  {
1877
7.78k
    if (sz)
1878
1.08k
    {
1879
1.08k
      WPS_DEBUG_MSG(("QuattroGraph::readDialogUnknown: size seems very bad\n"));
1880
1.08k
      f << "###";
1881
1.08k
    }
1882
7.78k
    ascFile.addPos(pos);
1883
7.78k
    ascFile.addNote(f.str().c_str());
1884
7.78k
    return true;
1885
7.78k
  }
1886
673
  if (dialog.m_flags2[8]&0x80)
1887
261
  {
1888
261
    f << "select,";
1889
261
    dialog.m_flags2[8]&=0x7f;
1890
261
  }
1891
673
  f << dialog << ",";
1892
673
  auto fl=int(libwps::readU8(input)); // [0128][08ac]
1893
673
  if (fl&1) f << "has[frame],";
1894
673
  fl &= 0xfe;
1895
673
  if (fl) f << "flag=" << std::hex << fl << std::dec << ",";
1896
673
  auto id=int(libwps::readU16(input));
1897
673
  f << "id=" << id << ",";
1898
673
  unsigned char col[3];
1899
2.01k
  for (auto &c : col) c=libwps::readU8(input);
1900
673
  f << "col=" << WPSColor(col[0],col[1],col[2]) << ",";
1901
673
  f << "fl3=[";
1902
4.03k
  for (int i=0; i<5; ++i)   // 0
1903
3.36k
  {
1904
3.36k
    auto val=int(libwps::readU8(input));
1905
3.36k
    if (val)
1906
2.10k
      f << std::hex << val << std::dec << ",";
1907
1.26k
    else
1908
1.26k
      f << "_,";
1909
3.36k
  }
1910
673
  f << "],";
1911
673
  if (input->tell()!=endPos) // then some flags
1912
505
    ascFile.addDelimiter(input->tell(),'|');
1913
673
  ascFile.addPos(pos);
1914
673
  ascFile.addNote(f.str().c_str());
1915
673
  return true;
1916
8.45k
}
1917
1918
////////////////////////////////////////////////////////////
1919
// send data
1920
////////////////////////////////////////////////////////////
1921
bool QuattroGraph::sendGraphics(int sheetId, Vec2i const &cell) const
1922
7.07k
{
1923
7.07k
  if (!m_listener)
1924
0
  {
1925
0
    WPS_DEBUG_MSG(("QuattroGraph::sendGraphics: can not find the listener\n"));
1926
0
    return false;
1927
0
  }
1928
7.07k
  auto it=m_state->m_sheetIdToGraphMap.find(sheetId);
1929
7.07k
  bool find=false;
1930
404k
  while (it!=m_state->m_sheetIdToGraphMap.end() && it->first==sheetId)
1931
397k
  {
1932
397k
    auto const &graph=it++->second;
1933
397k
    if (!graph || graph->m_cellBox[0]!=cell) continue;
1934
28.5k
    sendGraphic(*graph);
1935
28.5k
    find=true;
1936
28.5k
  }
1937
7.07k
  if (!find)
1938
0
  {
1939
0
    WPS_DEBUG_MSG(("QuattroGraph::sendGraphics: sorry, can not find any graph\n"));
1940
0
  }
1941
7.07k
  return find;
1942
7.07k
}
1943
1944
bool QuattroGraph::sendPageGraphics(int sheetId) const
1945
641k
{
1946
693k
  for (auto it=m_state->m_sheetIdToGraphMap.lower_bound(sheetId); it!=m_state->m_sheetIdToGraphMap.upper_bound(sheetId); ++it)
1947
51.7k
  {
1948
51.7k
    auto const &graph=it->second;
1949
51.7k
    if (!graph) continue;
1950
51.7k
    if (graph->m_type==graph->Shape)
1951
11.3k
      sendShape(*graph, sheetId);
1952
51.7k
    if (graph->m_type==graph->Textbox)
1953
415
      sendTextbox(*graph, sheetId);
1954
51.7k
  }
1955
641k
  return true;
1956
641k
}
1957
1958
bool QuattroGraph::sendGraphic(QuattroGraphInternal::Graph const &graph) const
1959
28.5k
{
1960
28.5k
  if (!m_listener)
1961
0
  {
1962
0
    WPS_DEBUG_MSG(("QuattroGraph::sendGraphic: can not find the listener\n"));
1963
0
    return false;
1964
0
  }
1965
28.5k
  WPSPosition pos(graph.m_cellBoxDecal[0], graph.m_size, librevenge::RVNG_POINT);
1966
28.5k
  pos.m_anchorTo = WPSPosition::Cell;
1967
28.5k
  pos.m_anchorCellName = libwps::getCellName(graph.m_cellBox[1]+Vec2i(1,1)).c_str();
1968
28.5k
  if (graph.m_type==graph.OLE)
1969
21.8k
  {
1970
21.8k
    if (!graph.m_linkName.empty())
1971
1.93k
    {
1972
1.93k
      auto it=m_state->m_linkNameToObjectMap.find(graph.m_linkName);
1973
1.93k
      if (it==m_state->m_linkNameToObjectMap.end() || it->second.isEmpty())
1974
1.84k
      {
1975
1.84k
        WPS_DEBUG_MSG(("QuattroGraph::sendGraphic: can not find ole %s\n", graph.m_linkName.cstr()));
1976
1.84k
      }
1977
87
      else
1978
87
        m_listener->insertObject(pos, it->second);
1979
1.93k
    }
1980
19.8k
    else if (graph.m_ole.isEmpty())
1981
19.7k
    {
1982
19.7k
      WPS_DEBUG_MSG(("QuattroGraph::sendGraphic: find an empty ole\n"));
1983
19.7k
    }
1984
85
    else
1985
85
      m_listener->insertObject(pos, graph.m_ole);
1986
21.8k
    return true;
1987
21.8k
  }
1988
6.75k
  if (graph.m_type==graph.Button)
1989
959
  {
1990
959
    if (graph.m_label.empty())
1991
82
    {
1992
82
      WPS_DEBUG_MSG(("QuattroGraph::sendGraphic: find an empty label\n"));
1993
82
    }
1994
877
    else
1995
877
    {
1996
877
      WPSGraphicStyle style;
1997
877
      style.setBackgroundColor(WPSColor(128,128,128));
1998
877
      auto doc=std::make_shared<QuattroGraphInternal::SubDocument>(const_cast<QuattroGraph &>(*this),graph.m_label);
1999
877
      m_listener->insertTextBox(pos, doc, style);
2000
877
    }
2001
959
    return true;
2002
959
  }
2003
5.79k
  static bool first=true;
2004
5.79k
  if (first)
2005
5
  {
2006
5
    first=false;
2007
5
    WPS_DEBUG_MSG(("QuattroGraph::sendGraphic: sorry, unexpected graph type\n"));
2008
5
  }
2009
5.79k
  return true;
2010
6.75k
}
2011
2012
bool QuattroGraph::sendShape(QuattroGraphInternal::Graph const &graph, int sheetId) const
2013
11.3k
{
2014
11.3k
  if (!m_listener)
2015
0
  {
2016
0
    WPS_DEBUG_MSG(("QuattroGraph::sendShape: can not find the listener\n"));
2017
0
    return false;
2018
0
  }
2019
11.3k
  if (graph.m_type!=graph.Shape || !graph.m_shape)
2020
11.0k
  {
2021
11.0k
    WPS_DEBUG_MSG(("QuattroGraph::sendShape: can not find the shape\n"));
2022
11.0k
    return false;
2023
11.0k
  }
2024
287
  auto const &shape=*graph.m_shape;
2025
287
  WPSPosition pos(graph.m_cellBoxDecal[0]+m_mainParser.getCellPosition(sheetId, graph.m_cellBox[0]), graph.m_size, librevenge::RVNG_POINT);
2026
287
  pos.m_anchorTo = WPSPosition::Page;
2027
287
  auto gShape=shape.m_shape;
2028
287
  auto bdBoxSize=gShape.getBdBox().size();
2029
287
  gShape.scale(Vec2f(bdBoxSize[0]>0 ? float(graph.m_size[0])/bdBoxSize[0] : 1.f, bdBoxSize[1]>0 ? float(graph.m_size[1])/bdBoxSize[1] : 1.f));
2030
287
  m_listener->insertPicture(pos, gShape, shape.m_style);
2031
287
  return true;
2032
11.3k
}
2033
2034
bool QuattroGraph::sendTextbox(QuattroGraphInternal::Graph const &graph, int sheetId) const
2035
415
{
2036
415
  if (!m_listener)
2037
0
  {
2038
0
    WPS_DEBUG_MSG(("QuattroGraph::sendTextbox: can not find the listener\n"));
2039
0
    return false;
2040
0
  }
2041
415
  if (graph.m_type!=graph.Textbox || !graph.m_textbox)
2042
0
  {
2043
0
    WPS_DEBUG_MSG(("QuattroGraph::sendTextbox: can not find the textbox\n"));
2044
0
    return false;
2045
0
  }
2046
415
  auto const &textbox=*graph.m_textbox;
2047
415
  WPSPosition pos(graph.m_cellBoxDecal[0]+m_mainParser.getCellPosition(sheetId, graph.m_cellBox[0]), graph.m_size, librevenge::RVNG_POINT);
2048
415
  pos.m_anchorTo = WPSPosition::Page;
2049
415
  auto doc=std::make_shared<QuattroGraphInternal::SubDocument>(const_cast<QuattroGraph &>(*this),graph.m_textbox, graph.m_stream);
2050
415
  m_listener->insertTextBox(pos, doc, textbox.m_style);
2051
415
  return true;
2052
415
}
2053
2054
bool QuattroGraph::send(QuattroGraphInternal::Textbox const &textbox, std::shared_ptr<WPSStream> stream) const
2055
415
{
2056
415
  if (!m_listener)
2057
0
  {
2058
0
    WPS_DEBUG_MSG(("QuattroGraph::send: can not find the listener\n"));
2059
0
    return false;
2060
0
  }
2061
415
  if (!stream || !textbox.m_entry.valid())
2062
51
  {
2063
51
    WPS_DEBUG_MSG(("QuattroGraph::send: can not find the file stream\n"));
2064
51
    return false;
2065
51
  }
2066
364
  m_listener->setFont(textbox.m_font);
2067
364
  m_listener->setParagraph(textbox.m_paragraph);
2068
364
  auto input=stream->m_input;
2069
364
  input->seek(textbox.m_entry.begin(), librevenge::RVNG_SEEK_SET);
2070
364
  auto fontType = m_mainParser.getDefaultFontType();
2071
364
  std::string text;
2072
16.2k
  for (long l=0; l<=textbox.m_entry.length(); ++l)
2073
16.2k
  {
2074
16.2k
    auto c=l==textbox.m_entry.length() ? '\0' : char(libwps::readU8(input));
2075
16.2k
    if ((c==0 || c==0x9 || c==0xd) && !text.empty())
2076
1.92k
    {
2077
1.92k
      m_listener->insertUnicodeString(libwps_tools_win::Font::unicodeString(text, fontType));
2078
1.92k
      text.clear();
2079
1.92k
    }
2080
16.2k
    if (l==textbox.m_entry.length()) break;
2081
15.9k
    if (c==0xd)
2082
171
      m_listener->insertEOL();
2083
15.7k
    else if (c==0x9)
2084
972
      m_listener->insertTab();
2085
14.7k
    else if (c)
2086
8.53k
      text.push_back(c);
2087
15.9k
  }
2088
364
  return true;
2089
415
}
2090
2091
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */