Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/Canvas5Graph.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 <array>
35
#include <cmath>
36
#include <iomanip>
37
#include <iostream>
38
#include <limits>
39
#include <map>
40
#include <set>
41
#include <sstream>
42
#include <stack>
43
44
#include <librevenge/librevenge.h>
45
46
#include "MWAWFont.hxx"
47
#include "MWAWFontConverter.hxx"
48
#include "MWAWGraphicListener.hxx"
49
#include "MWAWGraphicShape.hxx"
50
#include "MWAWGraphicStyle.hxx"
51
#include "MWAWListener.hxx"
52
#include "MWAWParagraph.hxx"
53
#include "MWAWParser.hxx"
54
#include "MWAWPictBitmap.hxx"
55
#include "MWAWPictMac.hxx"
56
#include "MWAWPosition.hxx"
57
#include "MWAWSubDocument.hxx"
58
59
#include "Canvas5Parser.hxx"
60
61
#include "Canvas5Graph.hxx"
62
#include "Canvas5Image.hxx"
63
#include "Canvas5Structure.hxx"
64
#include "Canvas5StyleManager.hxx"
65
66
#include "libmwaw_internal.hxx"
67
68
/** Internal: the structures of a Canvas5Graph */
69
namespace Canvas5GraphInternal
70
{
71
//! Internal: the section data
72
struct SectionData {
73
  //! constructor
74
  SectionData()
75
0
    : m_numColumns(1)
76
0
    , m_bdBox()
77
0
  {
78
0
  }
79
  //! the number of columns
80
  int m_numColumns;
81
  //! the bounding box
82
  MWAWBox2f m_bdBox;
83
};
84
85
//! Internal: the shape data
86
struct ShapeData {
87
  //! constructor
88
  ShapeData()
89
0
    : m_inMainZone(true)
90
0
    , m_type(0)
91
0
    , m_stream()
92
0
    , m_streamReverted(false)
93
0
    , m_entry()
94
0
    , m_vertices()
95
0
    , m_children()
96
0
    , m_macoId()
97
98
0
    , m_grid(1,1)
99
0
    , m_ngonType(4)
100
101
0
    , m_gdeType(0)
102
0
    , m_sections()
103
0
  {
104
0
    for (auto &l : m_local) l=0;
105
0
    for (auto &i : m_ids) i=0;
106
0
    for (auto &s : m_shapeIds) s=0;
107
0
    for (auto &s : m_specials) s=0;
108
0
    for (auto &e : m_cweb) e=MWAWEntry();
109
0
    for (auto &d : m_doubleValues) d=0;
110
0
  }
111
  //! returns the data stream
112
  Canvas5Structure::Stream &getStream() const
113
0
  {
114
0
    if (!m_stream || !m_stream->input()) {
115
0
      MWAW_DEBUG_MSG(("Canvas5GraphInternal::ShapeData::getStream: no input stream\n"));
116
0
      throw libmwaw::ParseException();
117
0
    }
118
0
    m_stream->input()->setReadInverted(m_streamReverted);
119
0
    return *m_stream;
120
0
  }
121
  //! operator<<
122
  friend std::ostream &operator<<(std::ostream &o, ShapeData const &s)
123
0
  {
124
0
    for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_local)); ++i) {
125
0
      if (s.m_local[i]) o << "l" << i << "=" << s.m_local[i] << ",";
126
0
    }
127
0
    for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_ids)); ++i) {
128
0
      if (!s.m_ids[i]) continue;
129
0
      char const *wh[]= {"TL", "Mat", "Str"};
130
0
      o << wh[i] << s.m_ids[i] << ",";
131
0
    }
132
0
    for (int i=0; i< int(MWAW_N_ELEMENTS(s.m_shapeIds)); ++i) {
133
0
      if (!s.m_shapeIds[i]) continue;
134
0
      char const *wh[]= {"child", "parent", "shape1", "shape2"};
135
0
      o << wh[i] << "=S" << s.m_shapeIds[i] << ",";
136
0
    }
137
0
    return o;
138
0
  }
139
  //! a flag to know if the shape is in the main zone or in Vkfl
140
  bool m_inMainZone;
141
  //! the shape type
142
  unsigned m_type;
143
  //! the data stream
144
  std::shared_ptr<Canvas5Structure::Stream> m_stream;
145
  //! a flag to know the stream endian
146
  bool m_streamReverted;
147
  //! the shape data entry
148
  MWAWEntry m_entry;
149
  //! the local variable
150
  int m_local[2];
151
  //! the text link, matrix, name id
152
  unsigned m_ids[3];
153
  //! the shape ids
154
  unsigned m_shapeIds[4];
155
156
  //! the shape vertices: line, ...
157
  std::vector<MWAWVec2f> m_vertices;
158
  //! the childs: group
159
  std::vector<unsigned> m_children;
160
  //! the macro Id: MACO
161
  std::vector<unsigned> m_macoId;
162
163
  // special
164
165
  //! the grid subdivision
166
  MWAWVec2i m_grid;
167
  //! some special values
168
  int m_specials[4];
169
  //! the buttons image entries
170
  MWAWEntry m_cweb[3];
171
  //! the n-polygon type: NGON
172
  int m_ngonType;
173
  //! the #Gde type
174
  int m_gdeType;
175
  //! the sections: #Gde
176
  std::vector<SectionData> m_sections;
177
  //! the arc angles or rect oval size: v9
178
  double m_doubleValues[4];
179
};
180
181
//! Internal: the shape of a Canvas5Graph
182
struct Shape {
183
  //! constructor
184
  Shape()
185
0
    : m_type(-1)
186
0
    , m_id(0)
187
0
    , m_initialBox()
188
0
    , m_bdbox()
189
    , m_pos()
190
0
    , m_sent(false)
191
0
  {
192
0
    for (auto &f : m_flags) f=0;
193
0
    for (auto &v : m_values) v=0;
194
0
  }
195
196
  //! returns the type name
197
  std::string getTypeName() const
198
0
  {
199
0
    static std::map<int, std::string> const s_typeName= {
200
0
      {2,"text"},
201
0
      {3,"line"},
202
0
      {4,"rect"},
203
0
      {5,"rectOval"},
204
0
      {6,"oval"},
205
0
      {7,"arc"},
206
0
      {9,"polyline"},
207
0
      {10,"spline"},
208
0
      {52,"special"},
209
0
      {99,"group"},
210
0
      {100,"none"}
211
0
    };
212
0
    auto const &it=s_typeName.find(m_type);
213
0
    if (it!=s_typeName.end())
214
0
      return it->second;
215
0
    std::stringstream s;
216
0
    s << "Type" << m_type << "A";
217
0
    return s.str();
218
0
  }
219
220
  //! operator<<
221
  friend std::ostream &operator<<(std::ostream &o, Shape const &s)
222
0
  {
223
0
    o << s.getTypeName() << ",";
224
0
    o << s.m_bdbox << ",";
225
0
    if (s.m_bdbox!=s.m_initialBox)
226
0
      o << "bdbox[orig]=" << s.m_initialBox << ",";
227
0
    if (s.m_type!=100 && s.m_pos>=0)
228
0
      o << "data=" << std::hex << s.m_pos << std::dec << ",";
229
0
    if (s.m_flags[0]) {
230
0
      if (s.m_flags[0]&1) o << "locked,";
231
0
      if (s.m_flags[0]&4) o << "noPrint,";
232
0
      if (s.m_flags[0]&0x200) o << "spread[trap],";
233
0
      if (s.m_flags[0]&0x400) o << "overPrint,";
234
0
      if (s.m_flags[0]&0x800) o << "trap[choke],";
235
0
      int val=(s.m_flags[0]&0xf1fa);
236
0
      if (val)
237
0
        o << "fl=" << std::hex << val << std::dec << ",";
238
0
    }
239
0
    if (s.m_flags[1]) {
240
0
      if (s.m_flags[1]&1) o << "parent,";
241
0
      if (s.m_flags[1]&2) o << "shape1,";
242
0
      if (s.m_flags[1]&4) o << "shape2,";
243
0
      if (s.m_flags[1]&8) o << "rot,";
244
0
      int val=(s.m_flags[1]&0xfff9);
245
0
      if (val)
246
0
        o << "fl1=" << std::hex << val << std::dec << ",";
247
0
    }
248
0
    if (s.m_flags[2]) {
249
0
      if ((s.m_flags[2]&0x1)==0) o << "no[size],";
250
0
      if (s.m_flags[2]&0x4) o << "txtPlc[id],";
251
0
      if (s.m_flags[2]&0x10) o << "mat,";
252
0
      if (s.m_flags[2]&0x20) o << "type,";
253
0
      if (s.m_flags[2]&0x80) o << "shape[id],";
254
0
      if (s.m_flags[2]&0x200) o << "loc1,";
255
0
      if (s.m_flags[2]&0x400) o << "loc2,";
256
0
      if (s.m_flags[2]&0x800) o << "name,";
257
0
      int val=(s.m_flags[2]&0xf1ca);
258
0
      if (val)
259
0
        o << "fl2=" << std::hex << val << std::dec << ",";
260
0
    }
261
0
    for (int i=0; i<int(MWAW_N_ELEMENTS(s.m_values)); ++i) {
262
0
      int val=s.m_values[i];
263
0
      if (val==0) continue;
264
0
      char const *wh[]= {nullptr, "col[surf]=Co", "col[line]=Co", "stroke=St"};
265
0
      if (wh[i])
266
0
        o << wh[i] << val << ",";
267
0
      else
268
0
        o << "f" << i << "=" << val << ",";
269
0
    }
270
0
    return o;
271
0
  }
272
  //! the shape type
273
  int m_type;
274
  //! the shape id
275
  int m_id;
276
  //! the original box
277
  MWAWBox2f m_initialBox;
278
  //! the bounding box
279
  MWAWBox2f m_bdbox;
280
  //! the beginning position
281
  long m_pos;
282
  //! some unknown value
283
  int m_values[4];
284
  //! some unknown flag
285
  int m_flags[3];
286
  //! a flag to know if the shape is already send
287
  mutable bool m_sent;
288
};
289
290
//! Internal[low level]: a pseudo class to store the data corresponding to a shape
291
struct PseudoShape {
292
  //! constructor
293
  PseudoShape()
294
0
    : m_shape()
295
0
    , m_data()
296
0
  {
297
0
  }
298
299
  //! the shape
300
  Shape m_shape;
301
  //! the data shape
302
  ShapeData m_data;
303
};
304
305
////////////////////////////////////////
306
//! Internal: the state of a Canvas5Graph
307
struct State {
308
  //! constructor
309
  State()
310
6.32k
    : m_dataStream()
311
6.32k
    , m_dataStreamReverted(false)
312
313
6.32k
    , m_shapeZones()
314
6.32k
    , m_idToShapeMap()
315
6.32k
    , m_posToShapeDataMap()
316
6.32k
    , m_idToMatrices()
317
318
6.32k
    , m_sendIdSet()
319
6.32k
    , m_sendAGIFIdSet()
320
6.32k
    , m_sendMACOIdSet()
321
6.32k
  {
322
6.32k
  }
323
324
  //! the data shape stream
325
  std::shared_ptr<Canvas5Structure::Stream> m_dataStream;
326
  //! a flag to retrieved the data shape entry
327
  bool m_dataStreamReverted;
328
329
  //! the shape data zones
330
  std::vector<MWAWEntry> m_shapeZones;
331
  //! the map id to shape
332
  std::map<int, Shape> m_idToShapeMap;
333
  //! the map id to shape data
334
  std::map<long, ShapeData> m_posToShapeDataMap;
335
  //! the map id to matrices
336
  std::map<int, std::array<std::array<double, 9>, 2> > m_idToMatrices;
337
338
  //! the list of current send shape id (used to avoid loop)
339
  std::set<int> m_sendIdSet;
340
  //! the list of current send GIF id (used to avoid loop)
341
  std::set<int> m_sendAGIFIdSet;
342
  //! the list of current send macro id (used to avoid loop)
343
  std::set<std::vector<unsigned> > m_sendMACOIdSet;
344
};
345
346
////////////////////////////////////////
347
//! Internal: the subdocument of a Canvas5Graph
348
class SubDocument final : public MWAWSubDocument
349
{
350
public:
351
  //! constructor from a zoneId
352
  SubDocument(Canvas5Graph &parser, MWAWInputStreamPtr const &input, Shape const &shape, ShapeData const &data)
353
0
    : MWAWSubDocument(parser.m_mainParser, input, MWAWEntry())
354
0
    , m_graphParser(parser)
355
0
    , m_shape(&shape)
356
0
    , m_data(&data)
357
0
    , m_measure()
358
0
    , m_font()
359
0
  {
360
0
  }
361
  //! constructor from string
362
  SubDocument(Canvas5Graph &parser, MWAWInputStreamPtr const &input, librevenge::RVNGString const &measure, MWAWFont const &font)
363
0
    : MWAWSubDocument(parser.m_mainParser, input, MWAWEntry())
364
0
    , m_graphParser(parser)
365
0
    , m_shape(nullptr)
366
0
    , m_data(nullptr)
367
0
    , m_measure(measure)
368
0
    , m_font(font)
369
0
  {
370
0
  }
371
372
  //! destructor
373
0
  ~SubDocument() final {}
374
375
  //! operator!=
376
  bool operator!=(MWAWSubDocument const &doc) const final
377
0
  {
378
0
    if (MWAWSubDocument::operator!=(doc)) return true;
379
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
380
0
    if (!sDoc) return true;
381
0
    if (&m_graphParser != &sDoc->m_graphParser) return true;
382
0
    if (m_shape != sDoc->m_shape) return true;
383
0
    if (m_data != sDoc->m_data) return true;
384
0
    if (m_measure != sDoc->m_measure) return true;
385
0
    return false;
386
0
  }
387
388
  //! the parser function
389
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
390
391
protected:
392
  //! the graph parser
393
  Canvas5Graph &m_graphParser;
394
  //! the shape
395
  Shape const *m_shape;
396
  //! the shape data
397
  ShapeData const *m_data;
398
  //! the measure
399
  librevenge::RVNGString m_measure;
400
  //! the font
401
  MWAWFont m_font;
402
private:
403
  SubDocument(SubDocument const &orig) = delete;
404
  SubDocument &operator=(SubDocument const &orig) = delete;
405
};
406
407
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
408
0
{
409
0
  if (!listener || !listener->canWriteText()) {
410
0
    MWAW_DEBUG_MSG(("Canvas5GraphInternal::SubDocument::parse: no listener\n"));
411
0
    return;
412
0
  }
413
0
  if (!m_shape || !m_data) {
414
0
    if (m_measure.empty()) {
415
0
      MWAW_DEBUG_MSG(("Canvas5GraphInternal::SubDocument::parse: can not find the measure\n"));
416
0
      return;
417
0
    }
418
0
    listener->setFont(m_font);
419
0
    MWAWParagraph para;
420
0
    para.m_justify = MWAWParagraph::JustificationCenter;
421
0
    listener->setParagraph(para);
422
0
    listener->insertUnicodeString(m_measure);
423
0
    return;
424
0
  }
425
0
  long pos = m_input ? m_input->tell() : 0;
426
0
  m_graphParser.sendText(listener, *m_shape, *m_data);
427
0
  if (m_input) m_input->seek(pos, librevenge::RVNG_SEEK_SET);
428
0
}
429
430
}
431
432
////////////////////////////////////////////////////////////
433
// constructor/destructor, ...
434
////////////////////////////////////////////////////////////
435
Canvas5Graph::Canvas5Graph(Canvas5Parser &parser)
436
6.32k
  : m_parserState(parser.getParserState())
437
6.32k
  , m_state(new Canvas5GraphInternal::State)
438
6.32k
  , m_mainParser(&parser)
439
6.32k
  , m_imageParser(parser.m_imageParser)
440
6.32k
  , m_styleManager(parser.m_styleManager)
441
6.32k
{
442
6.32k
}
443
444
Canvas5Graph::~Canvas5Graph()
445
6.32k
{
446
6.32k
}
447
448
int Canvas5Graph::version() const
449
0
{
450
0
  return m_parserState->m_version;
451
0
}
452
453
////////////////////////////////////////////////////////////
454
//
455
// Intermediate level
456
//
457
////////////////////////////////////////////////////////////
458
459
bool Canvas5Graph::readMatrices(std::shared_ptr<Canvas5Structure::Stream> stream)
460
0
{
461
0
  if (!stream) {
462
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: no stream\n"));
463
0
    return false;
464
0
  }
465
0
  auto input=stream->input();
466
0
  long pos=input->tell();
467
0
  if (!input->checkPosition(pos+4)) {
468
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: the zone is too short\n"));
469
0
    return false;
470
0
  }
471
0
  libmwaw::DebugFile &ascFile = stream->ascii();
472
0
  pos=input->tell();
473
0
  libmwaw::DebugStream f;
474
0
  f << "Entries(Matrix):";
475
0
  if (version()>=9) {
476
0
    ascFile.addPos(pos);
477
0
    ascFile.addNote(f.str().c_str());
478
0
    return m_mainParser->readArray9(stream, "Matrix",
479
0
    [this](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) {
480
0
      auto lInput=lStream->input();
481
0
      libmwaw::DebugFile &asciiFile = lStream->ascii();
482
0
      libmwaw::DebugStream lF;
483
0
      lF << "Mat" << item.m_id << ",";
484
0
      if (item.m_length!=144) {
485
0
        MWAW_DEBUG_MSG(("Canvas5Graph::readMatrices: a matrix is too short\n"));
486
0
        lF << "###";
487
0
        asciiFile.addPos(item.m_pos);
488
0
        asciiFile.addNote(lF.str().c_str());
489
0
      }
490
0
      lInput->seek(-4, librevenge::RVNG_SEEK_CUR);
491
0
      std::array<std::array<double, 9>, 2> matrices;
492
0
      for (size_t st=0; st<2; ++st) {
493
0
        lF << "mat" << st << "=[";
494
0
        auto &matrix = matrices[st];
495
0
        for (auto &d : matrix) {
496
0
          d=m_mainParser->readDouble(*lStream, 8);
497
0
          lF << d << ",";
498
0
        }
499
0
        lF << "],";
500
0
      }
501
0
      m_state->m_idToMatrices[item.m_id]=matrices;
502
0
      asciiFile.addPos(item.m_pos);
503
0
      asciiFile.addNote(lF.str().c_str());
504
0
    });
505
0
  }
506
0
  int val=int(input->readLong(4));
507
0
  if (val!=-1)
508
0
    f << "f0=" << val << ",";
509
0
  ascFile.addPos(pos);
510
0
  ascFile.addNote(f.str().c_str());
511
0
  if (!m_mainParser->readUsed(*stream, "Matrix")) // size=144
512
0
    return false;
513
0
  return m_mainParser->readExtendedHeader(stream, 0x48, "Matrix",
514
0
  [this](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) {
515
0
    auto lInput=lStream->input();
516
0
    libmwaw::DebugFile &asciiFile = lStream->ascii();
517
0
    libmwaw::DebugStream lF;
518
0
    lF << "Mat" << item.m_id << ",";
519
0
    std::array<std::array<double, 9>, 2> matrices;
520
0
    for (size_t st=0; st<2; ++st) {
521
0
      lF << "mat" << st << "=[";
522
0
      auto &matrix = matrices[st];
523
0
      for (auto &d : matrix) {
524
0
        d=double(lInput->readLong(4))/65536.;
525
0
        lF << d << ",";
526
0
      }
527
0
      lF << "],";
528
0
    }
529
0
    m_state->m_idToMatrices[item.m_id]=matrices;
530
0
    asciiFile.addPos(item.m_pos);
531
0
    asciiFile.addNote(lF.str().c_str());
532
0
  });
533
0
}
534
535
////////////////////////////////////////////////////////////
536
// shapes
537
////////////////////////////////////////////////////////////
538
539
bool Canvas5Graph::findShapeDataZones(std::shared_ptr<Canvas5Structure::Stream> stream)
540
0
{
541
0
  if (!stream || !stream->input())
542
0
    return false;
543
0
  m_state->m_dataStream=stream;
544
0
  auto input=stream->input();
545
0
  m_state->m_dataStreamReverted=input->readInverted();
546
0
  auto &ascFile=stream->ascii();
547
0
  long pos=input->tell();
548
0
  int len=int(input->readULong(4));
549
0
  if ((len%20)!=0 || (long)((unsigned long)pos+4+(unsigned)len)<pos+4 || !input->checkPosition(pos+4+len)) {
550
0
    MWAW_DEBUG_MSG(("Canvas5Graph::findShapeDataZones: can not find zone 1\n"));
551
0
    return false;
552
0
  }
553
0
  ascFile.addPos(pos);
554
0
  ascFile.addNote("Entries(DataShap):");
555
556
0
  libmwaw::DebugStream f;
557
0
  int N=len/20;
558
0
  for (int i=0; i<N; ++i) {
559
0
    pos=input->tell();
560
0
    f.str("");
561
0
    f << "DataShap-" << i << ":";
562
0
    f << "id=" << input->readULong(4) << ",";
563
0
    f << "f0=" << input->readULong(4) << ","; // small number
564
0
    f << "sz=" << input->readULong(4) << ",";
565
0
    for (int j=0; j<4; ++j) { // 0
566
0
      int val=int(input->readLong(2));
567
0
      if (val)
568
0
        f << "f" << j+1 << "=" << val << ",";
569
0
    }
570
0
    ascFile.addPos(pos);
571
0
    ascFile.addNote(f.str().c_str());
572
0
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
573
0
  }
574
575
0
  for (int i=0; i<N; ++i) {
576
0
    pos=input->tell();
577
0
    f.str("");
578
0
    f << "DataShap-A" << i << ":";
579
0
    long zLen=long(input->readULong(4));
580
0
    if ((long)((unsigned long)pos+4+(unsigned long)zLen)<pos+4 || !input->checkPosition(pos+4+zLen)) {
581
0
      MWAW_DEBUG_MSG(("Canvas5Graph::findShapeDataZones: can not find a zone 1 length\n"));
582
0
      f << "###";
583
0
      ascFile.addPos(pos);
584
0
      ascFile.addNote(f.str().c_str());
585
0
      return false;
586
0
    }
587
0
    MWAWEntry entry;
588
0
    entry.setBegin(pos+4);
589
0
    entry.setLength(zLen);
590
0
    m_state->m_shapeZones.push_back(entry);
591
0
    ascFile.addPos(pos);
592
0
    ascFile.addNote(f.str().c_str());
593
0
    input->seek(pos+4+zLen, librevenge::RVNG_SEEK_SET);
594
0
  }
595
0
  return true;
596
0
}
597
598
bool Canvas5Graph::readShapes(Canvas5Structure::Stream &stream, int numShapes)
599
0
{
600
0
  auto input=stream.input();
601
0
  long pos=input->tell();
602
0
  if (!input->checkPosition(pos+4)) {
603
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: can not find the input\n"));
604
0
    return false;
605
0
  }
606
0
  long len=long(input->readULong(4));
607
0
  long endPos=pos+4+len;
608
0
  int const vers=version();
609
0
  int const dataSize=vers<9 ? 60 : 96;
610
0
  if (endPos<pos+4 || len<dataSize*numShapes || !input->checkPosition(endPos)) {
611
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: can not determine the zone length\n"));
612
0
    return false;
613
0
  }
614
615
0
  libmwaw::DebugFile &ascFile = stream.ascii();
616
0
  libmwaw::DebugStream f;
617
0
  f << "Entries(Shape):";
618
0
  ascFile.addPos(pos);
619
0
  ascFile.addNote(f.str().c_str());
620
0
  bool reverted=input->readInverted();
621
0
  for (int i=0; i<numShapes; ++i) {
622
0
    pos=input->tell();
623
0
    if (i<1) {
624
0
      ascFile.addPos(pos);
625
0
      ascFile.addNote("_");
626
0
      input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET);
627
0
      continue;
628
0
    }
629
0
    Canvas5GraphInternal::Shape shape;
630
0
    f.str("");
631
0
    f << "Shape-S" << i << ":";
632
0
    float fDim[4];
633
0
    for (auto &d : fDim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8));
634
0
    if (vers<9)
635
0
      shape.m_initialBox=MWAWBox2f(MWAWVec2f(fDim[1], fDim[0]),MWAWVec2f(fDim[3], fDim[2]));
636
0
    else
637
0
      shape.m_initialBox=MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]),MWAWVec2f(fDim[2], fDim[3]));
638
0
    for (auto &d : fDim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8));
639
0
    if (vers<9)
640
0
      shape.m_bdbox=MWAWBox2f(MWAWVec2f(fDim[1], fDim[0]),MWAWVec2f(fDim[3], fDim[2]));
641
0
    else
642
0
      shape.m_bdbox=MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]),MWAWVec2f(fDim[2], fDim[3]));
643
0
    unsigned block=unsigned(input->readULong(2));
644
0
    shape.m_pos=int((block<<16)|input->readULong(2));
645
0
    if (shape.m_pos==int(0xFFFFFFFF)) shape.m_pos=-1;
646
0
    shape.m_type=int(input->readULong(1));
647
0
    if (shape.m_type==100) { // none
648
0
      ascFile.addPos(pos);
649
0
      ascFile.addNote("_");
650
0
      input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET);
651
0
      continue;
652
0
    }
653
0
    f << "id=" << std::hex << input->readULong(4) << std::dec << ",";
654
0
    shape.m_values[0]=int(input->readULong(1));
655
0
    for (int j=0; j<3; ++j)
656
0
      shape.m_flags[j]=int(input->readULong(2));
657
0
    if (reverted) std::swap(shape.m_flags[1],shape.m_flags[2]);
658
0
    if (shape.m_flags[1]&0x60) {
659
0
      f << "##fl,";
660
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: find some unknown flags\n"));
661
0
    }
662
0
    for (int j=0; j<3; ++j) // small number, maybe parent id, child id, ???
663
0
      shape.m_values[j+1]=int(input->readLong(4));
664
0
    f << shape << ",";
665
0
    shape.m_id=i;
666
0
    m_state->m_idToShapeMap[i]=shape;
667
0
    ascFile.addPos(pos);
668
0
    ascFile.addNote(f.str().c_str());
669
0
    input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET);
670
0
  }
671
0
  if (input->tell()<endPos)
672
0
    ascFile.skipZone(input->tell(), endPos-1);
673
0
  if (&stream!=m_state->m_dataStream.get()) {
674
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapes: oops, the shape data stream seems bad\n"));
675
0
  }
676
0
  else {
677
0
    for (auto const &it : m_state->m_idToShapeMap) {
678
0
      if (it.second.m_pos>=0)
679
0
        readShapeData(it.first, it.second);
680
0
    }
681
0
  }
682
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
683
0
  return true;
684
0
}
685
686
bool Canvas5Graph::readShapeData(int id, Canvas5GraphInternal::Shape const &shape)
687
0
{
688
0
  auto &stream=m_state->m_dataStream;
689
0
  if (shape.m_pos < 0 || !stream) {
690
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: shape id=%d has not a valid position\n", id));
691
0
    return false;
692
0
  }
693
0
  if ((shape.m_flags[1]&0x419f)==0 && (shape.m_flags[2]&0xfff)==0 && shape.m_type>=4 && shape.m_type<=7)
694
0
    return true; // sometimes m_pos is set even if there is no data
695
0
  size_t bl=size_t(shape.m_pos>>16);
696
0
  long pos=shape.m_pos&0xffff;
697
0
  if (bl>=m_state->m_shapeZones.size() || pos+4 > m_state->m_shapeZones[bl].length()) {
698
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the block corresponding to shape id=%d\n", id));
699
0
    return false;
700
0
  }
701
702
0
  if (m_state->m_posToShapeDataMap.find(shape.m_pos)!=m_state->m_posToShapeDataMap.end())
703
0
    return true;
704
0
  auto const &entry=m_state->m_shapeZones[bl];
705
0
  auto input=stream->input();
706
0
  int const vers=version();
707
0
  libmwaw::DebugFile &ascFile = stream->ascii();
708
0
  libmwaw::DebugStream f;
709
0
  f << "DataShap-S" << id << ":";
710
711
0
  input->seek(entry.begin()+pos, librevenge::RVNG_SEEK_SET);
712
0
  pos=input->tell();
713
0
  int val=int(input->readULong(4));
714
0
  if (val!=id) f << "dup2=" << val << ",";
715
0
  f << shape.getTypeName() << ",";
716
717
0
  m_state->m_posToShapeDataMap[shape.m_pos]=Canvas5GraphInternal::ShapeData();
718
0
  Canvas5GraphInternal::ShapeData &data=m_state->m_posToShapeDataMap.find(shape.m_pos)->second;
719
0
  long len=(shape.m_flags[2]&0x1) ? long(input->readULong(4)) : 0;
720
0
  if (shape.m_flags[2]&0x2) f << "f2=" << long(input->readULong(4)) << ","; // find id=1???
721
0
  if (shape.m_flags[2]&0x4) data.m_ids[0]=unsigned(input->readULong(4));
722
0
  if (shape.m_flags[2]&0x8) f << "f8=" << long(input->readULong(4)) << ","; // never seen this one
723
0
  if (shape.m_flags[2]&0x10) data.m_ids[1]=unsigned(input->readULong(4));
724
0
  if (shape.m_flags[2]&0x20) data.m_type = unsigned(input->readULong(4));
725
0
  if (shape.m_flags[2]&0x40) f << "f40=" << long(input->readULong(4)) << ","; // never seen this one
726
0
  if (shape.m_flags[2]&0x80) data.m_shapeIds[0]=unsigned(input->readULong(4)); // checkme: replaced?
727
0
  if (shape.m_flags[2]&0x100) f << "f100=" << long(input->readULong(4)) << ","; // never seen this one
728
0
  if (shape.m_flags[2]&0x200) data.m_local[0]=int(input->readULong(4)); // text: id?, rectOval: roundX, arc angl1
729
0
  if (shape.m_flags[2]&0x400) data.m_local[1]=int(input->readULong(4)); // roundY, angl2
730
0
  if (shape.m_flags[2]&0x800) data.m_ids[2]=unsigned(input->readULong(4));
731
0
  if (shape.m_flags[1]&0x1) data.m_shapeIds[1]=unsigned(input->readULong(4));
732
0
  if (shape.m_flags[1]&0x2) data.m_shapeIds[2]=unsigned(input->readULong(4)); // child?
733
0
  if (shape.m_flags[1]&0x4) data.m_shapeIds[3]=unsigned(input->readULong(4)); // often simillar to shape1 ?
734
0
  if (shape.m_flags[1]&0x8) f << "g8=" << long(input->readULong(4)) << ","; // rotation?
735
0
  if (shape.m_flags[1]&0x10) f << "g10=" << long(input->readULong(4)) << ","; // ?
736
  // checkme: we need probably also test for f1&0x20 and f1&0x40
737
0
  if (shape.m_flags[1]&0x80) f << "g80=" << long(input->readULong(4)) << ","; // ?
738
0
  if (shape.m_flags[1]&0x100) f << "link[id]=" << long(input->readULong(4)) << ","; //  checkme: appear in v6 with id=3200
739
0
  if (shape.m_flags[1]&0x4000) f << "Xobd" << long(input->readULong(4)) << ","; // appear in v6, related to object data base
740
741
0
  if (data.m_type) f << "type=" << Canvas5Structure::getString(data.m_type) << ",";
742
0
  f << data;
743
744
0
  long actPos=input->tell();
745
0
  long endPos=actPos+len;
746
0
  if (endPos<actPos || endPos>entry.end()) {
747
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: oops, bad length for shape id=%d\n", id));
748
0
    f << "###";
749
0
    ascFile.addPos(pos);
750
0
    ascFile.addNote(f.str().c_str());
751
0
    return false;
752
0
  }
753
754
0
  if (len && shape.m_type!=2)
755
0
    ascFile.addDelimiter(input->tell(),'|');
756
757
0
  input->pushLimit(entry.end());
758
759
0
  data.m_stream=stream;
760
0
  data.m_streamReverted=input->readInverted();
761
0
  data.m_entry.setBegin(input->tell());
762
0
  data.m_entry.setLength(len);
763
764
0
  switch (shape.m_type) {
765
0
  case 2: // with type="TXT " or "TxtU"
766
    // will be parsed by sendText
767
0
    break;
768
0
  case 3: {
769
0
    if (len<(vers<9 ? 16 : 32)) {
770
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a line\n"));
771
0
      f << "###";
772
0
      break;
773
0
    }
774
0
    f << "pts=[";
775
0
    for (int i=0; i<2; ++i) {
776
0
      float fDim[2];
777
0
      for (auto &d : fDim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
778
0
      if (vers>=9)
779
0
        data.m_vertices.push_back(MWAWVec2f(fDim[0], fDim[1]));
780
0
      else
781
0
        data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0]));
782
0
      f << data.m_vertices.back() << ",";
783
0
    }
784
0
    f << "];";
785
0
    break;
786
0
  }
787
0
  case 4: // rect
788
0
  case 5: // rectOval
789
0
  case 6: // oval
790
0
  case 7: // arc
791
0
    if (vers>=9 && (shape.m_type==5 || shape.m_type==7) && len==16) {
792
0
      f << (shape.m_type==5 ? "round" : "angle") << "=";
793
0
      for (int i=0; i<2; ++i) {
794
0
        data.m_doubleValues[i]=m_mainParser->readDouble(*stream, 8);
795
0
        f << data.m_doubleValues[i] << (i==0 ? "x" : ",");
796
0
      }
797
0
      break;
798
0
    }
799
0
    if (len) {
800
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: find unexpected length\n"));
801
0
      f << "###";
802
0
      break;
803
0
    }
804
0
    if (shape.m_type==5)
805
0
      f << "round=" << float(data.m_local[0])/65536.f << "x"  << float(data.m_local[1])/65536.f << ",";
806
0
    else if (shape.m_type==7)
807
0
      f << "angle=" << float(data.m_local[0])/65536.f << "->"  << float(data.m_local[1])/65536.f << ",";
808
0
    break;
809
0
  case 9: // polyline
810
0
  case 10: { // spline
811
0
    if (len<8) {
812
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a polyline/spline\n"));
813
0
      f << "###";
814
0
      break;
815
0
    }
816
0
    if (vers<9)
817
0
      input->seek(4, librevenge::RVNG_SEEK_CUR);
818
0
    int N=m_mainParser->readInteger(*stream, vers<9 ? 4 : 8);
819
0
    f << "N=" << N << ",";
820
0
    if (vers>=9)
821
0
      input->seek(8, librevenge::RVNG_SEEK_CUR);
822
0
    int const fieldSize=vers<9 ? 4 : 8;
823
0
    if (4+fieldSize+2*fieldSize*N<4+fieldSize || (len-4-fieldSize)/(2*fieldSize)<N || 4+fieldSize+2*fieldSize*N>len) {
824
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData[polyline/spline]: can not read N\n"));
825
0
      f << "###";
826
0
      break;
827
0
    }
828
0
    f << "pts=[";
829
0
    for (int i=0; i<N; ++i) {
830
0
      float fDim[2];
831
0
      for (auto &d : fDim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
832
0
      if (vers<9)
833
0
        data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0]));
834
0
      else
835
0
        data.m_vertices.push_back(MWAWVec2f(fDim[0], fDim[1]));
836
0
      f << data.m_vertices.back() << ",";
837
0
    }
838
0
    f << "],";
839
0
    break;
840
0
  }
841
0
  case 52: { // special
842
0
    std::string extra;
843
0
    if (!readSpecialData(stream, len, data, extra))
844
0
      f << "###";
845
0
    f << extra;
846
0
    break;
847
0
  }
848
0
  case 20: // master elements ?
849
0
  case 99: { // group
850
0
    if (len<4) {
851
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected size for a group\n"));
852
0
      f << "###";
853
0
      break;
854
0
    }
855
0
    int N=int(input->readULong(4));
856
0
    f << "N=" << N << ",";
857
0
    if (4+4*N<4 || 4+4*N>len) {
858
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData[group]: can not read N\n"));
859
0
      f << "###";
860
0
      break;
861
0
    }
862
0
    f << "id=[";
863
0
    for (int i=0; i<N; ++i) {
864
0
      data.m_children.push_back(unsigned(input->readULong(4)));
865
0
      f << "S" << data.m_children.back() << ",";
866
0
    }
867
0
    f << "],";
868
0
    break;
869
0
  }
870
0
  default:
871
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: unexpected type\n"));
872
0
    f << "###";
873
0
    break;
874
0
  }
875
0
  ascFile.addPos(pos);
876
0
  ascFile.addNote(f.str().c_str());
877
878
0
  if (len && input->tell()!=endPos)
879
0
    ascFile.addDelimiter(input->tell(),'|');
880
0
  input->popLimit();
881
882
0
  return true;
883
0
}
884
885
std::shared_ptr<Canvas5GraphInternal::PseudoShape> Canvas5Graph::readSpecialData(std::shared_ptr<Canvas5Structure::Stream> stream, long len, unsigned type, MWAWBox2f const &box, std::string &extra)
886
0
{
887
0
  if (!stream)
888
0
    return nullptr;
889
0
  auto input=stream->input();
890
891
0
  auto res=std::make_shared<Canvas5GraphInternal::PseudoShape>();
892
0
  Canvas5GraphInternal::ShapeData &data=res->m_data;
893
0
  data.m_inMainZone=false;
894
0
  data.m_type=type;
895
896
0
  data.m_stream=stream;
897
0
  data.m_streamReverted=input->readInverted();
898
0
  data.m_entry.setBegin(input->tell());
899
0
  data.m_entry.setLength(len);
900
0
  if (!readSpecialData(stream, len, data, extra))
901
0
    return nullptr;
902
0
  auto &shape=res->m_shape;
903
0
  shape.m_type=52;
904
0
  shape.m_initialBox=shape.m_bdbox=box;
905
0
  return res;
906
0
}
907
908
bool Canvas5Graph::readSpecialData(std::shared_ptr<Canvas5Structure::Stream> stream, long len, Canvas5GraphInternal::ShapeData &data, std::string &extra)
909
0
{
910
0
  if (!stream)
911
0
    return false;
912
0
  auto input=stream->input();
913
0
  int const vers=version();
914
0
  libmwaw::DebugStream f;
915
0
  int val;
916
0
  switch (data.m_type) {
917
0
  case 0x43756265: // Cube
918
0
    if (len<(vers<9 ? 64 : 128)) {
919
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the cube points\n"));
920
0
      return false;
921
0
    }
922
0
    for (int i=0; i<8; ++i) { // front face, back face
923
0
      float pts[2];
924
0
      for (auto &c : pts) c=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
925
0
      if (vers>=9)
926
0
        std::swap(pts[0],pts[1]);
927
0
      data.m_vertices.push_back(MWAWVec2f(pts[1],pts[0]));
928
0
      f << data.m_vertices.back() << ",";
929
0
    }
930
0
    break;
931
0
  case 0x43765465: // CvTe, will be read when we create the shape
932
0
  case 0x44494d4e: // DIMN, will be read when we create the shape
933
0
    break;
934
0
  case 0x4e474f4e: { // NGON
935
0
    if (len<(vers<9 ? 56 : 72)) {
936
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readShapeData: can not find the NGON data\n"));
937
0
      return false;
938
0
    }
939
0
    val=int(input->readULong(2));
940
0
    if (val&0x100)
941
0
      f << "smooth,";
942
0
    val&=0xfeff;
943
0
    if (val)
944
0
      f << "fl=" << std::hex << val << std::hex << ",";
945
0
    if (vers<9) {
946
0
      for (int i=0; i<5; ++i) {
947
0
        val=int(input->readULong(2));
948
0
        int const expected[]= {1,0x255, 0x6ae0, 0x2440, 0x1404 };
949
0
        if (val!=expected[i]) f << "f" << i << "=" << val << ",";
950
0
      }
951
0
      for (int i=0; i<5; ++i) {
952
0
        val=int(input->readULong(4));
953
0
        int const expected[]= {0x22e5140, 0x2232300, 0x2556af0, 0x23718c2, 0xec634 };
954
0
        if (val!=expected[i]) f << "f" << i+6 << "=" << val << ",";
955
0
      }
956
0
    }
957
0
    else {
958
0
      for (int i=0; i<7; ++i) {
959
0
        val=int(input->readULong(2));
960
0
        int const expected[]= {0x3884, 0xbfff, 0xdc80,0,0x20, 0xa000, 0xb430};
961
0
        if (val!=expected[i]) f << "f" << i << "=" << val << ",";
962
0
      }
963
0
      for (int i=0; i<8; ++i) {
964
0
        val=int(input->readULong(2));
965
0
        if (val) f << "f" << i+8 << "=" << val << ",";
966
0
      }
967
0
    }
968
0
    data.m_doubleValues[0]=m_mainParser->readDouble(*stream,vers<9 ? 4 : 8);
969
0
    f << "rad[min]=" << data.m_doubleValues[1] << ",";
970
0
    f << "angles=[";
971
0
    for (int i=0; i<2; ++i) { // 2 angles: pt0, min
972
0
      data.m_doubleValues[i+1]=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8);
973
0
      f << data.m_doubleValues[i+1] << ",";
974
0
    }
975
0
    f << "],";
976
0
    data.m_ngonType=int(input->readULong(4));
977
0
    if (data.m_ngonType!=4) f << "type=" << data.m_ngonType << ",";
978
0
    data.m_specials[0]=int(input->readLong(2));
979
0
    f << "N=" << data.m_specials[0] << ",";
980
0
    for (int i=0; i<(vers<9 ? 3 : 5); ++i) {
981
0
      val=int(input->readULong(2));
982
0
      int const expected[]= {vers<9 ? 0x207 : 0x3830, 0, 0, 0, 0};
983
0
      if (val!=expected[i]) f << "g" << i << "=" << val << ",";
984
0
    }
985
0
    break;
986
0
  }
987
0
  case 0x65666665: // effe: will be read by sendEffect
988
0
  case 0x45787472: // Extr: will be read by sendExtrude
989
0
    break;
990
0
  case 0x4772644d: { // GrdL
991
0
    if (len<4) {
992
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a grid\n"));
993
0
      return false;
994
0
    }
995
0
    int subdiv[2];
996
0
    for (auto &d : subdiv) d=int(input->readULong(2));
997
0
    data.m_grid=MWAWVec2i(subdiv[0], subdiv[1]);
998
0
    f << "grid=" << data.m_grid << ",";
999
0
    break;
1000
0
  }
1001
0
  case 0x43436972: // CCir
1002
0
  case 0x53504952: { // SPIR
1003
0
    if (len<4) {
1004
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a ccircle/spiral\n"));
1005
0
      return false;
1006
0
    }
1007
0
    for (int i=0; i<2; ++i) data.m_specials[i]=int(input->readLong(2));
1008
0
    f << "N=" << data.m_specials[0] << ",";
1009
0
    if (data.m_specials[1]) f << "space[between]=" << data.m_specials[1] << ","; // 0: equidistant (only used by CCir)
1010
0
    break;
1011
0
  }
1012
0
  case 0x4d41434f: { // MACO: object from macros, never sent ?
1013
0
    if (len<(vers<9 ? 92 : 128)) {
1014
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[MACO]: unexpected size\n"));
1015
0
      return false;
1016
0
    }
1017
0
    val=int(input->readLong(4));
1018
0
    if (val!=2)
1019
0
      f << "f0=" << val << ",";
1020
0
    if (vers>=9)
1021
0
      input->seek(4, librevenge::RVNG_SEEK_CUR);
1022
0
    float dim[4];
1023
0
    for (auto &d : dim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1024
0
    if (vers<9)
1025
0
      f << "box=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])) << ",";
1026
0
    else
1027
0
      f << "box=" << MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3])) << ",";
1028
0
    for (int i=0; i<(vers<9 ? 13 : 17); ++i) { // f5=0|1
1029
0
      val=int(input->readLong(4));
1030
0
      if (val)
1031
0
        f << "f" << i+1 << "=" << val << ",";
1032
0
    }
1033
1034
0
    std::string sMaco;
1035
0
    m_imageParser->readMacroIndent(*stream, data.m_macoId, sMaco);
1036
0
    f << "id=[" << sMaco << "],";
1037
0
    break;
1038
0
  }
1039
0
  case 0x4f4c6e6b : { // OLnk
1040
0
    if (len<56) {
1041
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a link\n"));
1042
0
      return false;
1043
0
    }
1044
0
    f << "pts=[";
1045
0
    for (int i=0; i<4; ++i) {
1046
0
      float fDim[2];
1047
0
      for (auto &d : fDim) d=float(input->readLong(4))/65536.f;
1048
0
      data.m_vertices.push_back(MWAWVec2f(fDim[1], fDim[0]));
1049
0
      f << data.m_vertices.back() << ",";
1050
0
    }
1051
0
    f << "],";
1052
0
    for (int i=0; i<3; ++i) { // f0=small number, f1=0|5
1053
0
      val=int(input->readLong(4));
1054
0
      if (val)
1055
0
        f << "f" << i << "=" << val << ",";
1056
0
    }
1057
0
    val=int(input->readLong(2)); // find 4,5,7
1058
0
    if (val) f << "f3=" << val << ",";
1059
0
    break;
1060
0
  }
1061
0
  case 0x706f626a:  // pobj
1062
0
    if (len<8) {
1063
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a pobj\n"));
1064
0
      return false;
1065
0
    }
1066
0
    for (int i=0; i<2; ++i)
1067
0
      data.m_specials[i]=int(input->readULong(4));
1068
0
    if (data.m_specials[0])
1069
0
      f << "B" << data.m_specials[1] << ":" << data.m_specials[0] << ",";
1070
0
    else
1071
0
      f << "B" << data.m_specials[1] << ",";
1072
0
    break;
1073
0
  case 0x54585420: // TEXT, only in Vkfl, will be read when we create the shape
1074
0
    if (data.m_inMainZone) {
1075
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected text in main zone\n"));
1076
0
      return false;
1077
0
    }
1078
0
    break;
1079
0
  case 0x41474946:  // AGIF: appear in v6
1080
0
    if (len<12) {
1081
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a AGIF\n"));
1082
0
      return false;
1083
0
    }
1084
0
    for (int i=0; i<3; ++i)
1085
0
      data.m_specials[i]=int(input->readULong(4));
1086
0
    if (data.m_specials[0]!=1)
1087
0
      f << "AG" << data.m_specials[1] << ":" << data.m_specials[0];
1088
0
    else
1089
0
      f << "AG" << data.m_specials[1];
1090
0
    if (data.m_specials[2]!=1)
1091
0
      f << "[" << data.m_specials[2] << "]";
1092
0
    f << ",";
1093
0
    break;
1094
0
  case 0x43574542: { // CWEB: a button with 3 potential shapes (and sound)
1095
    // checkme: find 8 times in two files, but with the same content...
1096
    //          this zone is clearly related with RsrcWEBE (unparsed)
1097
0
    if (len<40) {
1098
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[CWEB]: unexpected size\n"));
1099
0
      return false;
1100
0
    }
1101
0
    long pos=input->tell();
1102
0
    for (int i=0; i<2; ++i) {
1103
0
      val=int(input->readLong(4));
1104
0
      int const expected[]= {0x1261998, 1};
1105
0
      if (val!=expected[i])
1106
0
        f << "f" << i << "=" << val << ",";
1107
0
    }
1108
0
    f << "lengths=[";
1109
0
    std::vector<long> lengths;
1110
0
    for (int i=0; i<8; ++i) { // 0-2: image, 3-5: sound, 6-7: unsure ???
1111
0
      long len1=long(input->readLong(4));
1112
0
      if (!len1 && i>=5) break;
1113
0
      lengths.push_back(len1);
1114
0
      f << std::hex << len1 << std::dec << ",";
1115
0
    }
1116
0
    f << "],";
1117
0
    input->seek(pos+40, librevenge::RVNG_SEEK_SET);
1118
1119
0
    libmwaw::DebugFile &ascFile = stream->ascii();
1120
0
    long endPos=pos+len;
1121
0
    for (size_t i=0; i<6; ++i) {
1122
0
      if (i>=lengths.size())
1123
0
        break;
1124
0
      long l=lengths[i];
1125
0
      if (l==0) continue;
1126
0
      pos=input->tell();
1127
0
      if (l < 0 || (long)((unsigned long)pos+(unsigned long)l)<pos || pos+l>endPos) {
1128
0
        extra=f.str();
1129
0
        ascFile.addPos(input->tell());
1130
0
        ascFile.addNote("DataShap[CWEB]:###");
1131
0
        return false;
1132
0
      }
1133
0
      if (i<3) { // image
1134
0
        data.m_cweb[i].setBegin(pos);
1135
0
        data.m_cweb[i].setLength(l);
1136
0
      }
1137
0
      else {
1138
        // look like a basic snd file: see https://en.wikipedia.org/wiki/Au_file_format
1139
0
        ascFile.addPos(pos);
1140
0
        ascFile.addNote("DataShap[CWEB,snd]:##");
1141
0
      }
1142
0
      input->seek(pos+l, librevenge::RVNG_SEEK_SET);
1143
0
    }
1144
0
    if (input->tell()!=endPos) {
1145
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[CWEB]: find extra data\n"));
1146
0
      ascFile.addPos(input->tell());
1147
0
      ascFile.addNote("DataShap:special,CWEB:###");
1148
0
    }
1149
0
    break;
1150
0
  }
1151
0
  case 0x516b546d:  // QkTm: appear in v6
1152
0
    if (len!=4) {
1153
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a QkTm\n"));
1154
0
      return false;
1155
0
    }
1156
0
    data.m_specials[0]=int(input->readULong(4));
1157
0
    f << "QK" << data.m_specials[0] << ",";
1158
0
    break;
1159
0
  case 0x23476465: { // #Gde: text with column and section, appear in v6
1160
0
    if (len<28) {
1161
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: unexpected size\n"));
1162
0
      return false;
1163
0
    }
1164
0
    auto fl=input->readULong(4);
1165
0
    if (fl!=0x1771) f << "fl=" << std::hex << fl << std::dec << ",";
1166
0
    data.m_gdeType=int(input->readULong(4));
1167
0
    if (data.m_gdeType<=0 || data.m_gdeType>=4 || (data.m_gdeType==1 && len!=(vers<9 ? 52: 60))) {
1168
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: unexpected type0\n"));
1169
0
      f << "###type0=" << data.m_gdeType << "," << len << ",";
1170
0
      extra=f.str();
1171
0
      return false;
1172
0
    }
1173
0
    char const *wh[]= {"type1","type2","section/column"};
1174
0
    f << wh[data.m_gdeType-1] << ",";
1175
0
    switch (data.m_gdeType) {
1176
0
    case 0: {
1177
0
      float dims[2];
1178
0
      for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 4));
1179
0
      f << "dim=" << MWAWVec2f(dims[0], dims[1]) << ","; // 36x36 or 50x50
1180
0
      for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 4));
1181
0
      f << "unk=" << MWAWVec2f(dims[0], dims[1]) << ","; // 0.25x0.25..
1182
0
      f << "unk1=" << std::hex << input->readULong(4) << std::dec << ",";
1183
0
      break;
1184
0
    }
1185
0
    case 1: {
1186
0
      for (int i=0; i<3; ++i) { // f0=0|1, f1=f2=0|1
1187
0
        val=int(input->readULong(4));
1188
0
        int const expected[]= {0, 1, 1};
1189
0
        if (val!=expected[i]) f << "f" << i << "=" << val << ",";
1190
0
      }
1191
0
      if (vers>=9)
1192
0
        input->seek(4, librevenge::RVNG_SEEK_CUR);
1193
1194
0
      float dims[2];
1195
0
      for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1196
0
      f << "dim=" << MWAWVec2f(dims[1], dims[0]) << ","; // 36x36 or 50x50
1197
0
      if (vers<9)
1198
0
        f << "unk0=" << std::hex << input->readULong(4) << std::dec << ",";
1199
0
      for (auto &d : dims) d=float(m_mainParser->readDouble(*stream, 8));
1200
0
      f << "unk=" << MWAWVec2f(dims[0], dims[1]) << ","; // 0.25, 0.25 or 1x1 except when unkn0=0
1201
0
      f << "unk1=" << std::hex << input->readULong(4) << std::dec << ",";
1202
0
      break;
1203
0
    }
1204
0
    case 2: {
1205
0
      val=int(input->readULong(4)); // 0|1
1206
0
      if (val) f << "f0=" << val << ",";
1207
0
      int N=int(input->readULong(4));
1208
0
      f << "N=" << N << ",";
1209
0
      unsigned const headerSz=vers<9 ? 28 : 36;
1210
0
      unsigned const dataSz=vers<9 ? 8 : 16;
1211
0
      if (N<0 || int((len-headerSz)/dataSz)<N || len!=long(dataSz*unsigned(N)+headerSz)) {
1212
0
        MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N value\n"));
1213
0
        f << "###";
1214
0
        extra=f.str();
1215
0
        return false;
1216
0
      }
1217
0
      f << "unk=[";
1218
0
      for (int i=0; i<N; ++i) {
1219
0
        val=int(input->readLong(4)); // 1|2
1220
0
        if (vers>=9)
1221
0
          input->seek(4, librevenge::RVNG_SEEK_CUR);
1222
0
        f << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ":" << val << ",";
1223
0
      }
1224
0
      f << "],";
1225
0
      f << "unk1=[";
1226
0
      for (int i=0; i<(vers<9 ? 3 : 5); ++i)
1227
0
        f << float(input->readLong(4))/65536 << ",";
1228
0
      f << "],";
1229
0
      break;
1230
0
    }
1231
0
    case 3:
1232
0
    default: {
1233
0
      int N=int(input->readLong(4));
1234
0
      f << "N=" << N << ",";
1235
0
      int const dataSz=vers<9 ? 100 : 120;
1236
0
      if (N<0 || (len-28)/dataSz<N) {
1237
0
        MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N value\n"));
1238
0
        f << "###";
1239
0
        extra=f.str();
1240
0
        return false;
1241
0
      }
1242
0
      libmwaw::DebugStream f2;
1243
0
      libmwaw::DebugFile &ascFile = stream->ascii();
1244
0
      for (int i=0; i<N; ++i) {
1245
0
        long pos=input->tell();
1246
0
        f2.str("");
1247
0
        f2 << "DataShap[#Gde-S" << i << ":]";
1248
0
        Canvas5GraphInternal::SectionData section;
1249
0
        for (int j=0; j<4; ++j) {
1250
0
          val=int(input->readLong(4));
1251
0
          if (val)
1252
0
            f2 << "f" << j << "=" << val << ",";
1253
0
        }
1254
0
        float dim[4];
1255
0
        for (auto &d : dim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1256
0
        if (vers<9)
1257
0
          section.m_bdBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
1258
0
        else
1259
0
          section.m_bdBox=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
1260
0
        f2 << "box=" << section.m_bdBox << ",";
1261
0
        if (vers>=9) {
1262
0
          f2 << "unkn=" << m_mainParser->readDouble(*stream, 8) << ","; // 2
1263
0
          val=int(input->readLong(4));
1264
0
          if (val)
1265
0
            f2 << "f2=" << val << ",";
1266
0
        }
1267
0
        long actPos=input->tell();
1268
0
        std::string name;
1269
0
        for (int j=0; j<28; ++j) { // checkme what is the bigger length
1270
0
          char c=char(input->readULong(1));
1271
0
          if (!c)
1272
0
            break;
1273
0
          name+=c;
1274
0
        }
1275
0
        f2 << name << ",";
1276
0
        input->seek(actPos+28, librevenge::RVNG_SEEK_SET);
1277
0
        for (int j=0; j<(vers<9 ? 7 : 6); ++j) { // f11=0|1
1278
0
          val=int(input->readLong(4));
1279
0
          if (val==(j<3 ? 1 : 0)) continue;
1280
0
          if (j==0)
1281
0
            f2 << "writing[mode]=" << val << ","; // 2: means first rigth columns then toward left
1282
0
          else
1283
0
            f2 << "f" << j+5 << "=" << val << ",";
1284
0
        }
1285
0
        if (vers<9) {
1286
0
          val=int(input->readLong(4));
1287
0
          if (val!=0x20000)
1288
0
            f2 << "g0=" << float(val)/65536;
1289
0
        }
1290
0
        section.m_numColumns=int(input->readLong(4));
1291
0
        f2 << "num[columns]=" << section.m_numColumns << ",";
1292
0
        f2 << "id=" << input->readLong(4) << ",";
1293
0
        data.m_sections.push_back(section);
1294
1295
0
        ascFile.addPos(pos);
1296
0
        ascFile.addNote(f2.str().c_str());
1297
0
        input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET);
1298
0
      }
1299
1300
0
      long pos=input->tell();
1301
0
      f2.str("");
1302
0
      f2 << "DataShap[#Gde-columns]:";
1303
0
      if (vers<9) {
1304
0
        float dim[2];
1305
0
        for (auto &d : dim) d=float(input->readLong(4))/65536;
1306
0
        f2 << "orig=" << MWAWVec2f(dim[1],dim[0]) << ",";
1307
0
      }
1308
0
      else
1309
0
        input->seek(8, librevenge::RVNG_SEEK_CUR);
1310
0
      int N0=int(input->readLong(4));
1311
0
      f2 << "num[columns]=" << N0 << ",";
1312
0
      int const data1Sz=vers<9 ? 8 : 16;
1313
0
      if (N0<0 || 28+dataSz*N+data1Sz*N0<len || (len-dataSz*N-28)/data1Sz<N0) {
1314
0
        MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData[#Gde]: can not read the N0 value\n"));
1315
0
        f2 << "###";
1316
0
        ascFile.addPos(pos);
1317
0
        ascFile.addNote(f2.str().c_str());
1318
0
        extra=f.str();
1319
0
        return false;
1320
0
      }
1321
0
      f2 << "pos=[";
1322
0
      for (int i=0; i<=2*N0; ++i)
1323
0
        f2 << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ",";
1324
0
      f2 << "],";
1325
0
      ascFile.addPos(pos);
1326
0
      ascFile.addNote(f2.str().c_str());
1327
0
      break;
1328
0
    }
1329
0
    }
1330
0
    break;
1331
0
  }
1332
0
  case 0x416e4766: // AnGf: appear in v7, will be parsed when we send data
1333
0
    break;
1334
0
  case 0x70636567:  // pceg: appear in v7
1335
0
    if (len<8) {
1336
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a pceg\n"));
1337
0
      return false;
1338
0
    }
1339
0
    val=int(input->readULong(4));
1340
0
    if (val!=0x3251999)
1341
0
      f << "f0=" << std::hex << val << std::dec << ",";
1342
0
    data.m_specials[1]=int(input->readULong(4));
1343
0
    f << "PC" << data.m_specials[1] << ",";
1344
0
    break;
1345
0
  case 0x54656368: // Tech: appear in v7, will be parsed when we send data
1346
0
    break;
1347
1348
0
  case 0x72656750: // regP: registration mark, appear in v8
1349
0
    if (len<16) {
1350
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected size for a regP\n"));
1351
0
      return false;
1352
0
    }
1353
0
    for (int i=0; i<4; ++i) {
1354
0
      val=int(input->readLong(4));
1355
0
      int const expected[]= {0x7df, 0x700, 1, 1};
1356
0
      if (val!=expected[i])
1357
0
        f << "f" << i << "=" << val << ",";
1358
0
    }
1359
0
    break;
1360
0
  default:
1361
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readSpecialData: unexpected special %s\n", Canvas5Structure::getString(data.m_type).c_str()));
1362
0
    return false;
1363
0
  }
1364
0
  extra=f.str();
1365
0
  return true;
1366
0
}
1367
1368
////////////////////////////////////////////////////////////
1369
1370
bool Canvas5Graph::readDeR3(std::shared_ptr<Canvas5Structure::Stream> stream, Canvas5StyleManager::StyleList &styles)
1371
0
{
1372
0
  if (!stream || !stream->input())
1373
0
    return false;
1374
0
  auto input=stream->input();
1375
0
  long pos=input->tell();
1376
0
  int const vers=version();
1377
0
  int const headerSize=vers<9 ? 124 : 160;
1378
0
  if (!input->checkPosition(pos+headerSize)) {
1379
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: the zone is too short 1\n"));
1380
0
    return false;
1381
0
  }
1382
0
  libmwaw::DebugFile &ascFile = stream->ascii();
1383
0
  libmwaw::DebugStream f;
1384
0
  int val;
1385
0
  f << "Entries(DeR3):";
1386
0
  for (int i=0; i<2; ++i) {
1387
0
    val=int(input->readLong(2));
1388
0
    if (val!=(i==0 ? 2 : 0))
1389
0
      f << "f" << i << "=" << val << ",";
1390
0
  }
1391
0
  unsigned name=unsigned(input->readULong(4));
1392
0
  if (name!=0x44655233) { // "DeR3"
1393
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: unexcepted header\n"));
1394
0
    return false;
1395
0
  }
1396
0
  int nLines=0;
1397
0
  for (int i=0; i<4; ++i) {
1398
0
    val=int(input->readULong(2));
1399
0
    if (val==0) continue;
1400
0
    if (i==2) {
1401
0
      nLines=val;
1402
0
      f << "n[lines]=" << val << ",";
1403
0
    }
1404
0
    else
1405
0
      f << "f" << i+2 << "=" << val << ",";
1406
0
  }
1407
0
  unsigned long lengths[7], totalLength=0;
1408
0
  f << "len=[";
1409
0
  for (auto &l : lengths) {
1410
0
    l=input->readULong(4);
1411
0
    if (totalLength+l<totalLength) {
1412
0
      f << "###";
1413
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad lengths\n"));
1414
0
      ascFile.addPos(pos);
1415
0
      ascFile.addNote(f.str().c_str());
1416
0
      return false;
1417
0
    }
1418
0
    totalLength+=l;
1419
0
    if (l)
1420
0
      f << l << ",";
1421
0
    else
1422
0
      f << "_,";
1423
0
    if (long(l)<0) {
1424
0
      f << "###";
1425
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: a length is bad\n"));
1426
0
      ascFile.addPos(pos);
1427
0
      ascFile.addNote(f.str().c_str());
1428
0
      return false;
1429
0
    }
1430
0
  }
1431
0
  f << "],";
1432
0
  for (int i=0; i<(vers<9 ? 2 : 6); ++i) { // g0=0|12
1433
0
    val=int(input->readLong(2));
1434
0
    if (val) f << "g" << i << "=" << val << ",";
1435
0
  }
1436
0
  for (int i=0; i<2; ++i) { // dim0~=1 or dim2=0-100
1437
0
    double dVal=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8);
1438
0
    if (dVal<1 || dVal>1)
1439
0
      f << "dim" << i << "=" << dVal << ",";
1440
0
  }
1441
0
  int nIntervs=int(input->readLong(4));
1442
0
  if (nIntervs) f << "n[interv]=" << nIntervs << ",";
1443
0
  if (nIntervs<0 || (int(lengths[3])<nIntervs*12)) {
1444
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad number of tabulations\n"));
1445
0
    f << "###";
1446
0
    nIntervs=0;
1447
0
  }
1448
0
  val=int(input->readLong(4));
1449
0
  if (val!=10) f << "g2=" << val << ",";
1450
0
  for (int i=0; i<30; ++i) { // g2=1-6, g3=-1, g28=0-466
1451
0
    val=int(input->readLong(2));
1452
0
    if (val) f << "g" << i+3 << "=" << val << ",";
1453
0
  }
1454
0
  int const widthSize=vers<9 ? 4 : 8;
1455
0
  int const tabSize=vers<9 ? 12 : 24;
1456
0
  if (pos+headerSize+long(totalLength)<pos+headerSize || !input->checkPosition(pos+headerSize+long(totalLength)) ||
1457
0
      int(lengths[0])<4*(nLines+1) || int(lengths[1])<2*(nLines+1) || int(lengths[2])<widthSize*nLines ||
1458
0
      (lengths[3]%12)!=0 || (int(lengths[4])%tabSize)!=0) {
1459
0
    f << "###";
1460
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3: bad lengths\n"));
1461
0
    ascFile.addPos(pos);
1462
0
    ascFile.addNote(f.str().c_str());
1463
0
    return false;
1464
0
  }
1465
0
  ascFile.addPos(pos);
1466
0
  ascFile.addNote(f.str().c_str());
1467
0
  input->seek(pos+headerSize, librevenge::RVNG_SEEK_SET);
1468
1469
0
  if (lengths[0]) {
1470
0
    pos=input->tell();
1471
0
    f.str("");
1472
0
    f << "DeR3-line:numChar=[";
1473
0
    for (int i=0; i<=nLines; ++i) f << input->readULong(4) << ",";
1474
0
    f << "],";
1475
0
    ascFile.addPos(pos);
1476
0
    ascFile.addNote(f.str().c_str());
1477
0
    input->seek(pos+long(lengths[0]), librevenge::RVNG_SEEK_SET);
1478
0
  }
1479
1480
0
  if (lengths[1]) {
1481
0
    pos=input->tell();
1482
0
    f.str("");
1483
0
    f << "DeR3-flags:fl=[";
1484
0
    for (int i=0; i<=nLines; ++i) f << std::hex << input->readULong(2) << std::dec << ",";
1485
0
    f << "],";
1486
0
    ascFile.addPos(pos);
1487
0
    ascFile.addNote(f.str().c_str());
1488
0
    input->seek(pos+long(lengths[1]), librevenge::RVNG_SEEK_SET);
1489
0
  }
1490
1491
0
  if (lengths[2]) {
1492
0
    pos=input->tell();
1493
0
    f.str("");
1494
0
    f << "DeR3-widths:w=[";
1495
0
    for (int i=0; i<nLines; ++i) f << m_mainParser->readDouble(*stream, vers<9 ? 4 : 8) << ",";
1496
0
    f << "],";
1497
0
    ascFile.addPos(pos);
1498
0
    ascFile.addNote(f.str().c_str());
1499
0
    input->seek(pos+long(lengths[2]), librevenge::RVNG_SEEK_SET);
1500
0
  }
1501
1502
0
  long endPos=input->tell()+long(lengths[3]);
1503
0
  for (int i=0; i<int(lengths[3]/12); ++i) {
1504
0
    if (i>=nIntervs)
1505
0
      break;
1506
0
    pos=input->tell();
1507
0
    f.str("");
1508
0
    f << "DeR3-int" << i << ":";
1509
0
    f << "len=" << float(input->readLong(4))/65536.f << ",";
1510
0
    f << "type=" << input->readLong(2) << ",";
1511
0
    val=int(input->readLong(2));
1512
0
    if (val) f << "f1=" << val << ",";
1513
0
    f << "pos=" << float(input->readLong(4))/65536.f << ",";
1514
0
    ascFile.addPos(pos);
1515
0
    ascFile.addNote(f.str().c_str());
1516
0
    input->seek(pos+12, librevenge::RVNG_SEEK_SET);
1517
0
  }
1518
0
  if (input->tell()!=endPos) {
1519
0
    ascFile.addPos(input->tell());
1520
0
    ascFile.addNote("_");
1521
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1522
0
  }
1523
1524
0
  for (int i=0; i<int(lengths[4])/tabSize; ++i) {
1525
0
    pos=input->tell();
1526
0
    f.str("");
1527
0
    f << "DeR3-tab" << i << ":";
1528
0
    f << "pos=" << m_mainParser->readDouble(*stream, vers<9 ? 4: 8) << ",";
1529
0
    f << "type=" << input->readLong(2) << ",";
1530
0
    for (int j=0; j<(vers<9 ? 3 : 7); ++j) {
1531
0
      val=int(input->readLong(2));
1532
0
      if (val) f << "f" << j << "=" << val << ",";
1533
0
    }
1534
0
    ascFile.addPos(pos);
1535
0
    ascFile.addNote(f.str().c_str());
1536
0
    input->seek(pos+tabSize, librevenge::RVNG_SEEK_SET);
1537
0
  }
1538
1539
0
  if (lengths[5]) {
1540
0
    pos=input->tell();
1541
0
    f.str("");
1542
0
    f<< "DeR3-A";
1543
0
    ascFile.addPos(pos);
1544
0
    ascFile.addNote(f.str().c_str());
1545
0
    input->seek(pos+long(lengths[5]), librevenge::RVNG_SEEK_SET);
1546
0
  }
1547
1548
0
  if (!lengths[6]) return true;
1549
1550
0
  pos=input->tell();
1551
0
  endPos=pos+long(lengths[6]);
1552
0
  f.str("");
1553
0
  f<< "Entries(ParaStyl),DeR3-style:";
1554
1555
0
  int N[2];
1556
0
  f << "N=[";
1557
0
  for (auto &n : N) {
1558
0
    n=int(input->readULong(4));
1559
0
    f << n << ",";
1560
0
  }
1561
0
  f << "],";
1562
0
  f << "len=" << input->readULong(4) << ",";
1563
0
  f << "max[tabs,sz]=" << int(input->readULong(4)) << ",";
1564
0
  int styleSize=vers<9 ? 128 : 224;
1565
0
  if (lengths[6]<40 || N[0]<0 || N[1]<0 || int(lengths[6]-40)/styleSize<N[0] ||
1566
0
      long(N[0])*styleSize+40<40 || long(N[0])*styleSize+40>long(lengths[6])) {
1567
0
    MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: bad N\n"));
1568
0
    f << "###";
1569
0
    ascFile.addPos(pos);
1570
0
    ascFile.addNote(f.str().c_str());
1571
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1572
0
    return true;
1573
0
  }
1574
0
  ascFile.addPos(pos);
1575
0
  ascFile.addNote(f.str().c_str());
1576
1577
0
  input->seek(pos+(vers<9 ? 28 : 32), librevenge::RVNG_SEEK_SET);
1578
0
  styles.m_paragraphs.resize(size_t(N[0]));
1579
0
  for (int i=0; i<N[0]; ++i) {
1580
0
    pos=input->tell();
1581
0
    f.str("");
1582
0
    f<< "ParaStyl-E" << i+1 << ":";
1583
0
    ascFile.addPos(pos);
1584
0
    ascFile.addNote(f.str().c_str());
1585
0
    m_styleManager->readParaStyle(stream, i+1, &styles);
1586
0
    input->seek(pos+styleSize, librevenge::RVNG_SEEK_SET);
1587
0
  }
1588
1589
0
  for (int t=0; t<N[1]; ++t) {
1590
0
    pos=input->tell();
1591
0
    f.str("");
1592
0
    f << "DeR3-Tab" << t+1 << ":";
1593
0
    val=int(input->readULong(4));
1594
0
    if (val!=1)
1595
0
      f << "used=" << val << ",";
1596
0
    int len=int(input->readULong(4));
1597
0
    if (len<0 || pos+16+len > endPos) {
1598
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: bad tab size\n"));
1599
0
      f << "###";
1600
0
      ascFile.addPos(pos);
1601
0
      ascFile.addNote(f.str().c_str());
1602
0
      input->seek(endPos, librevenge::RVNG_SEEK_SET);
1603
0
      return true;
1604
0
    }
1605
0
    for (int i=0; i<4; ++i) { // 0
1606
0
      val=int(input->readLong(2));
1607
0
      if (val) f << "f" << i << "=" << val << ",";
1608
0
    }
1609
0
    double dVal=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8);
1610
0
    if (dVal<36 || dVal>36)
1611
0
      f << "dim?=" << dVal << ",";
1612
0
    int n=int(input->readULong(2));
1613
0
    if (n) f << "N=" << n << ",";
1614
0
    if (n<0 || len < (vers<9 ? 0 : 24) + tabSize*n) {
1615
0
      MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: the num of tab seems bad\n"));
1616
0
      f << "###";
1617
0
      n=0;
1618
0
    }
1619
0
    for (int i=0; i<(vers<9 ? 3 : 7); ++i) { // 0
1620
0
      val=int(input->readLong(2));
1621
0
      if (val) f << "f" << i+4 << "=" << val << ",";
1622
0
    }
1623
0
    f << "tabs=[";
1624
0
    std::vector<MWAWTabStop> tabs;
1625
0
    tabs.resize(size_t(n));
1626
0
    for (size_t i=0; i<size_t(n); ++i) {
1627
0
      MWAWTabStop &tab=tabs[i];
1628
0
      tab.m_position=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8)/72;
1629
0
      int type=int(input->readULong(2));
1630
0
      switch (type) {
1631
0
      case 0: // left
1632
0
        break;
1633
0
      case 1:
1634
0
        tab.m_alignment=MWAWTabStop::CENTER;
1635
0
        break;
1636
0
      case 2:
1637
0
        tab.m_alignment=MWAWTabStop::RIGHT;
1638
0
        break;
1639
0
      case 3:
1640
0
        tab.m_alignment=MWAWTabStop::DECIMAL;
1641
0
        tab.m_decimalCharacter=',';
1642
0
        break;
1643
0
      case 4:
1644
0
        tab.m_alignment=MWAWTabStop::DECIMAL;
1645
0
        tab.m_decimalCharacter='\'';
1646
0
        break;
1647
0
      default:
1648
0
        MWAW_DEBUG_MSG(("Canvas5Graph::readDeR3[G]: unknown tab type\n"));
1649
0
        f << "###type=" << val << ",";
1650
0
        break;
1651
0
      }
1652
0
      f << tab;
1653
0
      for (int j=0; j<(vers<9 ? 3 : 7); ++j) { // v9: f2 is probably related to leader char but 0x30 mean 'a' ?
1654
0
        val=int(input->readLong(2));
1655
0
        if (val) f << ":f" << j << "=" << val << ",";
1656
0
      }
1657
0
      f << ",";
1658
0
    }
1659
0
    f << "],";
1660
0
    if (!tabs.empty()) {
1661
0
      for (auto &paraId : styles.m_paragraphs) {
1662
0
        if (paraId.second==t+1)
1663
0
          paraId.first.m_tabs=tabs;
1664
0
      }
1665
0
    }
1666
0
    ascFile.addPos(pos);
1667
0
    ascFile.addNote(f.str().c_str());
1668
0
    input->seek(pos+16+len, librevenge::RVNG_SEEK_SET);
1669
0
  }
1670
1671
0
  pos=input->tell();
1672
0
  if (pos!=endPos) { // checkme: list of 0
1673
0
    ascFile.addPos(pos);
1674
0
    ascFile.addNote("_");
1675
0
  }
1676
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1677
0
  return true;
1678
0
}
1679
1680
////////////////////////////////////////////////////////////
1681
//
1682
// Low level
1683
//
1684
////////////////////////////////////////////////////////////
1685
1686
////////////////////////////////////////////////////////////
1687
// send data to the listener
1688
////////////////////////////////////////////////////////////
1689
bool Canvas5Graph::sendShape(int sId)
1690
0
{
1691
0
  return sendShape(sId, LocalState());
1692
0
}
1693
1694
bool Canvas5Graph::sendShape(int sId, Canvas5Graph::LocalState const &local)
1695
0
{
1696
0
  auto const &it = m_state->m_idToShapeMap.find(sId);
1697
0
  if (it==m_state->m_idToShapeMap.end()) {
1698
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendShape: can not find the shape %d\n", sId));
1699
0
    return false;
1700
0
  }
1701
0
  if (m_state->m_sendIdSet.find(sId)!=m_state->m_sendIdSet.end()) {
1702
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendShape: loop detected for shape %d\n", sId));
1703
0
    return false;
1704
0
  }
1705
0
  m_state->m_sendIdSet.insert(sId);
1706
0
  bool res=send(it->second, local);
1707
0
  m_state->m_sendIdSet.erase(sId);
1708
0
  return res;
1709
0
}
1710
1711
void Canvas5Graph::send(MWAWListenerPtr listener, MWAWGraphicShape const &shape, MWAWTransformation const &transform,
1712
                        MWAWGraphicStyle const &style)
1713
0
{
1714
0
  if (!listener)
1715
0
    return;
1716
0
  MWAWGraphicShape fShape=shape;
1717
0
  if (!transform.isIdentity())
1718
0
    fShape=fShape.transform(transform);
1719
0
  auto shapeBox=fShape.getBdBox();
1720
0
  MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
1721
0
  pos.m_anchorTo = MWAWPosition::Page;
1722
0
  listener->insertShape(pos, fShape, style);
1723
0
}
1724
1725
void Canvas5Graph::send(MWAWListenerPtr listener, librevenge::RVNGString const &text, MWAWVec2f const &center,
1726
                        MWAWTransformation const &transform, MWAWFont const &font, bool addFrame)
1727
0
{
1728
0
  if (!listener || text.empty())
1729
0
    return;
1730
1731
0
  MWAWPosition measurePos(center-MWAWVec2f(30,6), MWAWVec2f(60,12), librevenge::RVNG_POINT);
1732
0
  measurePos.m_anchorTo = MWAWPosition::Page;
1733
0
  std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, MWAWInputStreamPtr(), text, font));
1734
1735
0
  MWAWGraphicStyle measureStyle;
1736
0
  measureStyle.m_lineWidth=addFrame ? 1 : 0;
1737
0
  measureStyle.setSurfaceColor(MWAWColor::white());
1738
1739
0
  MWAWTransformation transf;
1740
0
  float rotation=0;
1741
0
  MWAWVec2f shearing;
1742
0
  if (!transform.isIdentity() && transform.decompose(rotation,shearing,transf,center)) {
1743
0
    auto shapeBox=transf*MWAWBox2f(center-MWAWVec2f(30,6),center+MWAWVec2f(30,6));
1744
0
    measurePos.setOrigin(shapeBox[0]);
1745
0
    measurePos.setSize(shapeBox[1]-shapeBox[0]);
1746
0
    measureStyle.m_rotate=-rotation;
1747
0
  }
1748
0
  listener->insertTextBox(measurePos, doc, measureStyle);
1749
0
}
1750
1751
bool Canvas5Graph::send(Canvas5GraphInternal::Shape const &shape, Canvas5Graph::LocalState const &lTransform)
1752
0
{
1753
0
  auto listener=m_parserState->m_graphicListener;
1754
0
  if (!listener) {
1755
0
    MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: can not find the listener\n"));
1756
0
    return false;
1757
0
  }
1758
0
  int const vers=version();
1759
0
  auto const &shapeIt=m_state->m_posToShapeDataMap.find(shape.m_pos);
1760
0
  bool hasShapeId=shapeIt!=m_state->m_posToShapeDataMap.end();
1761
0
  MWAWPosition pos(shape.m_initialBox[0], shape.m_initialBox.size(), librevenge::RVNG_POINT);
1762
0
  pos.m_anchorTo = MWAWPosition::Page;
1763
0
  LocalState local(pos, lTransform.m_style);
1764
0
  local.m_transform=lTransform.m_transform;
1765
0
  if (hasShapeId && shapeIt->second.m_ids[1]) {
1766
0
    auto const &matIt=m_state->m_idToMatrices.find(int(shapeIt->second.m_ids[1]));
1767
0
    if (matIt==m_state->m_idToMatrices.end()) {
1768
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: can not find the matrix %d\n", int(shapeIt->second.m_ids[1])));
1769
0
    }
1770
0
    else
1771
0
      local.multiplyMatrix(matIt->second[0]);
1772
0
  }
1773
0
  if (shape.m_values[1])
1774
0
    m_styleManager->updateSurfaceColor(shape.m_values[1], local.m_style);
1775
0
  if (shape.m_values[2])
1776
0
    m_styleManager->updateLineColor(shape.m_values[2], local.m_style);
1777
0
  int numLines=1;
1778
0
  if (shape.m_values[3])
1779
0
    m_styleManager->updateLineStyle(shape.m_values[3], local.m_style, numLines);
1780
0
  MWAWGraphicShape finalShape;
1781
0
  switch (shape.m_type) {
1782
0
  case 2: {
1783
0
    if (!hasShapeId || !shapeIt->second.m_stream) {
1784
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[text]: can not find the text zone\n"));
1785
0
      return false;
1786
0
    }
1787
0
    local.m_style.m_lineWidth=0;
1788
0
    std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, shapeIt->second.getStream().input(), shape, shapeIt->second));
1789
0
    MWAWTransformation transf;
1790
0
    float rotation=0;
1791
0
    MWAWVec2f shearing;
1792
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) {
1793
0
      MWAWBox2f box=transf*shape.m_initialBox;
1794
0
      pos.setOrigin(box[0]);
1795
0
      pos.setSize(box[1]-box[0]);
1796
0
      MWAWGraphicStyle style(local.m_style);
1797
0
      style.m_rotate=-rotation;
1798
0
      listener->insertTextBox(pos, doc, style);
1799
0
    }
1800
0
    else
1801
0
      listener->insertTextBox(pos, doc, local.m_style);
1802
0
    return true;
1803
0
  }
1804
0
  case 3: {
1805
0
    auto const &data=shapeIt->second;
1806
0
    if (data.m_vertices.size()==2)
1807
0
      finalShape=MWAWGraphicShape::line(data.m_vertices[0], data.m_vertices[1]);
1808
0
    else
1809
0
      finalShape=MWAWGraphicShape::line(shape.m_initialBox[0], shape.m_initialBox[1]);
1810
0
    break;
1811
0
  }
1812
0
  case 4:
1813
0
    finalShape=MWAWGraphicShape::rectangle(shape.m_initialBox);
1814
0
    break;
1815
0
  case 5:
1816
0
    if (!hasShapeId) {
1817
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[rectOval]: can not find the oval size\n"));
1818
0
      return false;
1819
0
    }
1820
0
    if (vers<9)
1821
0
      finalShape=MWAWGraphicShape::rectangle
1822
0
                 (shape.m_initialBox, 1/65536.f*MWAWVec2f(float(shapeIt->second.m_local[0])/2,float(shapeIt->second.m_local[1])/2));
1823
0
    else
1824
0
      finalShape=MWAWGraphicShape::rectangle
1825
0
                 (shape.m_initialBox, MWAWVec2f(float(shapeIt->second.m_doubleValues[0])/2,float(shapeIt->second.m_doubleValues[1])/2));
1826
0
    break;
1827
0
  case 6:
1828
0
    finalShape=MWAWGraphicShape::circle(shape.m_initialBox);
1829
0
    break;
1830
0
  case 7: { // arc
1831
0
    if (!hasShapeId) {
1832
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[arc]: can not find the angle\n"));
1833
0
      return false;
1834
0
    }
1835
0
    auto const &data=shapeIt->second;
1836
0
    float const angles[]= {vers<9 ? float(data.m_local[0])/65536 : float(180/M_PI *data.m_doubleValues[1]),
1837
0
                           vers<9 ? float(data.m_local[1])/65536 : float(180/ M_PI *data.m_doubleValues[0])
1838
0
                          };
1839
0
    int angle[2] = { int(90-angles[0]-angles[1]), int(90-angles[1]) };
1840
0
    if (angles[0]<0)
1841
0
      std::swap(angle[0],angle[1]);
1842
0
    else if (angles[0]>=360)
1843
0
      angle[0]-=359;
1844
0
    if (angle[1]>360) {
1845
0
      int numLoop=int(angle[1]/360)-1;
1846
0
      angle[0]-=numLoop*360;
1847
0
      angle[1]-=numLoop*360;
1848
0
      while (angle[1] > 360) {
1849
0
        angle[0]-=360;
1850
0
        angle[1]-=360;
1851
0
      }
1852
0
    }
1853
0
    if (angle[0] < -360) {
1854
0
      int numLoop=int(angle[0]/360)+1;
1855
0
      angle[0]-=numLoop*360;
1856
0
      angle[1]-=numLoop*360;
1857
0
      while (angle[0] < -360) {
1858
0
        angle[0]+=360;
1859
0
        angle[1]+=360;
1860
0
      }
1861
0
    }
1862
    // we must compute the real bd box
1863
0
    float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
1864
0
    int limitAngle[2];
1865
0
    for (int i = 0; i < 2; ++i)
1866
0
      limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
1867
0
    for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) {
1868
0
      float ang = (bord == limitAngle[0]) ? float(angle[0]) :
1869
0
                  (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord);
1870
0
      ang *= float(M_PI/180.);
1871
0
      float const actVal[2] = { std::cos(ang), -std::sin(ang)};
1872
0
      if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
1873
0
      else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
1874
0
      if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
1875
0
      else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
1876
0
    }
1877
0
    MWAWBox2f circleBox=shape.m_initialBox;
1878
    // we have the shape box, we need to reconstruct the circle box
1879
0
    if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) {
1880
0
      float const scaling[2]= { (shape.m_initialBox[1][0]-shape.m_initialBox[0][0])/(maxVal[0]-minVal[0]),
1881
0
                                (shape.m_initialBox[1][1]-shape.m_initialBox[0][1])/(maxVal[1]-minVal[1])
1882
0
                              };
1883
0
      float const constant[2]= { shape.m_initialBox[0][0]-minVal[0] *scaling[0], shape.m_initialBox[0][1]-minVal[1] *scaling[1]};
1884
0
      circleBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]),
1885
0
                          MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1]));
1886
0
    }
1887
0
    finalShape = MWAWGraphicShape::pie(shape.m_initialBox, circleBox, MWAWVec2f(float(angle[0]), float(angle[1])));
1888
0
    break;
1889
0
  }
1890
0
  case 9: { // polyline
1891
0
    if (!hasShapeId || shapeIt->second.m_vertices.size()<2) {
1892
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[spline]: can not find the point\n"));
1893
0
      return false;
1894
0
    }
1895
0
    if (local.m_style.hasSurface())
1896
0
      finalShape=MWAWGraphicShape::polygon(shape.m_initialBox);
1897
0
    else
1898
0
      finalShape=MWAWGraphicShape::polyline(shape.m_initialBox);
1899
0
    finalShape.m_vertices=shapeIt->second.m_vertices;
1900
0
    break;
1901
0
  }
1902
0
  case 10: { // spline
1903
0
    if (!hasShapeId || shapeIt->second.m_vertices.size()<2 || (shapeIt->second.m_vertices.size()%4)!=0) {
1904
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[spline]: can not find the point\n"));
1905
0
      return false;
1906
0
    }
1907
0
    finalShape=MWAWGraphicShape::path(shape.m_initialBox);
1908
0
    std::vector<MWAWGraphicShape::PathData> &path=finalShape.m_path;
1909
0
    path.push_back(MWAWGraphicShape::PathData('M', shapeIt->second.m_vertices[0]));
1910
0
    for (size_t p=3; p < shapeIt->second.m_vertices.size(); p+=4) {
1911
0
      if (p>=4 && shapeIt->second.m_vertices[p-4]!=shapeIt->second.m_vertices[p-3])
1912
0
        path.push_back(MWAWGraphicShape::PathData('M', shapeIt->second.m_vertices[p-3]));
1913
0
      bool hasFirstC=shapeIt->second.m_vertices[p-3]!=shapeIt->second.m_vertices[p-2];
1914
0
      bool hasSecondC=shapeIt->second.m_vertices[p-1]!=shapeIt->second.m_vertices[p];
1915
0
      if (!hasFirstC && !hasSecondC)
1916
0
        path.push_back(MWAWGraphicShape::PathData('L', shapeIt->second.m_vertices[p]));
1917
0
      else
1918
0
        path.push_back(MWAWGraphicShape::PathData('C', shapeIt->second.m_vertices[p], shapeIt->second.m_vertices[p-2], shapeIt->second.m_vertices[p-1]));
1919
0
    }
1920
0
    if (local.m_style.hasSurface())
1921
0
      path.push_back(MWAWGraphicShape::PathData('Z'));
1922
0
    break;
1923
0
  }
1924
0
  case 52:
1925
0
    if (!hasShapeId) {
1926
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[special]: can not find the special data\n"));
1927
0
      return false;
1928
0
    }
1929
0
    if (numLines!=1) {
1930
      // even if this is possible, using mutiple line on special give really weird results
1931
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[special]: find a special with multi lines\n"));
1932
0
      m_styleManager->updateLineStyle(shape.m_values[3], local.m_style, numLines, 0);
1933
0
    }
1934
0
    return sendSpecial(listener, shape, shapeIt->second, local);
1935
0
  case 20:
1936
0
  case 99:
1937
0
    if (!hasShapeId) {
1938
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[group]: can not find the child shape\n"));
1939
0
      return false;
1940
0
    }
1941
0
    if (shapeIt->second.m_children.empty())
1942
0
      return true;
1943
0
    if (shape.m_type==99)
1944
0
      local.m_style=MWAWGraphicStyle::emptyStyle();
1945
0
    listener->openGroup(pos);
1946
0
    for (auto cId : shapeIt->second.m_children)
1947
0
      sendShape(int(cId), local);
1948
0
    listener->closeGroup();
1949
0
    return true;
1950
0
  default:
1951
0
    static bool first=true;
1952
0
    if (first) {
1953
0
      MWAW_DEBUG_MSG(("Canvas5Graph::send[shape]: sorry, not implemented[%d]\n", shape.m_type));
1954
0
      first=false;
1955
0
    }
1956
0
    return false;
1957
0
  }
1958
0
  if (!local.m_transform.isIdentity()) {
1959
0
    finalShape=finalShape.transform(local.m_transform);
1960
0
    MWAWBox2f shapeBox=finalShape.getBdBox();
1961
0
    pos=MWAWPosition(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
1962
0
    pos.m_anchorTo = MWAWPosition::Page;
1963
0
  }
1964
0
  if (shape.m_values[3]==0 || numLines==1) {
1965
0
    listener->insertShape(pos, finalShape, local.m_style);
1966
0
    return true;
1967
0
  }
1968
0
  listener->openGroup(pos);
1969
0
  auto style=local.m_style;
1970
0
  style.m_lineWidth=0;
1971
0
  listener->insertShape(pos, finalShape, style);
1972
0
  style=MWAWGraphicStyle::emptyStyle();
1973
0
  if (shape.m_values[2])
1974
0
    m_styleManager->updateLineColor(shape.m_values[2], style);
1975
0
  auto path=finalShape.getPath(true);
1976
0
  for (int l=0; l<numLines; ++l) {
1977
0
    float offset;
1978
0
    m_styleManager->updateLineStyle(shape.m_values[3], style, numLines, l, &offset);
1979
0
    MWAWBox2f decalBox;
1980
0
    auto decalPath=MWAWGraphicShape::offsetVertices(path, offset, decalBox);
1981
0
    auto decalShape=MWAWGraphicShape::path(decalBox);
1982
0
    decalShape.m_path=decalPath;
1983
0
    pos=MWAWPosition(decalBox[0], decalBox.size(), librevenge::RVNG_POINT);
1984
0
    pos.m_anchorTo = MWAWPosition::Page;
1985
0
    listener->insertShape(pos, decalShape, style);
1986
0
  }
1987
0
  listener->closeGroup();
1988
0
  return true;
1989
0
}
1990
1991
bool Canvas5Graph::sendSpecial(MWAWListenerPtr listener, Canvas5GraphInternal::PseudoShape const &pseudoShape, LocalState const &local)
1992
0
{
1993
0
  return sendSpecial(listener, pseudoShape.m_shape, pseudoShape.m_data, local);
1994
0
}
1995
1996
bool Canvas5Graph::sendSpecial(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape, Canvas5GraphInternal::ShapeData const &data,
1997
                               Canvas5Graph::LocalState const &local)
1998
0
{
1999
0
  if (!data.m_stream)
2000
0
    return false;
2001
0
  if (!listener) {
2002
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: can not find the listener\n"));
2003
0
    return false;
2004
0
  }
2005
0
  int const vers=version();
2006
0
  auto &stream=data.getStream();
2007
0
  MWAWGraphicShape fShape;
2008
0
  auto const &box=shape.m_initialBox;
2009
0
  switch (data.m_type) {
2010
0
  case 0x43436972: { // CCir
2011
0
    if (data.m_specials[0]<=0 || data.m_specials[0]>20) {
2012
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of circles seems bad\n"));
2013
0
      return false;
2014
0
    }
2015
0
    listener->openGroup(local.m_position);
2016
0
    MWAWVec2f center=0.5f*(box[0]+box[1]);
2017
0
    MWAWVec2f diag=0.5f*box.size();
2018
0
    for (int i=0; i<data.m_specials[0]; ++i) {
2019
0
      MWAWVec2f newDiag;
2020
0
      if (data.m_specials[1]<=0)
2021
0
        newDiag=float(data.m_specials[0]-i)/float(data.m_specials[0])*diag;
2022
0
      else {
2023
0
        newDiag=diag-float(data.m_specials[1]*i)*MWAWVec2f(1,1);
2024
0
        for (int c=0; c<2; ++c) {
2025
0
          if (newDiag[c]<0)
2026
0
            newDiag[c]=0;
2027
0
        }
2028
0
      }
2029
0
      fShape=MWAWGraphicShape::circle(MWAWBox2f(center-newDiag, center+newDiag));
2030
0
      send(listener, fShape, local.m_transform, local.m_style);
2031
0
    }
2032
0
    listener->closeGroup();
2033
0
    break;
2034
0
  }
2035
0
  case 0x43756265: { // Cube
2036
0
    if (data.m_vertices.size()!=8) {
2037
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: can not find the cube vertices\n"));
2038
0
      return false;
2039
0
    }
2040
0
    int const faces[]= {
2041
0
      0, 2, 6, 4, // X==0
2042
0
      1, 3, 7, 5, // X==1
2043
0
      0, 1, 5, 4, // Y==0
2044
0
      2, 3, 7, 6, // Y==1
2045
0
      0, 1, 3, 2, // Z==0
2046
0
      4, 5, 7, 6, // Z==1
2047
0
    };
2048
0
    listener->openGroup(local.m_position);
2049
0
    fShape.m_type=local.m_style.hasSurface() ? MWAWGraphicShape::Polygon : MWAWGraphicShape::Polyline;
2050
0
    MWAWVec2f const dir=box[1]-box[0];
2051
0
    MWAWVec2f const dirs[]= {data.m_vertices[1]-data.m_vertices[0],
2052
0
                             data.m_vertices[2]-data.m_vertices[0],
2053
0
                             data.m_vertices[4]-data.m_vertices[0]
2054
0
                            };
2055
0
    int wh=(dirs[0][0]*dirs[2][1]-dirs[0][1]*dirs[2][0]>0) ? 0 : 1;
2056
0
    wh+=(dirs[1][0]*dirs[2][1]-dirs[1][1]*dirs[2][0]>0) ? 0 : 2;
2057
0
    if (dirs[0][0]*dirs[1][1]-dirs[0][1]*dirs[1][0]>0 && (wh==0 || wh==3)) wh=3-wh;
2058
2059
0
    for (int f=0; f<3; ++f) {
2060
0
      size_t face;
2061
0
      switch (f) {
2062
0
      case 0:
2063
0
        face=4;
2064
0
        break;
2065
0
      case 1:
2066
0
        face = (wh==0 || wh==1) ? 2 : 3;
2067
0
        break;
2068
0
      default:
2069
0
        face = (wh==0 || wh==2) ? 1 : 0;
2070
0
        break;
2071
0
      }
2072
2073
0
      MWAWBox2f shapeBox;
2074
0
      fShape.m_vertices.resize(4);
2075
0
      for (size_t p=0; p<4; ++p) {
2076
0
        MWAWVec2f const &pt=data.m_vertices[size_t(faces[4*face+p])];
2077
0
        fShape.m_vertices[p]=box[0]+MWAWVec2f(pt[0]*dir[0], pt[1]*dir[1]);
2078
0
      }
2079
0
      fShape.m_bdBox=shapeBox;
2080
0
      send(listener, fShape, local.m_transform, local.m_style);
2081
0
    }
2082
0
    listener->closeGroup();
2083
0
    break;
2084
0
  }
2085
0
  case 0x43765465: // CvTe
2086
0
    return sendCurveText(listener, shape, data, local);
2087
0
  case 0x44494d4e: // DIMN
2088
0
    if (vers<9)
2089
0
      return sendDimension(listener, shape, data, local);
2090
0
    return sendDimension9(listener, shape, data, local);
2091
0
  case 0x65666665: // eff
2092
0
    return sendEffect(listener, shape, data, local);
2093
0
  case 0x45787472: // Extr: extrude
2094
0
    return sendExtrude(listener, shape, data, local);
2095
0
  case 0x4772644d: { // GrdL
2096
0
    listener->openGroup(local.m_position);
2097
0
    if (data.m_grid[0]<=0 || data.m_grid[1]<=0 ||
2098
0
        data.m_grid[0]>100 || data.m_grid[1]>100) {
2099
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial[grid]: can not find the number of rows/columns\n"));
2100
0
      return false;
2101
0
    }
2102
0
    MWAWVec2f dim((box[1][0]-box[0][0])/float(data.m_grid[0]),
2103
0
                  (box[1][1]-box[0][1])/float(data.m_grid[1]));
2104
0
    for (int i=0; i<=data.m_grid[0]; ++i) {
2105
0
      float X=box[0][0]+float(i)*dim[0];
2106
0
      fShape=MWAWGraphicShape::line(MWAWVec2f(X,box[0][1]), MWAWVec2f(X,box[1][1]));
2107
0
      send(listener, fShape, local.m_transform, local.m_style);
2108
0
    }
2109
0
    for (int j=0; j<=data.m_grid[1]; ++j) {
2110
0
      float Y=box[0][1]+float(j)*dim[1];
2111
0
      fShape=MWAWGraphicShape::line(MWAWVec2f(box[0][0],Y), MWAWVec2f(box[1][0],Y));
2112
0
      send(listener, fShape, local.m_transform, local.m_style);
2113
0
    }
2114
0
    listener->closeGroup();
2115
0
    break;
2116
0
  }
2117
0
  case 0x4e474f4e: { // NGON
2118
0
    if (data.m_specials[0]<=2 || data.m_specials[0]>=50) { // find N=33
2119
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of ngon seems bad\n"));
2120
0
      return false;
2121
0
    }
2122
0
    int type=data.m_ngonType;
2123
0
    if (type<0 || type>5) {
2124
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the ngon's seems bad, assume 4\n"));
2125
0
      type=4;
2126
0
    }
2127
0
    bool needGroup=type!=0 && type!=3 && type!=4;
2128
0
    if (needGroup)
2129
0
      listener->openGroup(local.m_position);
2130
0
    MWAWVec2f const center=0.5f*(box[0]+box[1]);
2131
0
    MWAWVec2f const diag=0.5f*box.size();
2132
0
    double const angles[]= {M_PI/2-data.m_doubleValues[2], M_PI/2-M_PI/data.m_specials[0]};
2133
0
    double const step=-2*M_PI/data.m_specials[0];
2134
0
    float const rad=float(data.m_doubleValues[0]);
2135
0
    if (type==0 || type==1 || type==5) { // border
2136
0
      fShape=MWAWGraphicShape::polygon(box);
2137
0
      for (int i=0; i<data.m_specials[0]; ++i) {
2138
0
        float const angle1=float(angles[0]+i *step);
2139
0
        fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1]));
2140
0
      }
2141
0
      send(listener, fShape, local.m_transform, local.m_style);
2142
0
    }
2143
0
    if (type==1 || type==4) { // outside star
2144
0
      fShape=MWAWGraphicShape::polygon(box);
2145
0
      for (int i=0; i<data.m_specials[0]; ++i) {
2146
0
        float const angle1=float(angles[0]+i *step);
2147
0
        fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1]));
2148
0
        float const angle2=float(angles[1]+i *step);
2149
0
        fShape.m_vertices.push_back(center+MWAWVec2f(rad *std::cos(angle2)*diag[0], -rad *std::sin(angle2)*diag[1]));
2150
0
      }
2151
0
      send(listener, fShape, local.m_transform, local.m_style);
2152
0
    }
2153
0
    if (type==3) { // inside star
2154
0
      fShape=MWAWGraphicShape::polygon(box);
2155
0
      int id=0;
2156
0
      for (int i=0; i<data.m_specials[0]; ++i) {
2157
0
        float const angle1=float(angles[0]+id *step);
2158
0
        fShape.m_vertices.push_back(center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1]));
2159
0
        id+=(data.m_specials[0]-1+i%2)/2;
2160
0
      }
2161
0
      send(listener, fShape, local.m_transform, local.m_style);
2162
0
    }
2163
0
    if (type==2 || type==5) { // list of segment: center->outside points
2164
0
      for (int i=0; i<data.m_specials[0]; ++i) {
2165
0
        float const angle1=float(angles[0]+i *step);
2166
0
        fShape=MWAWGraphicShape::line(center, center+MWAWVec2f(std::cos(angle1)*diag[0], -std::sin(angle1)*diag[1]));
2167
0
        send(listener, fShape, local.m_transform, local.m_style);
2168
0
      }
2169
0
    }
2170
0
    if (needGroup)
2171
0
      listener->closeGroup();
2172
0
    break;
2173
0
  }
2174
0
  case 0x4f4c6e6b : { // OLnk
2175
0
    if (data.m_vertices.size()<2) {
2176
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, can not find the link extremities\n"));
2177
0
      return false;
2178
0
    }
2179
0
    fShape=MWAWGraphicShape::line(data.m_vertices[0], data.m_vertices[1]);
2180
0
    send(listener, fShape, local.m_transform, local.m_style);
2181
0
    break;
2182
0
  }
2183
0
  case 0x4d41434f: { // MACO
2184
0
    auto sIt=m_state->m_sendMACOIdSet.find(data.m_macoId);
2185
0
    if (sIt!=m_state->m_sendMACOIdSet.end()) {
2186
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry find a loop sending MACO\n"));
2187
0
      break;
2188
0
    }
2189
0
    auto maco=m_imageParser->getMACO(data.m_macoId);
2190
0
    if (!maco)
2191
0
      break;
2192
2193
0
    m_state->m_sendMACOIdSet.insert(data.m_macoId);
2194
0
    listener->openGroup(local.m_position);
2195
0
    m_imageParser->send(maco, listener, shape.m_initialBox, local.m_transform);
2196
0
    listener->closeGroup();
2197
0
    m_state->m_sendMACOIdSet.erase(data.m_macoId);
2198
0
    break;
2199
0
  }
2200
0
  case 0x706f626a: { // pobj
2201
0
    MWAWEmbeddedObject bitmap;
2202
0
    if (!m_imageParser->getBitmap(data.m_specials[1], bitmap))
2203
0
      return false;
2204
0
    MWAWTransformation transf;
2205
0
    float rotation=0;
2206
0
    MWAWVec2f shearing;
2207
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) {
2208
0
      MWAWBox2f shapeBox=transf*shape.m_initialBox;
2209
0
      MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
2210
0
      pos.m_anchorTo = MWAWPosition::Page;
2211
0
      MWAWGraphicStyle style(local.m_style);
2212
0
      style.m_rotate=-rotation;
2213
0
      listener->insertPicture(pos, bitmap, style);
2214
0
    }
2215
0
    else
2216
0
      listener->insertPicture(local.m_position, bitmap, local.m_style);
2217
0
    break;
2218
0
  }
2219
0
  case 0x53504952: { // SPIR
2220
0
    if (data.m_specials[0]<=0) {
2221
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, the number of spirals seems bad\n"));
2222
0
      return false;
2223
0
    }
2224
0
    fShape=MWAWGraphicShape::path(box);
2225
0
    auto const center = box.center();
2226
0
    auto const dir = 0.5f/4/float(data.m_specials[0]) * box.size();
2227
0
    std::vector<MWAWGraphicShape::PathData> &path=fShape.m_path;
2228
0
    auto pt=center;
2229
0
    path.push_back(MWAWGraphicShape::PathData('M', center));
2230
0
    for (int i=1; i<=4*data.m_specials[0]; ++i) {
2231
0
      auto nextPt=center;
2232
0
      nextPt[(i&1)] += ((i%4)<2 ? 1 : -1)*float(i)*dir[(i&1)];
2233
0
      MWAWVec2f l;
2234
0
      l[1-(i&1)]=pt[1-(i&1)];
2235
0
      l[(i&1)]=nextPt[(i&1)];
2236
0
      path.push_back(MWAWGraphicShape::PathData('Q', nextPt, l));
2237
0
      pt=nextPt;
2238
0
    }
2239
0
    send(listener, fShape, local.m_transform, local.m_style);
2240
0
    break;
2241
0
  }
2242
0
  case 0x43574542: { // CWEB: ie a button with 3 state
2243
0
    auto input=stream.input();
2244
0
    bool isSent=false;
2245
0
    for (auto const &e : data.m_cweb) {
2246
0
      if (!e.valid()) continue;
2247
0
      input->seek(e.begin(), librevenge::RVNG_SEEK_SET);
2248
0
      input->pushLimit(e.end());
2249
0
      bool ok=true;
2250
0
      std::shared_ptr<Canvas5ImageInternal::VKFLImage> image;
2251
0
      if (!m_imageParser->readVKFL(data.m_stream, e.length(), image)) {
2252
0
        auto &ascFile=stream.ascii();
2253
0
        ok=false;
2254
0
        ascFile.addPos(e.begin());
2255
0
        ascFile.addNote("DataShap:special,image:###");
2256
0
      }
2257
0
      else if (!isSent) {
2258
0
        isSent=true;
2259
0
        listener->openGroup(local.m_position);
2260
0
        m_imageParser->send(image, listener, shape.m_initialBox, local.m_transform);
2261
0
        listener->closeGroup();
2262
0
        static bool first=true;
2263
0
        if (first) {
2264
0
          MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecialData[button]: send only the first picture (instead of the three state pictures)\n"));
2265
0
          first=false;
2266
0
        }
2267
0
      }
2268
0
      input->popLimit();
2269
0
      if (!ok)
2270
0
        continue;
2271
0
#ifndef DEBUG
2272
0
      break;
2273
0
#endif
2274
0
    }
2275
0
    break;
2276
0
  }
2277
0
  case 0x54585420: { // TXT : only in Vkfl
2278
0
    if (data.m_inMainZone) {
2279
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecialData: unexpected text in main zone\n"));
2280
0
      return false;
2281
0
    }
2282
0
    auto lStyle=local.m_style;
2283
0
    lStyle.m_lineWidth=0;
2284
0
    std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, stream.input(), shape, data));
2285
0
    MWAWTransformation transf;
2286
0
    float rotation=0;
2287
0
    MWAWVec2f shearing;
2288
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) {
2289
0
      MWAWBox2f shapeBox=transf*shape.m_initialBox;
2290
0
      MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
2291
0
      pos.m_anchorTo = MWAWPosition::Page;
2292
0
      lStyle.m_rotate=-rotation;
2293
0
      listener->insertTextBox(pos, doc, lStyle);
2294
0
    }
2295
0
    else
2296
0
      listener->insertTextBox(local.m_position, doc, lStyle);
2297
0
    break;
2298
0
  }
2299
0
  case 0x41474946: { // AGIF appear in v6
2300
0
    auto sIt=m_state->m_sendAGIFIdSet.find(data.m_specials[1]);
2301
0
    if (sIt!=m_state->m_sendAGIFIdSet.end()) {
2302
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry find a loop sending AGIF\n"));
2303
0
      break;
2304
0
    }
2305
0
    auto gif=m_imageParser->getGIF(data.m_specials[1]);
2306
0
    if (!gif)
2307
0
      break;
2308
2309
0
    m_state->m_sendAGIFIdSet.insert(data.m_specials[1]);
2310
0
    listener->openGroup(local.m_position);
2311
0
    m_imageParser->send(gif, listener, shape.m_initialBox, local.m_transform);
2312
0
    listener->closeGroup();
2313
0
    m_state->m_sendAGIFIdSet.erase(data.m_specials[1]);
2314
0
    break;
2315
0
  }
2316
0
  case 0x516b546d: { // QkTm
2317
0
    MWAWEmbeddedObject movie;
2318
0
    if (!m_imageParser->getQuickTime(data.m_specials[0], movie))
2319
0
      return false;
2320
0
    static bool first=true;
2321
0
    if (first) {
2322
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial[QkTm]: this file contains movie, there will be probably illisible\n"));
2323
0
      first=false;
2324
0
    }
2325
0
    MWAWTransformation transf;
2326
0
    float rotation=0;
2327
0
    MWAWVec2f shearing;
2328
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) {
2329
0
      MWAWBox2f shapeBox=transf*shape.m_initialBox;
2330
0
      MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
2331
0
      pos.m_anchorTo = MWAWPosition::Page;
2332
0
      MWAWGraphicStyle style(local.m_style);
2333
0
      style.m_rotate=-rotation;
2334
0
      listener->insertPicture(pos, movie, style);
2335
0
    }
2336
0
    else
2337
0
      listener->insertPicture(local.m_position, movie, local.m_style);
2338
0
    break;
2339
0
  }
2340
0
  case 0x23476465: { // #Gde: appear in v6
2341
0
    if (data.m_gdeType!=3)
2342
0
      return true;
2343
0
    for (auto const &sect : data.m_sections) {
2344
      // add only a basic frame, todo: add also a frame to separate column
2345
0
      fShape=MWAWGraphicShape::rectangle(sect.m_bdBox);
2346
0
      MWAWGraphicStyle basicStyle;
2347
0
      basicStyle.m_lineColor=MWAWColor(127,127,255);
2348
0
      basicStyle.m_lineWidth=0.5f;
2349
0
      send(listener, fShape, local.m_transform, basicStyle);
2350
0
    }
2351
0
    break;
2352
0
  }
2353
0
  case 0x416e4766: // AnGf: appear in v7
2354
0
    return sendGIF(listener, shape, data, local);
2355
0
  case 0x54656368: // Tech: appear in v7
2356
0
    return sendTechnical(listener, shape, data, local);
2357
0
  case 0x494d534c: { // SIML: a slice mask?, appear in v8
2358
0
    fShape=MWAWGraphicShape::rectangle(shape.m_initialBox);
2359
0
    MWAWGraphicStyle basicStyle;
2360
0
    basicStyle.m_lineColor=MWAWColor(250,128,114);
2361
0
    basicStyle.m_lineWidth=0.5f;
2362
0
    basicStyle.setSurfaceColor(MWAWColor(255,255,0),0.5);
2363
0
    send(listener, fShape, local.m_transform, basicStyle);
2364
0
    break;
2365
0
  }
2366
0
  case 0x72656750: { // regP: appear in v8
2367
0
    listener->openGroup(local.m_position);
2368
0
    MWAWBox2f const &shapeBox=shape.m_initialBox;
2369
0
    auto const center=shapeBox.center();
2370
0
    MWAWGraphicStyle basicStyle;
2371
0
    for (int i=0; i<3; ++i) {
2372
0
      switch (i) {
2373
0
      case 0: {
2374
0
        MWAWBox2f cBox=shapeBox;
2375
0
        cBox.resizeFromCenter(0.5f*shapeBox.size());
2376
0
        fShape=MWAWGraphicShape::circle(cBox);
2377
0
        break;
2378
0
      }
2379
0
      case 1:
2380
0
        fShape=MWAWGraphicShape::line(MWAWVec2f(shapeBox[0][0],center[1]), MWAWVec2f(shapeBox[1][0],center[1]));
2381
0
        break;
2382
0
      case 2:
2383
0
      default:
2384
0
        fShape=MWAWGraphicShape::line(MWAWVec2f(center[0],shapeBox[0][1]), MWAWVec2f(center[0],shapeBox[1][1]));
2385
0
        break;
2386
0
      }
2387
0
      send(listener, fShape, local.m_transform, basicStyle);
2388
0
    }
2389
0
    listener->closeGroup();
2390
0
    break;
2391
0
  }
2392
0
  default:
2393
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendSpecial: sorry, sending %s is not implemented\n", Canvas5Structure::getString(data.m_type).c_str()));
2394
0
    return false;
2395
0
  }
2396
0
  return true;
2397
0
}
2398
2399
bool Canvas5Graph::sendText(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/, Canvas5GraphInternal::ShapeData const &data)
2400
0
{
2401
0
  if (!data.m_stream)
2402
0
    return false;
2403
2404
0
  if (!listener) {
2405
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the listener\n"));
2406
0
    return false;
2407
0
  }
2408
0
  auto &stream=data.getStream();
2409
0
  int const vers=version();
2410
0
  libmwaw::DebugStream f;
2411
0
  libmwaw::DebugFile &ascFile = stream.ascii();
2412
0
  auto input=stream.input();
2413
0
  auto entry=data.m_entry;
2414
0
  MWAWEntry fontEntry;
2415
0
  if (!data.m_inMainZone) {
2416
0
    if (!entry.valid() || entry.length()<16 || !input->checkPosition(entry.end())) {
2417
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the text entry\n"));
2418
0
      return false;
2419
0
    }
2420
2421
0
    input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2422
0
    long pos=input->tell();
2423
0
    f << "Text[zones]:";
2424
0
    MWAWEntry childs[2];
2425
0
    for (auto &c : childs) {
2426
0
      c.setBegin(entry.begin()+input->readLong(4));
2427
0
      c.setLength(input->readLong(4));
2428
0
      if (c.begin()<entry.begin() || c.end()>entry.end()) {
2429
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the main child entry\n"));
2430
0
        f << "###";
2431
0
        ascFile.addPos(pos);
2432
0
        ascFile.addNote(f.str().c_str());
2433
0
        return false;
2434
0
      }
2435
0
      f << std::hex << c.begin() << "<->" << c.end() << ",";
2436
0
    }
2437
0
    ascFile.addPos(pos);
2438
0
    ascFile.addNote(f.str().c_str());
2439
0
    entry=childs[0];
2440
0
    fontEntry=childs[1];
2441
0
    ascFile.addPos(fontEntry.begin());
2442
0
    ascFile.addNote("Text[fonts]:");
2443
0
  }
2444
0
  if (!entry.valid() || entry.length()<20+5*4 || !input->checkPosition(entry.end())) {
2445
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not find the text entry\n"));
2446
0
    return false;
2447
0
  }
2448
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2449
2450
0
  long pos=input->tell();
2451
0
  f.str("");
2452
0
  f << "Entries(Text):";
2453
0
  int val;
2454
0
  for (int i=0; i<7; ++i) {
2455
0
    val=int(input->readLong(2));
2456
0
    int const expected[]= {1,0,0xc,0,0,0,1};
2457
0
    if (val!=expected[i])
2458
0
      f << "f" << i << "=" << val << ",";
2459
0
  }
2460
0
  val=int(input->readULong(2));
2461
0
  if (val!=0x7071) f << "fl=" << std::hex << val << std::dec << ",";
2462
0
  val=int(input->readLong(2));
2463
0
  MWAWParagraph para;
2464
0
  switch (val) {
2465
0
  case -1:
2466
0
    para.m_justify=MWAWParagraph::JustificationRight;
2467
0
    f << "right,";
2468
0
    break;
2469
0
  case 0: // left
2470
0
    break;
2471
0
  case 1:
2472
0
    para.m_justify=MWAWParagraph::JustificationCenter;
2473
0
    f << "center,";
2474
0
    break;
2475
0
  case 4:
2476
0
    para.m_justify=MWAWParagraph::JustificationFull;
2477
0
    f << "justify,";
2478
0
    break;
2479
0
  default:
2480
0
    f << "#align=" << val << ",";
2481
0
  }
2482
0
  val=int(input->readLong(2));
2483
0
  if (val) f << "f7=" << val << ",";
2484
0
  unsigned long lengths[5], totalLength=0;
2485
0
  f << "len=[";
2486
0
  for (auto &l : lengths) {
2487
0
    l=input->readULong(4);
2488
0
    if (totalLength+l<totalLength) {
2489
0
      f << "###";
2490
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendText: bad lengths\n"));
2491
0
      ascFile.addPos(pos);
2492
0
      ascFile.addNote(f.str().c_str());
2493
0
      return false;
2494
0
    }
2495
0
    totalLength+=l;
2496
0
    if (l)
2497
0
      f << l << ",";
2498
0
    else
2499
0
      f << "_,";
2500
0
  }
2501
0
  f << "],";
2502
0
  if (pos+24+5*4+long(totalLength)<pos+24+20 || pos+24+5*4+long(totalLength)>=entry.end()) {
2503
0
    f << "###";
2504
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: bad lengths\n"));
2505
0
    ascFile.addPos(pos);
2506
0
    ascFile.addNote(f.str().c_str());
2507
0
    return false;
2508
0
  }
2509
0
  ascFile.addPos(pos);
2510
0
  ascFile.addNote(f.str().c_str());
2511
2512
0
  pos=input->tell();
2513
0
  MWAWEntry textEntry;
2514
0
  textEntry.setBegin(pos);
2515
0
  textEntry.setLength(int(lengths[0]));
2516
0
  input->seek((lengths[0]&1) ? long(lengths[0])+1 : long(lengths[0]), librevenge::RVNG_SEEK_CUR);
2517
2518
0
  if (lengths[1]) {
2519
0
    ascFile.addPos(input->tell());
2520
0
    ascFile.addNote("Text-Unkn:");
2521
0
    input->seek(long(lengths[1]), librevenge::RVNG_SEEK_CUR);
2522
0
  }
2523
0
  bool ok=true;
2524
0
  if (lengths[2]<8) {
2525
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 2 seems too short\n"));
2526
0
    ok=false;
2527
0
  }
2528
2529
0
  std::map<int, int> posToFontIdMap;
2530
0
  if (ok) {
2531
0
    pos=input->tell();
2532
0
    f.str("");
2533
0
    f << "Text-plc:";
2534
0
    int N0=int(input->readLong(2));
2535
0
    if (N0!=1) f << "f0=" << N0 << ",";
2536
0
    int N=int(input->readULong(2));
2537
0
    f << "numPLC=" << N << ",";
2538
0
    if (int(lengths[2])<20+N0*8) {
2539
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 2 seems bad\n"));
2540
0
      f << "###";
2541
0
    }
2542
0
    else {
2543
0
      for (int i=0; i<8; ++i) { // 0
2544
0
        val=int(input->readLong(2));
2545
0
        if (val) f << "f" << i << "=" << val << ",";
2546
0
      }
2547
0
      f << "plcs=[";
2548
0
      for (int i=0; i<N0; ++i) {
2549
0
        int posi=int(input->readULong(4));
2550
0
        int id=int(input->readULong(2));
2551
0
        val=int(input->readLong(2)); // almost always 0, but find 4447|a0 ?
2552
0
        f << posi << ":" << id;
2553
0
        if (val) f << "[" << val << "]";
2554
0
        f << ",";
2555
0
        posToFontIdMap[posi]=id;
2556
0
      }
2557
0
      f << input->readULong(4);
2558
0
      f << "],";
2559
0
    }
2560
0
    ascFile.addDelimiter(input->tell(),'|');
2561
0
    ascFile.addPos(pos);
2562
0
    ascFile.addNote(f.str().c_str());
2563
0
    input->seek(pos+long(lengths[2]), librevenge::RVNG_SEEK_SET);
2564
0
  }
2565
2566
0
  int const styleSz=vers<9 ? 60 : 96;
2567
0
  if (ok && (int(lengths[4])%styleSz)!=0) {
2568
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 4 seems bads\n"));
2569
0
    ok=false;
2570
0
  }
2571
2572
0
  Canvas5StyleManager::StyleList styles;
2573
0
  if (ok) {
2574
0
    int N=int(lengths[4])/styleSz;
2575
0
    styles.m_fonts.resize(size_t(N));
2576
0
    for (int n=0; n<N; ++n) {
2577
0
      pos=input->tell();
2578
0
      m_styleManager->readCharStyle(stream, n, styles.m_fonts[size_t(n)], data.m_inMainZone);
2579
0
      input->seek(pos+styleSz, librevenge::RVNG_SEEK_SET);
2580
0
    }
2581
0
  }
2582
2583
0
  if (ok && (lengths[3]%16)) {
2584
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendText: length 3 seems bads\n"));
2585
0
    ok=false;
2586
0
  }
2587
2588
0
  if (ok) {
2589
0
    int N=int(lengths[3]/16);
2590
0
    for (int n=0; n<N; ++n) {
2591
      // unsure maybe
2592
      // before v9 n*[2 double:int4 + 32 bytes]
2593
      // in v9 n*[2 double + 32 bytes] + n*[2 int]
2594
0
      pos=input->tell();
2595
0
      f.str("");
2596
0
      f << "Text-A" << n << ":";
2597
0
      ascFile.addPos(pos);
2598
0
      ascFile.addNote(f.str().c_str());
2599
0
      input->seek(pos+16, librevenge::RVNG_SEEK_SET);
2600
0
    }
2601
2602
0
    pos=input->tell();
2603
0
    if (!readDeR3(data.m_stream, styles)) {
2604
0
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2605
0
      ok=false;
2606
0
    }
2607
0
  }
2608
2609
0
  pos=input->tell();
2610
0
  input->seek(textEntry.begin(), librevenge::RVNG_SEEK_SET);
2611
0
  f.str("");
2612
0
  f << "Text-text:";
2613
0
  listener->setParagraph(para);
2614
2615
0
  int linkId=0;
2616
0
  bool linkIsOpen=false;
2617
0
  for (int n=0; n<int(lengths[0]); ++n) {
2618
0
    auto it=posToFontIdMap.find(n);
2619
0
    if (it!=posToFontIdMap.end()) {
2620
0
      if (it->second<0 || it->second>=int(styles.m_fonts.size())) {
2621
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendText: can not read find the font=%d\n", it->second));
2622
0
      }
2623
0
      else {
2624
0
        auto const &font=styles.m_fonts[size_t(it->second)];
2625
0
        if (font.m_paragraphId>0 && size_t(font.m_paragraphId)<styles.m_paragraphs.size())
2626
0
          listener->setParagraph(styles.m_paragraphs[size_t(font.m_paragraphId)].first);
2627
0
        listener->setFont(font.m_font);
2628
0
        if (font.m_linkId!=linkId) {
2629
0
          if (linkIsOpen) {
2630
0
            listener->closeLink();
2631
0
            linkIsOpen=false;
2632
0
          }
2633
0
          linkId=font.m_linkId;
2634
0
          if (linkId) {
2635
0
            auto ref=m_mainParser->getTextLink(linkId);
2636
0
            if (!ref.empty()) {
2637
0
              MWAWLink link;
2638
0
              link.m_HRef=ref.cstr();
2639
0
              listener->openLink(link);
2640
0
              linkIsOpen=true;
2641
0
            }
2642
0
          }
2643
0
        }
2644
0
      }
2645
0
    }
2646
0
    unsigned char c=(unsigned char)(input->readULong(1));
2647
0
    f << c;
2648
0
    switch (c) {
2649
0
    case 0x9:
2650
0
      listener->insertTab();
2651
0
      break;
2652
0
    case 0xd:
2653
0
      if (linkIsOpen) {
2654
0
        listener->closeLink();
2655
0
        linkIsOpen=false;
2656
0
      }
2657
0
      listener->insertEOL();
2658
0
      break;
2659
0
    default:
2660
0
      if (c<=0x1f) {
2661
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendText: find unexpected char=%x\n", (unsigned int)(c)));
2662
0
      }
2663
0
      else
2664
0
        listener->insertCharacter(c);
2665
0
    }
2666
0
  }
2667
0
  if (linkIsOpen)
2668
0
    listener->closeLink();
2669
0
  ascFile.addPos(textEntry.begin());
2670
0
  ascFile.addNote(f.str().c_str());
2671
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2672
0
  return ok;
2673
0
}
2674
2675
bool Canvas5Graph::sendEffect(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape,
2676
                              Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
2677
0
{
2678
0
  if (!listener || !data.m_stream) {
2679
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: can not find the listener\n"));
2680
0
    return false;
2681
0
  }
2682
0
  auto &stream=data.getStream();
2683
0
  auto input=stream.input();
2684
0
  auto const &entry=data.m_entry;
2685
0
  libmwaw::DebugFile &ascFile = stream.ascii();
2686
0
  if (!entry.valid() || entry.length()<8 || !input->checkPosition(entry.end())) {
2687
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: can not find the number of zone\n"));
2688
0
    return false;
2689
0
  }
2690
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2691
0
  long pos=input->tell();
2692
0
  libmwaw::DebugStream f;
2693
0
  f << "Entries(Effect):";
2694
0
  for (int i=0; i<2; ++i) {
2695
0
    int val=int(input->readLong(i==0 ? 4 : 2));
2696
0
    if (val!=1-i) f << "f" << i << "=" << val << ",";
2697
0
  }
2698
0
  int N=int(input->readULong(2));
2699
0
  f << "N=" << N << ",";
2700
0
  ascFile.addPos(pos);
2701
0
  ascFile.addNote(f.str().c_str());
2702
2703
0
  if (N>2)
2704
0
    listener->openGroup(local.m_position);
2705
0
  for (int i=0; i<N; ++i) {
2706
0
    pos=input->tell();
2707
0
    f.str("");
2708
0
    f << "Effect-" << i << ":";
2709
0
    long dLen=input->readLong(4);
2710
0
    f << "sz=" << dLen << ",";
2711
0
    long endPos=pos+4+dLen;
2712
0
    if (endPos<pos+4 || !input->checkPosition(endPos)) {
2713
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendEffect: the length seems bad\n"));
2714
0
      f << "###";
2715
0
      ascFile.addPos(pos);
2716
0
      ascFile.addNote(f.str().c_str());
2717
0
      break;
2718
0
    }
2719
0
    ascFile.addPos(pos);
2720
0
    ascFile.addNote(f.str().c_str());
2721
0
    std::shared_ptr<Canvas5ImageInternal::VKFLImage> image;
2722
0
    if (m_imageParser->readVKFL(data.m_stream, dLen, image) && image)
2723
0
      m_imageParser->send(image, listener, shape.m_initialBox, local.m_transform);
2724
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
2725
0
  }
2726
2727
0
  if (N>2)
2728
0
    listener->closeGroup();
2729
0
  return true;
2730
0
}
2731
2732
bool Canvas5Graph::sendExtrude(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape,
2733
                               Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
2734
0
{
2735
0
  if (!listener || !data.m_stream) {
2736
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not find the listener\n"));
2737
0
    return false;
2738
0
  }
2739
0
  auto &stream=data.getStream();
2740
0
  auto input=stream.input();
2741
0
  auto const &entry=data.m_entry;
2742
0
  libmwaw::DebugFile &ascFile = stream.ascii();
2743
0
  if (!entry.valid() || entry.length()<1000+48 || !input->checkPosition(entry.end())) {
2744
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not find the text entry\n"));
2745
0
    return false;
2746
0
  }
2747
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2748
0
  long pos=input->tell();
2749
0
  libmwaw::DebugStream f;
2750
0
  f << "Entries(Extrude):";
2751
0
  ascFile.addPos(pos);
2752
0
  ascFile.addNote(f.str().c_str());
2753
2754
0
  int val;
2755
0
  for (int i=0; i<25; ++i) {
2756
    // 0: width
2757
    // 1: height
2758
    // 2: width[far]
2759
    // 12: 0, w, h, w2
2760
    // 13: w/2, h
2761
    //
2762
2763
0
    pos=input->tell();
2764
0
    f.str("");
2765
0
    f << "Extrude-" << i << ":";
2766
0
    for (int j=0; j<5; ++j) {
2767
0
      val=int(input->readULong(1));
2768
0
      input->seek(-1, librevenge::RVNG_SEEK_CUR);
2769
0
      if (val==0) {
2770
0
        for (int k=0; k<2; ++k) {
2771
0
          val=int(input->readLong(4));
2772
0
          if (val) f << "f" << 2*j+k << "=" << val << ",";
2773
0
        }
2774
0
      }
2775
0
      else {
2776
0
        double value;
2777
0
        bool isNAN;
2778
0
        if (!m_mainParser->readDouble(stream, value, isNAN)) {
2779
0
          f << "###";
2780
0
          input->seek(pos+8*(j+1), librevenge::RVNG_SEEK_SET);
2781
0
        }
2782
0
        else
2783
0
          f << "g" << j << "=" << value << ",";
2784
0
      }
2785
0
    }
2786
0
    ascFile.addPos(pos);
2787
0
    ascFile.addNote(f.str().c_str());
2788
0
    input->seek(pos+40, librevenge::RVNG_SEEK_SET);
2789
0
  }
2790
0
  pos=input->tell();
2791
0
  f.str("");
2792
0
  f << "Extrude-A:";
2793
0
  int N=0;
2794
0
  for (int i=0; i<12; ++i) {
2795
0
    val=int(input->readLong(4));
2796
0
    if (!val) continue;
2797
0
    if (i==4) {
2798
0
      N=val;
2799
0
      f << "N=" << N << ",";
2800
0
    }
2801
0
    else
2802
0
      f << "f" << i << "=" << val << ",";
2803
0
  }
2804
0
  if (N<2 || 1048+N*24<1048 || 1048+N*24>entry.length()) {
2805
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: the number of points seems bad\n"));
2806
0
    f << "###";
2807
0
    ascFile.addPos(pos);
2808
0
    ascFile.addNote(f.str().c_str());
2809
0
    return false;
2810
0
  }
2811
0
  ascFile.addPos(pos);
2812
0
  ascFile.addNote(f.str().c_str());
2813
0
  MWAWPosition const &position=local.m_position;
2814
0
  MWAWVec2f origin=position.origin()+0.5*position.size();
2815
0
  MWAWVec2f dir=0.5*position.size();
2816
0
  bool ok=true;
2817
2818
0
  std::vector<MWAWVec2f> pts;
2819
0
  for (int i=0; i<N; ++i) {
2820
0
    pos=input->tell();
2821
0
    f.str("");
2822
0
    f << "Extrude-B" << i << ":";
2823
0
    float coords[]= {0,0};
2824
0
    for (int j=0; j<2; ++j) {
2825
0
      double value;
2826
0
      bool isNAN;
2827
0
      if (!m_mainParser->readDouble(stream, value, isNAN) || value<-2 || value>2) {
2828
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: can not read a coordinate\n"));
2829
0
        f << "###";
2830
0
        input->seek(pos+8*(j+1), librevenge::RVNG_SEEK_SET);
2831
0
        ok=false;
2832
0
      }
2833
0
      else {
2834
0
        coords[j]=float(value);
2835
0
        f << "g" << j << "=" << value << ",";
2836
0
      }
2837
0
    }
2838
0
    pts.push_back(origin+MWAWVec2f(coords[0]*dir[0], coords[1]*dir[1]));
2839
0
    for (int j=0; j<2; ++j) {
2840
0
      val=int(input->readLong(4));
2841
0
      if (!val) continue;
2842
0
      f << "f" << i << "=" << val << ",";
2843
0
    }
2844
0
    ascFile.addPos(pos);
2845
0
    ascFile.addNote(f.str().c_str());
2846
0
    input->seek(pos+24, librevenge::RVNG_SEEK_SET);
2847
0
  }
2848
0
  if (input->tell()<entry.end()) {
2849
0
    ascFile.addPos(input->tell());
2850
0
    ascFile.addNote("Extrude-End:");
2851
0
  }
2852
0
  if (!ok)
2853
0
    return false;
2854
2855
  // FIXME: sometimes there is multiple contours in this list of points ...
2856
0
  static bool first=true;
2857
0
  if (first) {
2858
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendExtrude: sorry, sending extrude's shape is not reliable\n"));
2859
0
    first=false;
2860
0
  }
2861
0
  auto fShape=MWAWGraphicShape::polygon(shape.m_initialBox);
2862
0
  fShape.m_vertices=pts;
2863
0
  send(listener, fShape, local.m_transform, local.m_style);
2864
0
  return true;
2865
0
}
2866
2867
bool Canvas5Graph::sendGIF(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape,
2868
                           Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
2869
0
{
2870
0
  if (!listener || !data.m_stream) {
2871
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the listener\n"));
2872
0
    return false;
2873
0
  }
2874
0
  auto &stream=data.getStream();
2875
0
  auto input=stream.input();
2876
0
  auto const &entry=data.m_entry;
2877
0
  libmwaw::DebugFile &ascFile = stream.ascii();
2878
0
  if (!entry.valid() || entry.length()<104 || !input->checkPosition(entry.end())) {
2879
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the number of zone\n"));
2880
0
    return false;
2881
0
  }
2882
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2883
0
  long pos=input->tell();
2884
0
  libmwaw::DebugStream f;
2885
0
  f << "Entries(ANGF):";
2886
0
  int val=int(input->readULong(4));
2887
0
  if (val) f << "id=" << std::hex << val << std::dec << ",";
2888
0
  auto len=input->readLong(4);
2889
0
  if (104+len<104 || 104+len>entry.length()) {
2890
0
    f << "###";
2891
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the GIF length\n"));
2892
0
    ascFile.addPos(pos);
2893
0
    ascFile.addNote(f.str().c_str());
2894
0
    return false;
2895
0
  }
2896
0
  ascFile.addDelimiter(input->tell(),'|');
2897
0
  input->seek(pos+8+80, librevenge::RVNG_SEEK_SET);
2898
0
  int dim[2];
2899
0
  for (auto &d : dim)
2900
0
    d = int(input->readLong(4));
2901
0
  f << "dim=" << MWAWVec2i(dim[0],dim[1]) << ",";
2902
0
  val=int(input->readLong(4));
2903
0
  if (val!=1)
2904
0
    f << "f0=" << val << ",";
2905
0
  val=int(input->readLong(4));
2906
0
  if (val!=4)
2907
0
    f << "f0=" << val << ",";
2908
0
  ascFile.addPos(pos);
2909
0
  ascFile.addNote(f.str().c_str());
2910
2911
0
  if (!len) {
2912
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendGIF: can not find the GIF picture\n"));
2913
0
  }
2914
0
  else {
2915
0
    pos=input->tell();
2916
0
    librevenge::RVNGBinaryData gif;
2917
0
    if (!input->readDataBlock(len, gif)) {
2918
0
      MWAW_DEBUG_MSG(("Canvas5Image::sendGIF: oops can not retrieve the gif\n"));
2919
0
      ascFile.addPos(pos);
2920
0
      ascFile.addNote("ANGF:###");
2921
0
      return false;
2922
0
    }
2923
2924
0
    ascFile.skipZone(pos, pos+len-1);
2925
#ifdef DEBUG_WITH_FILES
2926
    std::stringstream s;
2927
    static int index=0;
2928
    s << "gif" << ++index << ".gif";
2929
    libmwaw::Debug::dumpFile(gif, s.str().c_str());
2930
#endif
2931
2932
0
    MWAWEmbeddedObject obj(gif, "image/gif");
2933
0
    MWAWTransformation transf;
2934
0
    float rotation=0;
2935
0
    MWAWVec2f shearing;
2936
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,shape.m_initialBox.center())) {
2937
0
      MWAWBox2f shapeBox=transf*shape.m_initialBox;
2938
0
      MWAWPosition posi(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
2939
0
      posi.m_anchorTo = MWAWPosition::Page;
2940
0
      MWAWGraphicStyle style(local.m_style);
2941
0
      style.m_rotate=-rotation;
2942
0
      listener->insertPicture(posi, obj, style);
2943
0
    }
2944
0
    else
2945
0
      listener->insertPicture(local.m_position, obj, local.m_style);
2946
0
  }
2947
2948
0
  while (!input->tell()+4<entry.end()) {
2949
    // find 4 blocks with size 28
2950
0
    pos=input->tell();
2951
0
    len=input->readLong(4);
2952
0
    if (pos+len<pos+4 || pos+len>entry.end()) {
2953
0
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2954
0
      break;
2955
0
    }
2956
0
    ascFile.addPos(pos);
2957
0
    ascFile.addNote("ANGF-Dt:");
2958
0
    input->seek(pos+len, librevenge::RVNG_SEEK_SET);
2959
0
  }
2960
2961
0
  pos=input->tell();
2962
0
  if (pos!=entry.end()) {
2963
0
    MWAW_DEBUG_MSG(("Canvas5Image::sendGIF: find extra data\n"));
2964
0
    ascFile.addPos(pos);
2965
0
    ascFile.addNote("ANGF[extra]:###");
2966
0
  }
2967
0
  return true;
2968
0
}
2969
2970
bool Canvas5Graph::sendTechnical(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape,
2971
                                 Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
2972
0
{
2973
0
  if (!listener || !data.m_stream) {
2974
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not find the listener\n"));
2975
0
    return false;
2976
0
  }
2977
0
  auto &stream=data.getStream();
2978
0
  auto input=stream.input();
2979
0
  auto const &entry=data.m_entry;
2980
0
  libmwaw::DebugFile &ascFile = stream.ascii();
2981
0
  if (!entry.valid() || entry.length()<8 || !input->checkPosition(entry.end())) {
2982
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not find the number of zone\n"));
2983
0
    return false;
2984
0
  }
2985
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2986
0
  long pos=input->tell();
2987
0
  libmwaw::DebugStream f;
2988
0
  f << "Entries(Technical):";
2989
0
  int N[2];
2990
0
  f << "N=[";
2991
0
  for (auto &n : N) {
2992
0
    n=m_mainParser->readInteger(stream, 8);
2993
0
    f << n << ",";
2994
0
  }
2995
2996
0
  bool isGroupOpened=false;
2997
0
  if (N[0]>1) {
2998
0
    isGroupOpened=true;
2999
0
    listener->openGroup(local.m_position);
3000
0
  }
3001
0
  ascFile.addPos(pos);
3002
0
  ascFile.addNote(f.str().c_str());
3003
0
  for (int poly=0; poly<N[0]; ++poly) {
3004
0
    f.str("");
3005
0
    pos=input->tell();
3006
0
    f << "Technical-T" << poly << ":";
3007
0
    if (pos+8 > data.m_entry.end()) {
3008
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a spline\n"));
3009
0
      f << "###";
3010
0
      ascFile.addPos(pos);
3011
0
      ascFile.addNote(f.str().c_str());
3012
0
      if (isGroupOpened)
3013
0
        listener->closeGroup();
3014
0
      return false;
3015
0
    }
3016
0
    int N1[2]; // id, num pt
3017
0
    f << "N=[";
3018
0
    for (auto &n : N1) {
3019
0
      double value;
3020
0
      bool isNan;
3021
0
      if (!m_mainParser->readDouble(stream, value, isNan)) {
3022
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a generic number\n"));
3023
0
        f << "###";
3024
0
        ascFile.addPos(pos);
3025
0
        ascFile.addNote(f.str().c_str());
3026
0
        if (isGroupOpened)
3027
0
          listener->closeGroup();
3028
0
        return false;
3029
0
      }
3030
0
      n=int(value+0.2);
3031
0
      f << n << ",";
3032
0
    }
3033
0
    f << "],";
3034
0
    if (N1[1]<0 || (data.m_entry.end()-pos-8)/16<N1[1] || pos+8+16*N1[1] > data.m_entry.end()) {
3035
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a sub shape\n"));
3036
0
      f << "###";
3037
0
      ascFile.addPos(pos);
3038
0
      ascFile.addNote(f.str().c_str());
3039
0
      if (isGroupOpened)
3040
0
        listener->closeGroup();
3041
0
      return false;
3042
0
    }
3043
3044
0
    f << "pts=[";
3045
0
    std::vector<MWAWVec2f> points;
3046
0
    for (int p=0; p<N1[1]; ++p) {
3047
0
      double coord[2];
3048
0
      for (auto &c : coord) {
3049
0
        bool isNan;
3050
0
        long actPos=input->tell();
3051
0
        if (!m_mainParser->readDouble(stream, c, isNan)) {
3052
0
          MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a number\n"));
3053
0
          f << "###";
3054
0
          input->seek(actPos+8, librevenge::RVNG_SEEK_SET);
3055
0
          c=0;
3056
0
        }
3057
0
      }
3058
0
      points.push_back(MWAWVec2f(float(coord[1]), float(coord[0])));
3059
0
      f << points.back() << ",";
3060
0
    }
3061
0
    f << "],";
3062
3063
0
    auto const orig=shape.m_initialBox[0];
3064
0
    auto const dir=shape.m_initialBox.size();
3065
0
    for (auto &p : points)
3066
0
      p=orig+MWAWVec2f(p[0]*dir[0],p[1]*dir[1]);
3067
0
    if (points.size()<4) {
3068
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: the spline seems bad\n"));
3069
0
      f << "###";
3070
0
    }
3071
0
    else {
3072
0
      auto finalShape=MWAWGraphicShape::path(shape.m_initialBox);
3073
0
      std::vector<MWAWGraphicShape::PathData> &path=finalShape.m_path;
3074
0
      path.push_back(MWAWGraphicShape::PathData('M', points[0]));
3075
0
      for (size_t p=3; p < points.size(); p+=4) {
3076
0
        if (p>=4 && points[p-4]!=points[p-3])
3077
0
          path.push_back(MWAWGraphicShape::PathData('M', points[p-3]));
3078
0
        bool hasFirstC=points[p-3]!=points[p-2];
3079
0
        bool hasSecondC=points[p-1]!=points[p];
3080
0
        if (!hasFirstC && !hasSecondC)
3081
0
          path.push_back(MWAWGraphicShape::PathData('L', points[p]));
3082
0
        else
3083
0
          path.push_back(MWAWGraphicShape::PathData('C', points[p], points[p-2], points[p-1]));
3084
0
      }
3085
0
      if (local.m_style.hasSurface())
3086
0
        path.push_back(MWAWGraphicShape::PathData('Z'));
3087
0
      send(listener, finalShape, local.m_transform, local.m_style);
3088
0
    }
3089
3090
0
    ascFile.addPos(pos);
3091
0
    ascFile.addNote(f.str().c_str());
3092
0
  }
3093
0
  if (isGroupOpened)
3094
0
    listener->closeGroup();
3095
3096
0
  pos=input->tell();
3097
0
  f.str("");
3098
0
  f << "Technical-A:";
3099
0
  if (pos+16>entry.end()) {
3100
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read the last part\n"));
3101
0
    f << "###";
3102
0
    ascFile.addPos(pos);
3103
0
    ascFile.addNote(f.str().c_str());
3104
0
    return false;
3105
0
  }
3106
0
  for (int i=0; i<6; ++i) {
3107
0
    int val=int(input->readLong(2));
3108
0
    int const expected[]= {0,0,0,0,0x6ef0,1};
3109
0
    if (val==expected[i])
3110
0
      continue;
3111
0
    if (i==3)
3112
0
      f << "fl=" << std::hex << val << std::dec << ","; // 5X01
3113
0
    else
3114
0
      f << "f" << i << "=" << val << ",";
3115
0
  }
3116
0
  int n=int(input->readULong(4));
3117
0
  f << "N=" << n << ",";
3118
0
  ascFile.addPos(pos);
3119
0
  ascFile.addNote(f.str().c_str());
3120
3121
0
  for (int i=0; i<n; ++i) {
3122
0
    pos=input->tell();
3123
0
    f.str("");
3124
0
    f << "Technical-A" << i << ":";
3125
0
    if (pos+12>entry.end()) {
3126
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a type block\n"));
3127
0
      f << "###";
3128
0
      ascFile.addPos(pos);
3129
0
      ascFile.addNote(f.str().c_str());
3130
0
      return false;
3131
0
    }
3132
0
    unsigned type=unsigned(input->readULong(4));
3133
0
    f << Canvas5Structure::getString(type) << ",";
3134
0
    int val=int(input->readLong(4));
3135
0
    if (val)
3136
0
      f << "id=" << val << ",";
3137
0
    long len=input->readLong(4);
3138
0
    long endPos=pos+12+len;
3139
0
    if (endPos<pos+12 || endPos>entry.end()) {
3140
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: can not read a type block\n"));
3141
0
      f << "###";
3142
0
      ascFile.addPos(pos);
3143
0
      ascFile.addNote(f.str().c_str());
3144
0
      return false;
3145
0
    }
3146
0
    switch (type) {
3147
0
    case 0x42507473: { //BPts copy of main zone of points but store with int
3148
0
      libmwaw::DebugStream f2;
3149
0
      while (input->tell()+8<endPos) {
3150
0
        long actPos=input->tell();
3151
0
        f2.str("");
3152
0
        f2 << "Technical-bPts:";
3153
0
        f2 << "id=" << input->readLong(4) << ",";
3154
0
        int nbPts=int(input->readLong(4));
3155
0
        f2 << "N=" << nbPts << ",";
3156
0
        if (nbPts<4 || (endPos-actPos-8)/8 < nbPts) {
3157
0
          input->seek(actPos, librevenge::RVNG_SEEK_SET);
3158
0
          break;
3159
0
        }
3160
0
        f2 << "pts=[";
3161
0
        for (int j=0; j<nbPts; ++j) {
3162
0
          float coord[2];
3163
0
          for (auto &c : coord) c=float(input->readLong(4))/65536;
3164
0
          f2 << MWAWVec2f(coord[0],coord[1]) << ",";
3165
0
        }
3166
0
        f2 << "],";
3167
0
        ascFile.addPos(actPos);
3168
0
        ascFile.addNote(f2.str().c_str());
3169
0
      }
3170
0
      if (input->tell()!=endPos) {
3171
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[bPts]: can not read some data\n"));
3172
0
        ascFile.addPos(input->tell());
3173
0
        ascFile.addNote("Technical-bPts:###");
3174
0
      }
3175
0
      break;
3176
0
    }
3177
0
    case 0x4374726c: // Ctrl
3178
0
      if (long(int(len/4))*4!=len || (len%4)!=0) {
3179
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Ctrl]: unexpected length\n"));
3180
0
        f << "###";
3181
0
        break;
3182
0
      }
3183
0
      f << "val=["; // [4] or [1,2,3]
3184
0
      for (int j=0; j<int(len)/4; ++j)
3185
0
        f << input->readLong(4) << ",";
3186
0
      f << "],";
3187
0
      break;
3188
0
    case 0x44697263: // Dirc
3189
0
      if (len!=4) {
3190
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Dirc]: unexpected length\n"));
3191
0
        f << "###";
3192
0
        break;
3193
0
      }
3194
0
      f << "f0=" << input->readLong(4) << ","; // 4
3195
0
      break;
3196
0
    case 0x53686450: // ShdP
3197
0
      if (long(int(len/4))*4!=len || (len%4)!=0) {
3198
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[ShdP]: unexpected length\n"));
3199
0
        f << "###";
3200
0
        break;
3201
0
      }
3202
0
      f << "val=["; // [2] or [2,3]
3203
0
      for (int j=0; j<int(len)/4; ++j)
3204
0
        f << input->readLong(4) << ",";
3205
0
      f << "],";
3206
0
      break;
3207
0
    case 0x53796d6d: // Symm
3208
0
      if (len!=4) {
3209
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[Symm]: unexpected length\n"));
3210
0
        f << "###";
3211
0
        break;
3212
0
      }
3213
0
      f << "f0=" << input->readLong(4) << ","; // 0
3214
0
      break;
3215
0
    case 0x54787450: // TxtP
3216
0
      if (len!=4) {
3217
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[TxtP]: unexpected length\n"));
3218
0
        f << "###";
3219
0
        break;
3220
0
      }
3221
0
      f << "f0=" << input->readLong(4) << ","; // 1
3222
0
      break;
3223
0
    case 0x57547874: // WTxt
3224
0
      if (len!=4) {
3225
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[WTxt]: unexpected length\n"));
3226
0
        f << "###";
3227
0
        break;
3228
0
      }
3229
0
      f << "f0=" << input->readLong(4) << ","; // 0
3230
0
      break;
3231
0
    case 0x6b696e64: // kind
3232
0
      if (len!=4) {
3233
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical[kind]: unexpected length\n"));
3234
0
        f << "###";
3235
0
        break;
3236
0
      }
3237
0
      f << input->readLong(4) << ",";
3238
0
      break;
3239
0
    default:
3240
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendTechnical: unexpected type=%s\n", Canvas5Structure::getString(type).c_str()));
3241
0
      f << "###";
3242
0
      break;
3243
0
    }
3244
0
    if (input->tell()!=endPos) {
3245
0
      ascFile.addDelimiter(input->tell(),'|');
3246
0
      input->seek(endPos, librevenge::RVNG_SEEK_SET);
3247
0
    }
3248
0
    ascFile.addPos(pos);
3249
0
    ascFile.addNote(f.str().c_str());
3250
0
  }
3251
3252
0
  return true;
3253
0
}
3254
3255
bool Canvas5Graph::sendCurveText(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/,
3256
                                 Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
3257
0
{
3258
0
  if (!listener || !data.m_stream) {
3259
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: can not find the listener\n"));
3260
0
    return false;
3261
0
  }
3262
0
  auto &stream=data.getStream();
3263
0
  auto input=stream.input();
3264
0
  int const vers=version();
3265
0
  auto const &entry=data.m_entry;
3266
0
  libmwaw::DebugFile &ascFile = stream.ascii();
3267
0
  int const headerSz=vers<9 ? 176 : 344;
3268
0
  if (!entry.valid() || entry.length()<headerSz || !input->checkPosition(entry.end())) {
3269
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: can not find the text entry\n"));
3270
0
    return false;
3271
0
  }
3272
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
3273
0
  long pos=input->tell();
3274
0
  libmwaw::DebugStream f;
3275
0
  f << "Entries(CurveTxt):";
3276
3277
0
  input->seek(pos+(vers<9 ? 24 : 40), librevenge::RVNG_SEEK_SET);
3278
0
  ascFile.addDelimiter(input->tell(),'|');
3279
0
  f << "unk=[";
3280
0
  MWAWVec2f origin=local.m_position.origin();
3281
0
  for (int p=0; p<9; ++p) { // pt7: origin bdbox max, pt8 origin bdbox min
3282
0
    float dim[2];
3283
0
    for (auto &d : dim) d=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8));
3284
0
    if (vers>=9)
3285
0
      std::swap(dim[0],dim[1]);
3286
0
    f << MWAWVec2f(dim[1],dim[0]) << ",";
3287
0
    if (p==8) origin=MWAWVec2f(dim[1],dim[0]); // checkme: not always fine
3288
0
  }
3289
0
  f << "],";
3290
0
  int N=int(input->readULong(2)), val;
3291
0
  f << "N=" << N << ",";
3292
0
  for (int i=0; i<4; ++i) { // g0: current style ?
3293
0
    val=int(input->readLong(2));
3294
0
    if (val!=(i==0 ? 1 : 0))
3295
0
      f << "g" << i << "=" << val << ",";
3296
0
  }
3297
0
  int nFonts=int(input->readULong(2));
3298
0
  f << "nFonts=" << nFonts << ",";
3299
0
  int const fontSize=vers<9 ? 72 : 120;
3300
0
  int const textSize=vers<9 ? 60 : 112;
3301
0
  if (headerSz+nFonts*fontSize+N*textSize<0 || headerSz+nFonts*fontSize+N*textSize>entry.length()) {
3302
0
    f << "###";
3303
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: N seems bad\n"));
3304
0
    return false;
3305
0
  }
3306
0
  input->seek(pos+headerSz, librevenge::RVNG_SEEK_SET);
3307
0
  ascFile.addPos(pos);
3308
0
  ascFile.addNote(f.str().c_str());
3309
3310
0
  std::vector<Canvas5StyleManager::CharStyle> fonts;
3311
0
  fonts.resize(size_t(nFonts));
3312
0
  for (size_t i=0; i<size_t(nFonts); ++i) {
3313
0
    pos=input->tell();
3314
0
    f.str("");
3315
0
    f << "CurveTxt-F" << i+1 << ":";
3316
0
    for (int j=0; j<(vers<9 ? 2 : 4); ++j) { // f0: small number
3317
0
      val=int(input->readLong(4));
3318
0
      if (val) f << "f" << j << "=" << val << ",";
3319
0
    }
3320
0
    ascFile.addPos(pos);
3321
0
    ascFile.addNote(f.str().c_str());
3322
0
    m_styleManager->readCharStyle(stream, int(i+1), fonts[i]);
3323
0
    for (int j=0; j<(vers<9 ? 2 : 4); ++j) {
3324
0
      val=int(input->readLong(2));
3325
0
      if (val) f << "f" << j+4 << "=" << val << ",";
3326
0
    }
3327
0
  }
3328
3329
0
  if (N>1)
3330
0
    listener->openGroup(local.m_position);
3331
0
  auto fontConverter=m_parserState->m_fontConverter;
3332
0
  MWAWGraphicStyle charStyle=MWAWGraphicStyle::emptyStyle();
3333
0
  MWAWPosition charPos(local.m_position);
3334
0
  for (int i=0; i<N; ++i) {
3335
0
    pos=input->tell();
3336
0
    f.str("");
3337
0
    f << "CurveTxt-" << i << ":";
3338
0
    int fId=int(input->readULong(2));
3339
0
    f << "F" << fId+1 << ",";
3340
0
    MWAWFont font;
3341
0
    if (fId>=0 && fId<int(nFonts))
3342
0
      font=fonts[size_t(fId)].m_font;
3343
0
    else {
3344
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: find unknow fonts\n"));
3345
0
      f << "###";
3346
0
    }
3347
0
    librevenge::RVNGString text;
3348
0
    char c=char(input->readULong(1));
3349
0
    int unicode = fontConverter->unicode(font.id(), (unsigned char)(c));
3350
0
    if (unicode == -1) {
3351
0
      if (c < 0x20) {
3352
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendCurveText: Find odd char %x\n", static_cast<unsigned int>(c)));
3353
0
      }
3354
0
      else
3355
0
        text.append(c);
3356
0
    }
3357
0
    else
3358
0
      libmwaw::appendUnicode(uint32_t(unicode), text);
3359
0
    if (!text.empty())
3360
0
      f << text.cstr() << ",";
3361
0
    input->seek(1, librevenge::RVNG_SEEK_CUR);
3362
0
    val=int(input->readULong(4));
3363
0
    if (val!=0x17c94)
3364
0
      f << "f0=" << val << ",";
3365
0
    float angle=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8));
3366
0
    f << "angle=" << angle << ",";
3367
0
    MWAWVec2f points[5];
3368
0
    f << "pts=[";
3369
0
    for (auto &pt : points) { // decal, then a box?
3370
0
      float pts[2];
3371
0
      for (auto &p : pts) p=float(m_mainParser->readDouble(stream, vers<9 ? 4 : 8));
3372
0
      if (vers<9)
3373
0
        pt= MWAWVec2f(pts[1],pts[0]);
3374
0
      else
3375
0
        pt= MWAWVec2f(pts[0],pts[1]);
3376
0
      f << pt << ",";
3377
0
    }
3378
0
    f << "],";
3379
0
    ascFile.addPos(pos);
3380
0
    ascFile.addNote(f.str().c_str());
3381
0
    input->seek(pos+textSize, librevenge::RVNG_SEEK_SET);
3382
3383
0
    if (text.empty()) continue;
3384
0
    std::shared_ptr<MWAWSubDocument> doc(new Canvas5GraphInternal::SubDocument(*this, input, text, font));
3385
3386
0
    MWAWTransformation transf;
3387
0
    float rotation=0;
3388
0
    MWAWVec2f shearing;
3389
0
    if (!local.m_transform.isIdentity() && local.m_transform.decompose(rotation,shearing,transf,origin+0.5*points[2]+0.5*points[3])) {
3390
0
      MWAWBox2f shapeBox=transf*MWAWBox2f(origin+points[2],origin+points[3]);
3391
0
      charPos.setOrigin(shapeBox[0]);
3392
0
      charPos.setSize(shapeBox[1]-shapeBox[0]);
3393
0
      charStyle.m_rotate=-angle-rotation;
3394
0
    }
3395
0
    else {
3396
0
      charPos.setOrigin(origin+points[2]);
3397
0
      charPos.setSize(points[3]-points[2]);
3398
0
      charStyle.m_rotate=-angle;
3399
0
    }
3400
0
    listener->insertTextBox(charPos, doc, charStyle);
3401
0
  }
3402
0
  if (N>1)
3403
0
    listener->closeGroup();
3404
3405
0
  pos=input->tell();
3406
0
  f.str("");
3407
0
  f << "CurveTxt-End:";
3408
0
  ascFile.addPos(pos);
3409
0
  ascFile.addNote(f.str().c_str());
3410
0
  return true;
3411
0
}
3412
3413
bool Canvas5Graph::sendDimension(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &shape,
3414
                                 Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
3415
0
{
3416
0
  if (!listener || !data.m_stream || version()>=9) {
3417
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not find the listener\n"));
3418
0
    return false;
3419
0
  }
3420
0
  auto &stream=data.getStream();
3421
0
  auto input=stream.input();
3422
0
  auto const &entry=data.m_entry;
3423
0
  if (!entry.valid() || !input->checkPosition(entry.end())) {
3424
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not find the shape enntry\n"));
3425
0
    return false;
3426
0
  }
3427
3428
0
  libmwaw::DebugFile &ascFile = stream.ascii();
3429
0
  libmwaw::DebugStream f;
3430
0
  f << "Entries(Dimension):";
3431
0
  if (entry.length()<420) {
3432
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: the data seens too short\n"));
3433
0
    f << "###sz";
3434
0
    ascFile.addPos(entry.begin());
3435
0
    ascFile.addNote(f.str().c_str());
3436
0
    return false;
3437
0
  }
3438
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
3439
0
  int type=int(input->readLong(2)); // 1-15
3440
0
  if (type) f << "type=" << type << ",";
3441
0
  int val=int(input->readLong(2)); // 0
3442
0
  if (val) f << "f0=" << val << ",";
3443
0
  f << "points=[";
3444
0
  std::vector<MWAWVec2f> pts;
3445
0
  for (int i=0; i<18; ++i) {
3446
0
    float dims[2];
3447
    // fract type: between -2 and 2
3448
0
    for (auto &d : dims) d=4*float(input->readLong(4))/65536.f/65536.f;
3449
0
    pts.push_back(MWAWVec2f(dims[1],dims[0]));
3450
0
    f << pts.back() << ",";
3451
0
  }
3452
0
  f << "],";
3453
0
  ascFile.addPos(entry.begin());
3454
0
  ascFile.addNote(f.str().c_str());
3455
3456
0
  long posi=input->tell();
3457
0
  f.str("");
3458
0
  f << "Dimension[data1]:";
3459
0
  input->seek(posi+40, librevenge::RVNG_SEEK_SET);
3460
0
  ascFile.addDelimiter(input->tell(),'|');
3461
0
  bool arrowInside=true;
3462
0
  bool hasFrame=false;
3463
0
  for (int i=0; i<3; ++i) {
3464
0
    val=int(input->readLong(2));
3465
0
    int const expected[]= {1,0,0};
3466
0
    if (val==expected[i]) continue;
3467
0
    char const *wh[]= {"arrows[inside]", "text[centered]", "frame[text]"};
3468
0
    if (val==0) {
3469
0
      if (i==0) arrowInside=false;
3470
0
      f << wh[i] << "=off,";
3471
0
    }
3472
0
    else if (val==1) {
3473
0
      if (i==2) hasFrame=true;
3474
0
      f << wh[i] << "=on,";
3475
0
    }
3476
0
    else
3477
0
      f << "###" << wh[i] << "=" << val << ",";
3478
0
  }
3479
0
  for (int i=0; i<5; ++i) {
3480
0
    val=int(input->readLong(2));
3481
0
    int const expected[]= { 1, 1, 1, 0, 3};
3482
0
    if (val==expected[i]) continue;
3483
0
    char const *wh[]= {
3484
0
      "leader",  // none, left, right, automatic
3485
0
      nullptr,
3486
0
      "display[text]", // hori, hori/90, aligned, above, below
3487
0
      "what", // 1: line, 3: arc?
3488
0
      "precision", // X, X.X, X.XX, X.XXX, X.XXXX, X X/X
3489
0
    };
3490
0
    if (i==3 && val==3)
3491
0
      f << "print[angle],";
3492
0
    else if (wh[i])
3493
0
      f << wh[i] << "=" << val << ",";
3494
0
    else
3495
0
      f << "f" << i << "=" << val << ",";
3496
0
  }
3497
0
  f << "tolerances=[";
3498
0
  for (int i=0; i<3; ++i) f << float(input->readLong(4))/65536.f << ",";
3499
0
  f << "],";
3500
0
  val=int(input->readLong(2));
3501
0
  if (val!=1)
3502
0
    f << "f6=" << val << ",";
3503
0
  librevenge::RVNGString format;
3504
0
  long actPos=input->tell();
3505
0
  if (m_mainParser->readString(stream, format, 19))
3506
0
    f << "unit=" << format.cstr() << ",";
3507
0
  else {
3508
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not read the format's name\n"));
3509
0
    f << "###format,";
3510
0
    input->seek(actPos+20, librevenge::RVNG_SEEK_SET);
3511
0
  }
3512
0
  ascFile.addDelimiter(input->tell(), '|');
3513
0
  input->seek(posi+162, librevenge::RVNG_SEEK_SET);
3514
0
  ascFile.addPos(posi);
3515
0
  ascFile.addNote(f.str().c_str());
3516
3517
0
  posi=input->tell();
3518
0
  f.str("");
3519
0
  f << "Dimension-format:";
3520
0
  input->seek(posi+22, librevenge::RVNG_SEEK_SET);
3521
0
  ascFile.addDelimiter(input->tell(), '|');
3522
0
  if (m_mainParser->readString(stream, format, 19))
3523
0
    f << "name=" << format.cstr() << ",";
3524
0
  else {
3525
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not read the format's name\n"));
3526
0
    f << "###format,";
3527
0
  }
3528
0
  input->seek(posi+22+20, librevenge::RVNG_SEEK_SET);
3529
0
  ascFile.addDelimiter(input->tell(), '|');
3530
0
  ascFile.addPos(posi);
3531
0
  ascFile.addNote(f.str().c_str());
3532
3533
0
  MWAWVec2f bDir=shape.m_initialBox.size();
3534
0
  for (auto &pt : pts)
3535
0
    pt=shape.m_initialBox[0]+MWAWVec2f(pt[0]*bDir[0], pt[1]*bDir[1]);
3536
3537
0
  MWAWGraphicStyle style=local.m_style;
3538
0
  listener->openGroup(local.m_position);
3539
3540
0
  MWAWGraphicShape fShape;
3541
0
  MWAWBox2f shapeBox;
3542
3543
0
  MWAWVec2f textOrigin;
3544
0
  librevenge::RVNGString text;
3545
0
  if (type==12) { // a sector instead of a line
3546
    // circle between pts[0], pts[1]->pts[2]
3547
0
    float angles[2];
3548
0
    for (size_t i=0; i<2; ++i) {
3549
0
      MWAWVec2f dir=pts[i+1]-pts[0];
3550
0
      angles[i]=180*std::atan2(-dir[1],dir[0])/float(M_PI);
3551
0
    }
3552
0
    if (std::isnan(angles[0]) || std::isnan(angles[1])) {
3553
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension: can not compute the sector angles\n"));
3554
0
    }
3555
0
    else {
3556
0
      if (angles[1]<angles[0])
3557
0
        std::swap(angles[0],angles[1]);
3558
0
      MWAWVec2f dir=pts[5]-pts[0];
3559
0
      float len=std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]);
3560
0
      MWAWBox2f circleBox(pts[0]-len *MWAWVec2f(1,1), pts[0]+len *MWAWVec2f(1,1));
3561
0
      for (int st=0; st<2; ++st) {
3562
0
        float angle[2];
3563
0
        if (arrowInside) {
3564
0
          if (st==1)
3565
0
            break;
3566
0
          angle[0]=angles[0];
3567
0
          angle[1]=angles[1];
3568
0
        }
3569
0
        else if (st==0) {
3570
0
          angle[0]=angles[0]-10;
3571
0
          angle[1]=angles[0];
3572
0
        }
3573
0
        else {
3574
0
          angle[0]=angles[1];
3575
0
          angle[1]=angles[1]+10;
3576
0
        }
3577
        // we must compute the real bd box
3578
0
        float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
3579
0
        int limitAngle[2];
3580
0
        for (int i = 0; i < 2; ++i)
3581
0
          limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
3582
0
        for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) {
3583
0
          float ang = (bord == limitAngle[0]) ? float(angle[0]) :
3584
0
                      (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord);
3585
0
          ang *= float(M_PI/180.);
3586
0
          float const actVal[2] = { std::cos(ang), -std::sin(ang)};
3587
0
          if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
3588
0
          else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
3589
0
          if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
3590
0
          else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
3591
0
        }
3592
0
        MWAWBox2f arcBox=circleBox;
3593
        // we have the shape box, we need to reconstruct the circle box
3594
0
        if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) {
3595
0
          float scaling[2]= { (circleBox[1][0]-circleBox[0][0])/(maxVal[0]-minVal[0]),
3596
0
                              (circleBox[1][1]-circleBox[0][1])/(maxVal[1]-minVal[1])
3597
0
                            };
3598
0
          for (auto &s : scaling) {
3599
0
            if (s>1e7)
3600
0
              s=100;
3601
0
            else if (s<-1e7)
3602
0
              s=-100;
3603
0
          }
3604
0
          float const constant[2]= { circleBox[0][0]-minVal[0] *scaling[0], circleBox[0][1]-minVal[1] *scaling[1]};
3605
0
          arcBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]),
3606
0
                           MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1]));
3607
0
        }
3608
0
        style.setSurfaceColor(MWAWColor::white(), 0);
3609
0
        style.m_arrows[st]=arrowInside ? MWAWGraphicStyle::Arrow::plain(): MWAWGraphicStyle::Arrow();
3610
0
        style.m_arrows[1-st]=MWAWGraphicStyle::Arrow::plain();
3611
3612
0
        fShape = MWAWGraphicShape::arc(arcBox, circleBox, MWAWVec2f(float(angle[0]), float(angle[1])));
3613
0
        send(listener, fShape, local.m_transform, style);
3614
0
      }
3615
0
    }
3616
    // TODO: use format for unit, ...
3617
0
    textOrigin=pts[9];
3618
0
    std::stringstream s;
3619
0
    s << std::setprecision(0) << std::fixed << angles[1]-angles[0] << " ";
3620
0
    text=s.str().c_str();
3621
0
    libmwaw::appendUnicode(0xb0, text);
3622
0
  }
3623
0
  else if (type>12 && type<=14) { // radius/diameter inside an circle/ellipse
3624
0
    size_t orig=type==13 ? 0 : 4;
3625
0
    fShape=MWAWGraphicShape::line(pts[orig],pts[3]);
3626
0
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
3627
0
    send(listener, fShape, local.m_transform, style);
3628
3629
0
    fShape=MWAWGraphicShape::line(pts[1],pts[3]);
3630
0
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
3631
0
    send(listener, fShape, local.m_transform, style);
3632
3633
0
    textOrigin=pts[1];
3634
    // TODO: use format for unit, ...
3635
0
    MWAWVec2f lineSz=pts[orig]-pts[3];
3636
0
    std::stringstream s;
3637
0
    s << std::setprecision(0) << std::fixed << std::sqrt(lineSz[0]*lineSz[0]+lineSz[1]*lineSz[1]) << " pt";
3638
0
    text=s.str().c_str();
3639
0
  }
3640
0
  else if (type==15) { // four segments, no text
3641
0
    for (size_t i=0; i<4; ++i) {
3642
0
      fShape=MWAWGraphicShape::line(pts[1],pts[i+14]);
3643
0
      send(listener, fShape, local.m_transform, style);
3644
0
    }
3645
0
  }
3646
0
  else {
3647
0
    for (size_t i=0; i<2; ++i) {
3648
0
      size_t const limits[]= {4,6, 7,9 }; // outside1, outside2
3649
0
      fShape=MWAWGraphicShape::line(pts[limits[2*i]],pts[limits[2*i+1]]);
3650
0
      send(listener, fShape, local.m_transform, style);
3651
0
    }
3652
3653
0
    if (arrowInside) {
3654
0
      style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
3655
0
      fShape=MWAWGraphicShape::line(pts[5],pts[8]);
3656
0
      send(listener, fShape, local.m_transform, style);
3657
0
    }
3658
0
    else {
3659
0
      style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
3660
0
      for (size_t i=0; i<2; ++i) {
3661
0
        size_t const limits[]= {5,10, 8,11 }; // arrows1, arrows2
3662
0
        fShape=MWAWGraphicShape::line(pts[limits[2*i]],pts[limits[2*i+1]]);
3663
0
        send(listener, fShape, local.m_transform, style);
3664
0
      }
3665
0
    }
3666
3667
    // sometimes there is also a line to rely pts[5/8] and the text
3668
3669
0
    textOrigin=pts[3];
3670
    // TODO: use format for unit, ...
3671
0
    MWAWVec2f lineSz=pts[5]-pts[8];
3672
0
    std::stringstream s;
3673
0
    s << std::setprecision(0) << std::fixed << std::sqrt(lineSz[0]*lineSz[0]+lineSz[1]*lineSz[1]) << " pt";
3674
0
    text=s.str().c_str();
3675
0
  }
3676
  // TODO: use local style to define the text's color...
3677
0
  if (!text.empty())
3678
0
    send(listener, text, textOrigin, local.m_transform, MWAWFont(3,10), hasFrame);
3679
3680
0
  listener->closeGroup();
3681
0
  return true;
3682
0
}
3683
3684
namespace Canvas5GraphInternal
3685
{
3686
bool intersect(MWAWVec2f const &A, MWAWVec2f const &dirA, MWAWVec2f const &B, MWAWVec2f const &dirB, MWAWVec2f &pt)
3687
0
{
3688
0
  float cross=dirA[0]*dirB[1]-dirA[1]*dirB[0];
3689
0
  if (cross>-1e-9f && cross<1e-9f) return false;
3690
0
  MWAWVec2f AB=B-A;
3691
0
  float alpha=(AB[0]*dirB[1]-AB[1]*dirB[0])/cross;
3692
0
  pt=A+alpha*dirA;
3693
0
  return true;
3694
0
}
3695
3696
std::vector<MWAWVec2f> intersect(MWAWBox2f const &box, MWAWVec2f const &pt, MWAWVec2f const &dir)
3697
0
{
3698
0
  std::vector<MWAWVec2f> res;
3699
0
  for (int d=0; d<2; ++d) {
3700
0
    for (int wh=0; wh<2; ++wh) {
3701
0
      MWAWVec2f pts[]= {box[0],box[1]};
3702
0
      pts[1-wh][1-d]=pts[wh][1-d];
3703
0
      MWAWVec2f AB=pts[1]-pts[0];
3704
0
      float cross=AB[0]*dir[1]-AB[1]*dir[0];
3705
0
      if (cross>-1e-9f && cross<1e-9f) continue;
3706
0
      MWAWVec2f AO=pt-pts[0];
3707
0
      float alpha=(AO[0]*dir[1]-AO[1]*dir[0])/cross;
3708
0
      if (alpha<-1e-9f || alpha>1+1e-9f) continue;
3709
0
      if (alpha<0)
3710
0
        alpha=0;
3711
0
      else if (alpha>1)
3712
0
        alpha=1;
3713
0
      res.push_back((1-alpha)*pts[0]+alpha *pts[1]);
3714
0
    }
3715
0
  }
3716
0
  for (size_t i=0; i<res.size(); ++i) {
3717
0
    for (size_t j=i+1; j<res.size(); ++j) {
3718
0
      MWAWVec2f diff=res[j]-res[i];
3719
0
      if (diff[0]*diff[0]+diff[1]*diff[1]>1e-8f)
3720
0
        continue;
3721
0
      std::swap(res[j],res.back());
3722
0
      res.resize(res.size()-1);
3723
0
      --j;
3724
0
    }
3725
0
  }
3726
0
  if (res.size()!=2) {
3727
0
    MWAW_DEBUG_MSG(("Canvas5GraphInternal::intersect:: find %d intersections\n", int(res.size())));
3728
0
    return std::vector<MWAWVec2f>();
3729
0
  }
3730
0
  return res;
3731
0
}
3732
}
3733
bool Canvas5Graph::sendDimension9(MWAWListenerPtr listener, Canvas5GraphInternal::Shape const &/*shape*/,
3734
                                  Canvas5GraphInternal::ShapeData const &data, Canvas5Graph::LocalState const &local)
3735
0
{
3736
0
  if (!listener || !data.m_stream || version()<9) {
3737
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not find the listener\n"));
3738
0
    return false;
3739
0
  }
3740
0
  auto &stream=data.getStream();
3741
0
  auto input=stream.input();
3742
0
  auto const &entry=data.m_entry;
3743
0
  if (!entry.valid() || !input->checkPosition(entry.end())) {
3744
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not find the shape enntry\n"));
3745
0
    return false;
3746
0
  }
3747
3748
0
  libmwaw::DebugFile &ascFile = stream.ascii();
3749
0
  libmwaw::DebugStream f;
3750
0
  f << "Entries(Dimension):";
3751
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
3752
0
  long zoneSize=input->readLong(4);
3753
0
  if (zoneSize<0x796 || zoneSize>entry.end()) {
3754
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: can not read the zone size\n"));
3755
0
    f << "###sz";
3756
0
    ascFile.addPos(entry.begin());
3757
0
    ascFile.addNote(f.str().c_str());
3758
0
    return false;
3759
0
  }
3760
0
  int val=int(input->readLong(4)); // 4
3761
0
  if (val!=4) f << "f0=" << val << ",";
3762
0
  int type=int(input->readLong(1));
3763
0
  if (type) f << "type=" << type << ",";
3764
0
  input->seek(1, librevenge::RVNG_SEEK_CUR);
3765
0
  val=int(input->readLong(4)); // 1
3766
0
  if (val!=1) f << "f1=" << val << ",";
3767
0
  MWAWBox2f bdbox;
3768
0
  for (int i=0; i<2; ++i) {
3769
0
    float dims[2];
3770
    // fract type: between -2 and 2
3771
0
    for (auto &d : dims) d=float(m_mainParser->readDouble(stream,8));
3772
0
    ascFile.addDelimiter(input->tell(),'|');
3773
0
    if (i==0)
3774
0
      bdbox.setMin(MWAWVec2f(dims[0],dims[1]));
3775
0
    else
3776
0
      bdbox.setMax(MWAWVec2f(dims[0],dims[1]));
3777
0
  }
3778
0
  f << "box=" << bdbox << ",";
3779
0
  for (int i=0; i<2; ++i) {
3780
0
    val=int(input->readLong(4));
3781
0
    if (val)
3782
0
      f << "f" << i << "=" << val << ",";
3783
0
  }
3784
0
  long posi=input->tell();
3785
0
  int N=0;
3786
0
  bool finishedWithN=type!=4 && type!=7;
3787
0
  if (finishedWithN) {
3788
0
    input->seek(entry.end()-4, librevenge::RVNG_SEEK_SET);
3789
0
    ascFile.addDelimiter(input->tell(),'|');
3790
0
    N=int(input->readULong(4));
3791
0
    f << "N=" << N << ",";
3792
0
    input->seek(posi, librevenge::RVNG_SEEK_SET);
3793
0
  }
3794
0
  ascFile.addPos(entry.begin());
3795
0
  ascFile.addNote(f.str().c_str());
3796
3797
0
  for (int i=0; i<2; ++i) {
3798
0
    posi=input->tell();
3799
0
    f.str("");
3800
0
    f << "Dimension[" << (i==0 ? "prefix" : "suffix") << "]:";
3801
0
    std::string name;
3802
0
    for (int j=0; j<64; ++j) {
3803
0
      char c=char(input->readULong(1));
3804
0
      if (!c)
3805
0
        break;
3806
0
      name+=c;
3807
0
    }
3808
0
    if (!name.empty())
3809
0
      f << name << ",";
3810
0
    input->seek(posi+64, librevenge::RVNG_SEEK_SET);
3811
0
    val=int(input->readLong(4));
3812
0
    if (val)
3813
0
      f << "f0=" << val << ",";
3814
0
    ascFile.addPos(posi);
3815
0
    ascFile.addNote(f.str().c_str());
3816
0
  }
3817
0
  for (int i=0; i<12; ++i) {
3818
0
    posi=input->tell();
3819
0
    f.str("");
3820
0
    f << "Dimension[data" << i << "]:";
3821
0
    ascFile.addPos(posi);
3822
0
    ascFile.addNote(f.str().c_str());
3823
0
    input->seek(posi+(i<11 ? 128 : 112), librevenge::RVNG_SEEK_SET);
3824
0
  }
3825
3826
0
  posi=input->tell();
3827
0
  f.str("");
3828
0
  f << "Dimension[format]:";
3829
0
  int arrowType=3;
3830
0
  for (int i=0; i<8; ++i) { // f5=f6=3, f7=2
3831
0
    val=int(input->readLong(4));
3832
0
    int const expected[]= {0,0,0,0,0, 3,3,2};
3833
0
    if (val==expected[i]) continue;
3834
0
    if (i==5) {
3835
0
      arrowType=val;
3836
0
      f << "arrow=" << val << ","; // 0-3: none, inside, outside, auto
3837
0
    }
3838
0
    else if (i==7)
3839
0
      f << "witness[line]=" << val << ","; // 0-2: none, short, long
3840
0
    else
3841
0
      f << "f" << i << "=" << val << ",";
3842
0
  }
3843
0
  MWAWFont font;
3844
0
  f << "font=[";
3845
0
  font.setSize(float(m_mainParser->readDouble(stream, 8)));
3846
0
  val=int(input->readULong(4)); // 0
3847
0
  uint32_t flags = 0;
3848
0
  if (val&0x1) flags |= MWAWFont::boldBit;
3849
0
  if (val&0x2) flags |= MWAWFont::italicBit;
3850
0
  if (val&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
3851
0
  if (val&0x8) flags |= MWAWFont::embossBit;
3852
0
  if (val&0x10) flags |= MWAWFont::shadowBit;
3853
0
  if (val&0x80) font.setStrikeOutStyle(MWAWFont::Line::Simple);
3854
0
  font.setFlags(flags);
3855
0
  val &= 0xffffff60;
3856
0
  if (val)
3857
0
    f << "flag=" << std::hex << val << std::dec << ",";
3858
0
  std::string name;
3859
0
  for (int i=0; i<32; ++i) {
3860
0
    char c=char(input->readULong(1));
3861
0
    if (!c)
3862
0
      break;
3863
0
    name+=c;
3864
0
  }
3865
0
  auto fontConverter=m_parserState->m_fontConverter;
3866
0
  std::string const family=m_mainParser->isWindowsFile() ? "CP1252" : "";
3867
0
  if (!name.empty())
3868
0
    font.setId(fontConverter->getId(name, family));
3869
0
  f << font.getDebugString(fontConverter) << ",";
3870
0
  f << "],";
3871
0
  input->seek(posi+76, librevenge::RVNG_SEEK_SET);
3872
0
  ascFile.addPos(posi);
3873
0
  ascFile.addNote(f.str().c_str());
3874
3875
0
  posi=input->tell();
3876
0
  f.str("");
3877
0
  f << "Dimension[formatA]:";
3878
0
  for (int i=0; i<7; ++i) { // f2=-1|3, f4=1,
3879
0
    val=int(input->readLong(4));
3880
0
    if (!val)
3881
0
      continue;
3882
0
    if (i==2) // -1-20
3883
0
      f << "dimension=" << val << ",";
3884
0
    else if (i==5) {
3885
0
      if (val==1)
3886
0
        f << "use[secondary],";
3887
0
      else
3888
0
        f << "use[secondary]=" << val << ",";
3889
0
    }
3890
0
    else if (i==6) // 0-3
3891
0
      f << "tolerance=" << val << ",";
3892
0
    else
3893
0
      f << "f" << i << "=" << val << ",";
3894
0
  }
3895
0
  f << "unkn=["; // 0.05*3
3896
0
  for (int i=0; i<3; ++i)
3897
0
    f << m_mainParser->readDouble(stream, 8) << ",";
3898
0
  f << "],";
3899
0
  val=int(input->readLong(4)); // 0
3900
0
  if (val)
3901
0
    f << "f10=" << val << ",";
3902
0
  f << "unkn1=" << m_mainParser->readDouble(stream, 8) << ","; // 18
3903
0
  for (int i=0; i<2; ++i) {
3904
0
    val=int(input->readLong(4));
3905
0
    if (val==(i==0 ? 0 : 2)) continue;
3906
0
    if (i==1)
3907
0
      f << "digits=" << val << ",";
3908
0
    else
3909
0
      f << "g" << i << "=" << val << ",";
3910
0
  }
3911
0
  f << "displ[scaling]=" << m_mainParser->readDouble(stream, 8) << ","; // 1
3912
0
  for (int i=0; i<12; ++i) {
3913
0
    val=int(input->readLong(4));
3914
0
    if (val)
3915
0
      f << "g" << i+2 << "=" << val << ",";
3916
0
  }
3917
0
  ascFile.addPos(posi);
3918
0
  ascFile.addNote(f.str().c_str());
3919
3920
0
  posi=input->tell();
3921
0
  f.str("");
3922
0
  f << "Dimension[last,type=" << type << "]:";
3923
0
  if (type<1 || type>11) {
3924
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: unknown type\n"));
3925
0
    f << "###type=" << type << ",";
3926
0
    ascFile.addPos(posi);
3927
0
    ascFile.addNote(f.str().c_str());
3928
0
    return false;
3929
0
  }
3930
3931
0
  std::vector<MWAWVec2f> pts;
3932
0
  f << "unkn=[";
3933
0
  for (int i=0; i<((type==11||type==10) ? 2 : type==7 ? 3 : 4); ++i) {
3934
0
    float dim[2];
3935
0
    for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
3936
0
    pts.push_back(MWAWVec2f(dim[0], dim[1]));
3937
0
    f << pts.back() << ",";
3938
0
  }
3939
0
  f << "],";
3940
3941
0
  long remain=entry.end()-input->tell()-(finishedWithN ? 4 : 0);
3942
0
  switch (type) {
3943
0
  case 1: // simple
3944
0
    if (remain<0) {
3945
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[1]: can not read the last part\n"));
3946
0
      f << "###";
3947
0
      ascFile.addPos(posi);
3948
0
      ascFile.addNote(f.str().c_str());
3949
0
      return false;
3950
0
    }
3951
0
    break;
3952
0
  case 2: // array 1d <->|<->
3953
0
  case 3: { // array 1D
3954
0
    if (N<0 || remain/64<N+1 || remain<64*(N+1)+(type==2 ? 4 : 0)) {
3955
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[1]: can not read the last part\n"));
3956
0
      f << "###";
3957
0
      ascFile.addPos(posi);
3958
0
      ascFile.addNote(f.str().c_str());
3959
0
      return false;
3960
0
    }
3961
0
    f << "unk2=[";
3962
0
    for (int i=0; i<=N; ++i) {
3963
0
      f << "[";
3964
0
      for (int j=0; j<4; ++j) {
3965
0
        float dim[2];
3966
0
        for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
3967
0
        pts.push_back(MWAWVec2f(dim[0], dim[1]));
3968
0
        f << pts.back() << ",";
3969
0
      }
3970
0
      f << "],";
3971
0
    }
3972
0
    f << "],";
3973
0
    ascFile.addDelimiter(input->tell(),'|');
3974
0
    if (type==2) {
3975
0
      input->seek(entry.end()-8, librevenge::RVNG_SEEK_SET);
3976
0
      int direction=int(input->readULong(4));
3977
0
      f << "dir=" << direction << ","; // 1: hori, 2: verti, 0: all?
3978
0
      if (direction<0 || direction>2) {
3979
0
        MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[2]: unexpected direction\n"));
3980
0
        f << "###";
3981
0
      }
3982
0
    }
3983
0
    input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
3984
0
    break;
3985
0
  }
3986
0
  case 4: { // perpendicular line ...
3987
0
    if (remain<4 || (remain%16)!=4) {
3988
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[4]: can not read the last part\n"));
3989
0
      f << "###";
3990
0
      ascFile.addPos(posi);
3991
0
      ascFile.addNote(f.str().c_str());
3992
0
      return false;
3993
0
    }
3994
0
    val=int(input->readLong(4));
3995
0
    if (val)
3996
0
      f << "f0=" << val << ",";
3997
0
    int n=int(remain/16);
3998
0
    f << "unk2=[";
3999
0
    for (int i=0; i<n; ++i) { // then the line
4000
0
      float dim[2];
4001
0
      for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
4002
0
      pts.push_back(MWAWVec2f(dim[0], dim[1]));
4003
0
      f << pts.back() << ",";
4004
0
    }
4005
0
    f << "],";
4006
0
    break;
4007
0
  }
4008
  // case 5: side object (no data)
4009
0
  case 6: { // arc
4010
0
    if (remain!=48) {
4011
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[6]: can not read the last part\n"));
4012
0
      f << "###";
4013
0
      ascFile.addPos(posi);
4014
0
      ascFile.addNote(f.str().c_str());
4015
0
      return false;
4016
0
    }
4017
0
    f << "unk2=[";
4018
0
    for (int i=0; i<3; ++i) {
4019
0
      float dim[2];
4020
0
      for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
4021
0
      pts.push_back(MWAWVec2f(dim[0], dim[1]));
4022
0
      f << pts.back() << ",";
4023
0
    }
4024
0
    f << "],";
4025
0
    break;
4026
0
  }
4027
0
  case 7: // radius
4028
0
    if (remain!=40) {
4029
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[9]: can not read the last part\n"));
4030
0
      f << "###";
4031
0
      ascFile.addPos(posi);
4032
0
      ascFile.addNote(f.str().c_str());
4033
0
      return false;
4034
0
    }
4035
0
    input->seek(6, librevenge::RVNG_SEEK_CUR);
4036
0
    f << "unk2=[";
4037
0
    for (int i=0; i<2; ++i) {
4038
0
      float dim[2];
4039
0
      for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
4040
0
      pts.push_back(MWAWVec2f(dim[0], dim[1]));
4041
0
      f << pts.back() << ",";
4042
0
    }
4043
0
    f << "],";
4044
0
    val=int(input->readLong(2));
4045
0
    if (val)
4046
0
      f << "f0=" << val << ",";
4047
0
    break;
4048
  // case 8: diameter(no data)
4049
0
  case 9: // cross in circle
4050
0
    if (remain!=20) {
4051
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[9]: can not read the last part\n"));
4052
0
      f << "###";
4053
0
      ascFile.addPos(posi);
4054
0
      ascFile.addNote(f.str().c_str());
4055
0
      return false;
4056
0
    }
4057
0
    float dim[2];
4058
0
    for (auto &p : dim) p=float(m_mainParser->readDouble(stream, 8));
4059
0
    pts.push_back(MWAWVec2f(dim[0], dim[1]));
4060
0
    f << "unkn2=" << pts.back() << ","; // center?
4061
0
    val=int(input->readLong(4));
4062
0
    if (val)
4063
0
      f << "f0=" << val << ",";
4064
0
    break;
4065
  // case 10: inside area
4066
  // case 11: outside area
4067
0
  default:
4068
0
    break;
4069
0
  }
4070
0
  ascFile.addPos(posi);
4071
0
  ascFile.addNote(f.str().c_str());
4072
4073
0
  if (input->tell()+(finishedWithN ? 4 : 0)<entry.end()) {
4074
0
    MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: find extra data\n", type));
4075
0
    posi=input->tell();
4076
0
    f.str("");
4077
0
    f << "Dimension[end]:type=" << type << ",";
4078
0
    ascFile.addPos(posi);
4079
0
    ascFile.addNote(f.str().c_str());
4080
0
  }
4081
4082
0
  MWAWGraphicShape fShape;
4083
0
  MWAWBox2f shapeBox;
4084
0
  MWAWGraphicStyle style=local.m_style;
4085
0
  MWAWPosition pos;
4086
0
  pos.m_anchorTo = MWAWPosition::Page;
4087
4088
0
  listener->openGroup(local.m_position);
4089
0
  switch (type) {
4090
0
  case 1:
4091
0
  case 2:
4092
0
  case 3:
4093
0
  case 4:
4094
0
  case 5: {
4095
0
    if (type>=2 && type<=3 && pts.size()<12) {
4096
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems to small\n", type));
4097
0
      break;
4098
0
    }
4099
0
    else if (type==4 && pts.size()<6) {
4100
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems to small\n", type));
4101
0
      break;
4102
0
    }
4103
0
    int num=(type==1 || type==4 || type==5) ? 1 : int(pts.size()-8)/4;
4104
0
    for (int n=0; n<num; ++n) {
4105
0
      if (n>0) {
4106
0
        static bool first=true;
4107
0
        if (first) {
4108
0
          first=false;
4109
0
          MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: oops, do not know how to retrieve multi-dimension type=%d\n", type));
4110
0
        }
4111
#if 0
4112
        style.m_surfaceOpacity=0;
4113
        fShape=MWAWGraphicShape::rectangle(bdbox);
4114
        send(listener, fShape, local.m_transform, style);
4115
#endif
4116
0
        break;
4117
0
      }
4118
0
      MWAWVec2f v=pts[3]-pts[2];
4119
0
      MWAWVec2f dir(v[1], -v[0]);
4120
      // first border
4121
0
      style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
4122
0
      for (size_t i=0; i<2; ++i) {
4123
0
        std::vector<MWAWVec2f> points=Canvas5GraphInternal::intersect(bdbox, pts[i], dir);
4124
0
        if (points.size()!=2) continue;
4125
0
        fShape=MWAWGraphicShape::line(points[0],points[1]);
4126
0
        send(listener, fShape, local.m_transform, style);
4127
0
      }
4128
0
      MWAWVec2f points[2];
4129
0
      bool ok=true;
4130
0
      for (size_t j=0; j<2; ++j) {
4131
0
        if (Canvas5GraphInternal::intersect(pts[2],v, pts[j], dir, points[j]))
4132
0
          continue;
4133
0
        ok=true;
4134
0
        break;
4135
0
      }
4136
0
      if (!ok) continue;
4137
      // now the main arrow
4138
0
      MWAWVec2f u=pts[1]-pts[0];
4139
0
      bool outside=arrowType==2 || (arrowType!=1 && u[0]*u[0]+u[1]*u[1]<50*50);
4140
0
      if (outside) {
4141
0
        std::vector<MWAWVec2f> points2=Canvas5GraphInternal::intersect(bdbox, points[0], points[1]-points[0]);
4142
0
        if (points2.size()==2) {
4143
0
          MWAWVec2f dir0=points[1]-points[0];
4144
0
          MWAWVec2f dir1=points2[1]-points2[0];
4145
0
          if (dir0[0]*dir1[0]+dir0[1]*dir1[1]<0)
4146
0
            std::swap(points2[0],points2[1]);
4147
0
          if (arrowType!=0)
4148
0
            style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
4149
0
          for (size_t i=0; i<2; ++i) {
4150
0
            fShape=MWAWGraphicShape::line(points2[i],points[i]);
4151
0
            send(listener, fShape, local.m_transform, style);
4152
0
          }
4153
0
        }
4154
0
      }
4155
0
      else {
4156
0
        if (arrowType!=0)
4157
0
          style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
4158
0
        fShape=MWAWGraphicShape::line(points[0],points[1]);
4159
0
        send(listener, fShape, local.m_transform, style);
4160
0
      }
4161
4162
      // and the text
4163
0
      std::stringstream s;
4164
0
      s << std::setprecision(0) << std::fixed << std::sqrt(u[0]*u[0]+u[1]*u[1]) << " pt";
4165
0
      librevenge::RVNGString text=s.str().c_str();
4166
4167
0
      MWAWVec2f textOrigin=0.5f*(points[0]+points[1]);
4168
0
      send(listener, text, textOrigin, local.m_transform, font, false);
4169
0
    }
4170
0
    break;
4171
0
  }
4172
0
  case 6: {
4173
0
    if (pts.size()!=7) {
4174
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type));
4175
0
      break;
4176
0
    }
4177
0
    MWAWVec2f orig;
4178
0
    if (!Canvas5GraphInternal::intersect(pts[0],pts[1]-pts[0], pts[3],pts[3]-pts[2],orig)) {
4179
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, can not find the origin\n", type));
4180
0
      break;
4181
0
    }
4182
0
    float angles[2];
4183
0
    for (size_t i=0; i<2; ++i) {
4184
0
      MWAWVec2f dir=pts[1+2*i]-orig;
4185
0
      angles[i]=std::atan2(-dir[1],dir[0]);
4186
0
    }
4187
4188
0
    if (std::isnan(angles[0]) || std::isnan(angles[1])) {
4189
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[6]: can not compute the sector angle\n"));
4190
0
    }
4191
0
    else {
4192
0
      MWAWVec2f dir=pts[5]-orig;
4193
0
      float radius=std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]);
4194
0
      std::swap(angles[0],angles[1]);
4195
0
      MWAWBox2f circleBox(MWAWVec2f(orig[0]-radius, orig[1]-radius),MWAWVec2f(orig[0]+radius, orig[1]+radius));
4196
4197
      // we must compute the arc box
4198
0
      float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
4199
0
      int limitAngle[2];
4200
0
      for (int i = 0; i < 2; ++i)
4201
0
        limitAngle[i] = (angles[i] < 0) ? int(2*angles[i]/float(M_PI))-1 : int(2*angles[i]/float(M_PI));
4202
0
      for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) {
4203
0
        float ang = (bord == limitAngle[0]) ? float(angles[0]) :
4204
0
                    (bord == limitAngle[1]+1) ? float(angles[1]) : float(M_PI/2*bord);
4205
0
        float const actVal[2] = { std::cos(ang), -std::sin(ang)};
4206
0
        if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
4207
0
        else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
4208
0
        if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
4209
0
        else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
4210
0
      }
4211
0
      MWAWBox2f arcBox(MWAWVec2f(orig[0]+minVal[0]*radius, orig[1]+minVal[1]*radius),MWAWVec2f(orig[0]+maxVal[0]*radius, orig[1]+maxVal[1]*radius));
4212
0
      fShape = MWAWGraphicShape::pie(arcBox, circleBox, MWAWVec2f(float(180/M_PI)*angles[0], float(180/M_PI)*angles[1]));
4213
0
      send(listener, fShape, local.m_transform, style);
4214
0
    }
4215
    // and the text
4216
0
    std::stringstream s;
4217
0
    s << std::setprecision(2) << std::fixed << float(180/M_PI)*(angles[1]-angles[0]) << " ";
4218
0
    librevenge::RVNGString text=s.str().c_str();
4219
4220
0
    send(listener, text, pts[5], local.m_transform, font, false);
4221
0
    break;
4222
0
  }
4223
0
  case 7: {
4224
0
    if (pts.size()!=5) {
4225
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type));
4226
0
      break;
4227
0
    }
4228
0
    fShape=MWAWGraphicShape::line(pts[1],pts[2]);
4229
0
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
4230
0
    send(listener, fShape, local.m_transform, style);
4231
0
    fShape=MWAWGraphicShape::line(pts[0],pts[1]);
4232
0
    if (arrowType!=0)
4233
0
      style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
4234
0
    send(listener, fShape, local.m_transform, style);
4235
    // and the text
4236
0
    std::stringstream s;
4237
0
    MWAWVec2f dir=pts[2]-pts[0];
4238
0
    s << std::setprecision(0) << std::fixed << std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]) << " pt";
4239
0
    librevenge::RVNGString text=s.str().c_str();
4240
0
    send(listener, text, pts[1], local.m_transform, font, false);
4241
0
    break;
4242
0
  }
4243
0
  case 8: {
4244
0
    if (pts.size()!=4) {
4245
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type));
4246
0
      break;
4247
0
    }
4248
0
    fShape=MWAWGraphicShape::line(pts[0],pts[1]);
4249
0
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
4250
0
    send(listener, fShape, local.m_transform, style);
4251
0
    fShape=MWAWGraphicShape::line(pts[0],pts[2]);
4252
0
    if (arrowType!=0)
4253
0
      style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
4254
0
    send(listener, fShape, local.m_transform, style);
4255
    // and the text
4256
0
    std::stringstream s;
4257
0
    MWAWVec2f dir=pts[2]-pts[0];
4258
0
    s << std::setprecision(0) << std::fixed << std::sqrt(dir[0]*dir[0]+dir[1]*dir[1]) << " pt";
4259
0
    librevenge::RVNGString text=s.str().c_str();
4260
0
    send(listener, text, pts[1], local.m_transform, font, false);
4261
0
    break;
4262
0
  }
4263
0
  case 9: // 0 is the center
4264
0
    if (pts.size()!=5) {
4265
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9[%d]: sorry, the number of points seems bad\n", type));
4266
0
      break;
4267
0
    }
4268
0
    style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow();
4269
0
    fShape=MWAWGraphicShape::line(pts[1],pts[2]);
4270
0
    send(listener, fShape, local.m_transform, style);
4271
0
    fShape=MWAWGraphicShape::line(pts[3],pts[4]);
4272
0
    send(listener, fShape, local.m_transform, style);
4273
0
    break;
4274
0
  case 10:
4275
0
  case 11: {
4276
0
    static bool first=true;
4277
0
    if (first) {
4278
0
      first=false;
4279
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: sorry, sending area dimension of type=%d is not implemented\n", type));
4280
0
    }
4281
0
    break;
4282
0
  }
4283
0
  default:
4284
0
    static bool first=true;
4285
0
    if (first) {
4286
0
      first=false;
4287
0
      MWAW_DEBUG_MSG(("Canvas5Graph::sendDimension9: sorry, sending dimension of type=%d is not implemented\n", type));
4288
0
    }
4289
0
    break;
4290
0
  }
4291
0
  listener->closeGroup();
4292
0
  return true;
4293
0
}
4294
4295
////////////////////////////////////////////////////////////
4296
// auxilliary structure
4297
////////////////////////////////////////////////////////////
4298
4299
void Canvas5Graph::LocalState::multiplyMatrix(std::array<double, 9> const &mat)
4300
0
{
4301
0
  if (mat[8]>=-1e-3 && mat[8]<=1e-3) {
4302
    // checkme: this seems possible, unsure what this means ?
4303
0
    static bool first=true;
4304
0
    if (first) {
4305
0
      first=false;
4306
0
      MWAW_DEBUG_MSG(("Canvas5Graph::LocalState::multiplyMatrix: find some matrix with mat[3][3]=0\n"));
4307
0
    }
4308
0
  }
4309
0
  if (mat[2]<-1e-3 || mat[2]>1e-3 || mat[5]<-1e-3 || mat[5]>1e-3) {
4310
0
    MWAW_DEBUG_MSG(("Canvas5Graph::LocalState::multiplyMatrix: projection will be ignored\n"));
4311
0
    return;
4312
0
  }
4313
0
  m_transform*=MWAWTransformation(MWAWVec3f((float)mat[0], (float)mat[3], (float)mat[6]), MWAWVec3f((float)mat[1], (float)mat[4], (float)mat[7]));
4314
0
}
4315
4316
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: