Coverage Report

Created: 2026-10-28 06:34

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