Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/Canvas5Image.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
#ifdef DEBUG_WITH_FILES
47
#  define DEBUG_CANVAS_VKFL
48
#endif
49
50
#ifdef DEBUG_CANVAS_VKFL
51
#  include "MWAWGraphicEncoder.hxx"
52
#endif
53
#include "MWAWGraphicListener.hxx"
54
#include "MWAWGraphicShape.hxx"
55
#include "MWAWGraphicStyle.hxx"
56
#include "MWAWListener.hxx"
57
#include "MWAWParser.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 Canvas5Image */
69
namespace Canvas5ImageInternal
70
{
71
//! Internal: the stroke style of a Canvas5Image
72
struct Stroke {
73
  //! constructor
74
  Stroke()
75
0
    : m_type(1)
76
0
    , m_penPos(-1)
77
0
    , m_dashPos(-1)
78
0
  {
79
0
    for (auto &id : m_arrowPos) id=-1;
80
0
  }
81
  //! the type
82
  unsigned m_type;
83
  //! the pen id
84
  long m_penPos;
85
  //! the dash id
86
  long m_dashPos;
87
  //! the arrow id (beg/end)
88
  long m_arrowPos[2];
89
};
90
91
////////////////////////////////////////
92
//! Internal: the internal shape of a Canvas5Image
93
struct VKFLShape {
94
  //! constructor
95
  VKFLShape()
96
0
    : m_type(-1)
97
0
    , m_subType(0)
98
0
    , m_box()
99
0
    , m_idToDataPos()
100
0
    , m_style()
101
102
0
    , m_vertices()
103
0
    , m_bitmap()
104
0
    , m_bitmapColor(MWAWColor::white())
105
106
0
    , m_special()
107
0
    , m_macoImage()
108
0
  {
109
0
    for (auto &v : m_locals) v=0;
110
0
  }
111
  static std::string getTypeName(int type)
112
0
  {
113
0
    switch (type) {
114
0
    case -1:
115
0
      return "";
116
0
    case 1:
117
0
      return "poly";
118
0
    case 2:
119
0
      return "spline";
120
0
    case 6:
121
0
      return "rect";
122
0
    case 7:
123
0
      return "circle";
124
0
    case 8:
125
0
      return "rectOval";
126
0
    case 9:
127
0
      return "line";
128
0
    case 10:
129
0
      return "arc";
130
0
    case 11:
131
0
      return "group";
132
0
    case 12: // a group for ???
133
0
      return "group1";
134
0
    case 14:
135
0
      return "special";
136
0
    default:
137
0
      return Canvas5Structure::getString(unsigned(type));
138
0
    }
139
0
  }
140
  //! the type
141
  int m_type;
142
  //! the sub type
143
  unsigned m_subType;
144
  //! the dimension
145
  MWAWBox2f m_box;
146
  //! the map id(type) to data pos in the main zone
147
  std::map<int, long> m_idToDataPos;
148
  //! the graphic style
149
  MWAWGraphicStyle m_style;
150
151
  //! the vertices: spline, poly, ...
152
  std::vector<MWAWVec2f> m_vertices;
153
  //! the local values : arc=>angles, rectOval=>oval size
154
  float m_locals[2];
155
  //! the bitmap
156
  MWAWEmbeddedObject m_bitmap;
157
  //! the bitmap color
158
  MWAWColor m_bitmapColor;
159
  //! a graph pseudo box: special
160
  std::shared_ptr<Canvas5GraphInternal::PseudoShape> m_special;
161
  //! a macro image : special
162
  std::shared_ptr<VKFLImage> m_macoImage;
163
};
164
165
//! Internal: the internal image of a Canvas5Image
166
struct VKFLImage {
167
  //! constructor
168
  VKFLImage()
169
0
    : m_data()
170
0
    , m_shapes()
171
172
0
    , m_posToTypesMap()
173
174
0
    , m_posToArrowMap()
175
0
    , m_posToColorMap()
176
0
    , m_posToDashMap()
177
0
    , m_posToMatrixMap()
178
0
    , m_posToPenMap()
179
0
    , m_posToStrokeMap()
180
0
  {
181
0
    for (auto &box : m_boxes) box=MWAWBox2f();
182
0
    for (auto &mat : m_matrices) mat=std::array<double,9>();
183
0
  }
184
  //! the data entry
185
  MWAWEntry m_data[2];
186
  //! the list of shape
187
  std::vector<VKFLShape> m_shapes;
188
  //! the dimensions
189
  MWAWBox2f m_boxes[2];
190
  //! the transformations
191
  std::array<double,9> m_matrices[2];
192
193
  //! the map pos to type and sub type
194
  std::map<long, std::pair<unsigned, unsigned> > m_posToTypesMap;
195
196
  //! the position to arrow map
197
  std::map<long, MWAWGraphicStyle::Arrow> m_posToArrowMap;
198
  //! the position to color map
199
  std::map<long, std::shared_ptr<Canvas5StyleManagerInternal::ColorStyle> > m_posToColorMap;
200
  //! the position to dash map
201
  std::map<long, std::vector<float> > m_posToDashMap;
202
  //! the position to matrix map
203
  std::map<long, std::array<double,9> > m_posToMatrixMap;
204
  //! the position to pen map
205
  std::map<long, std::shared_ptr<Canvas5StyleManagerInternal::PenStyle> > m_posToPenMap;
206
  //! the position to stroke map
207
  std::map<long, Stroke> m_posToStrokeMap;
208
};
209
210
////////////////////////////////////////
211
//! Internal: the state of a Canvas5Image
212
struct State {
213
  //! constructor
214
  State()
215
6.47k
    : m_idToObject()
216
6.47k
    , m_idToGIF()
217
6.47k
    , m_idToMACO()
218
6.47k
    , m_idToQkTm()
219
6.47k
  {
220
6.47k
  }
221
222
  //! the map id to bitmap
223
  std::map<int, MWAWEmbeddedObject> m_idToObject;
224
  //! the map id to git
225
  std::map<int, std::shared_ptr<VKFLImage> > m_idToGIF;
226
  //! the map id to maco
227
  std::map<std::vector<unsigned>, std::shared_ptr<VKFLImage> > m_idToMACO;
228
  //! the map id to quicktime
229
  std::map<int, librevenge::RVNGBinaryData> m_idToQkTm;
230
};
231
232
}
233
234
////////////////////////////////////////////////////////////
235
// constructor/destructor, ...
236
////////////////////////////////////////////////////////////
237
Canvas5Image::Canvas5Image(Canvas5Parser &parser)
238
6.47k
  : m_parserState(parser.getParserState())
239
6.47k
  , m_state(new Canvas5ImageInternal::State)
240
6.47k
  , m_mainParser(&parser)
241
6.47k
{
242
6.47k
}
243
244
Canvas5Image::~Canvas5Image()
245
6.47k
{
246
6.47k
}
247
248
int Canvas5Image::version() const
249
0
{
250
0
  return m_parserState->m_version;
251
0
}
252
253
std::shared_ptr<Canvas5StyleManager> Canvas5Image::getStyleManager() const
254
0
{
255
0
  return m_mainParser->m_styleManager;
256
0
}
257
258
bool Canvas5Image::getBitmap(int bitmapId, MWAWEmbeddedObject &object)
259
0
{
260
0
  auto const &pIt=m_state->m_idToObject.find(bitmapId);
261
0
  if (pIt==m_state->m_idToObject.end()) {
262
0
    MWAW_DEBUG_MSG(("Canvas5Image::getBitmap: can not find bitmap %d\n", bitmapId));
263
0
    return false;
264
0
  }
265
0
  object=pIt->second;
266
0
  return true;
267
0
}
268
269
std::shared_ptr<Canvas5ImageInternal::VKFLImage> Canvas5Image::getGIF(int gifId)
270
0
{
271
0
  auto const &pIt=m_state->m_idToGIF.find(gifId);
272
0
  if (pIt==m_state->m_idToGIF.end()) {
273
0
    MWAW_DEBUG_MSG(("Canvas5Image::getGIF: can not find GIF %d\n", gifId));
274
0
    return nullptr;
275
0
  }
276
0
  return pIt->second;
277
0
}
278
279
std::shared_ptr<Canvas5ImageInternal::VKFLImage> Canvas5Image::getMACO(std::vector<unsigned> const &macoId)
280
0
{
281
0
  auto const &pIt=m_state->m_idToMACO.find(macoId);
282
0
  if (pIt==m_state->m_idToMACO.end()) {
283
0
    MWAW_DEBUG_MSG(("Canvas5Image::getMACO: can not find a MACO picture\n"));
284
0
    return nullptr;
285
0
  }
286
0
  return pIt->second;
287
0
}
288
289
bool Canvas5Image::getQuickTime(int quicktimeId, MWAWEmbeddedObject &object)
290
0
{
291
0
  object=MWAWEmbeddedObject();
292
0
  auto const &qIt=m_state->m_idToQkTm.find(quicktimeId);
293
0
  if (qIt==m_state->m_idToQkTm.end()) {
294
0
    MWAW_DEBUG_MSG(("Canvas5Image::getBitmap: can not find quicktime %d\n", quicktimeId));
295
0
    return false;
296
0
  }
297
0
  object.add(qIt->second, "video/quicktime");
298
0
  return true;
299
0
}
300
301
////////////////////////////////////////////////////////////
302
//
303
// Intermediate level
304
//
305
////////////////////////////////////////////////////////////
306
307
////////////////////////////////////////////////////////////
308
// bitmap
309
////////////////////////////////////////////////////////////
310
311
bool Canvas5Image::readImages(std::shared_ptr<Canvas5Structure::Stream> stream)
312
0
{
313
0
  if (!stream || !stream->input()) return false;
314
0
  auto input=stream->input();
315
316
0
  long pos=input->tell();
317
0
  if (!input->checkPosition(pos+4)) {
318
0
    MWAW_DEBUG_MSG(("Canvas5Image::readImages: the zone is too short\n"));
319
0
    return false;
320
0
  }
321
322
0
  libmwaw::DebugFile &ascFile = stream->ascii();
323
0
  ascFile.addPos(pos);
324
0
  ascFile.addNote("Entries(BitmDef):");
325
0
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
326
327
0
  std::vector<bool> defined;
328
0
  if (!m_mainParser->readDefined(*stream, defined, "BitmDef"))
329
0
    return false;
330
331
  // find list of 2bb73XXX, always multiple of 4 some auto ref ?
332
0
  std::vector<unsigned long> unknowns;
333
0
  if (!m_mainParser->readExtendedHeader(stream, 4, "BitmDef",
334
0
  [&unknowns](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &, std::string const &) {
335
0
  auto lInput=lStream->input();
336
0
    unknowns.push_back(lInput->readULong(4));
337
0
  }))
338
0
  return false;
339
340
0
  size_t w=0;
341
0
  int const vers=version();
342
0
  for (size_t i=0; i<defined.size(); ++i) {
343
0
    if (!defined[i]) continue;
344
0
    if (w>=unknowns.size())
345
0
      break;
346
0
    if (unknowns[w++]==0) continue;
347
0
    MWAWEmbeddedObject object;
348
0
    if (!Canvas5Structure::readBitmapDAD58Bim(*stream, vers, object))
349
0
      return false;
350
0
    m_state->m_idToObject[int(i+1)]=object;
351
0
  }
352
0
  return true;
353
0
}
354
355
bool Canvas5Image::readImages9(std::shared_ptr<Canvas5Structure::Stream> stream)
356
0
{
357
0
  if (!stream || !stream->input()) return false;
358
359
0
  auto input=stream->input();
360
0
  auto &ascFile=stream->ascii();
361
0
  int const vers=version();
362
0
  long pos=input->tell();
363
0
  if (!input->checkPosition(pos+8)) {
364
0
    MWAW_DEBUG_MSG(("Canvas5Image::readImages9: the zone is too short\n"));
365
0
    return false;
366
0
  }
367
0
  libmwaw::DebugStream f;
368
0
  f << "Entries(Image):";
369
0
  int val=int(input->readLong(4));
370
0
  if (val!=3)
371
0
    f << "f0=" << val << ",";
372
0
  int N=int(input->readLong(4));
373
0
  f << "N=" << N << ",";
374
0
  ascFile.addPos(pos);
375
0
  ascFile.addNote(f.str().c_str());
376
377
0
  for (int i=0; i<N; ++i) {
378
0
    pos=input->tell();
379
0
    f.str("");
380
0
    f << "Image-B" << i+1 << ":";
381
0
    std::string name;
382
0
    int type;
383
0
    if (!m_mainParser->getTAG9(*stream, name, type) || type!=0) {
384
0
      MWAW_DEBUG_MSG(("Canvas5Image::readImages9: can not find the image tag\n"));
385
0
      f << "###";
386
0
      ascFile.addPos(pos);
387
0
      ascFile.addNote(f.str().c_str());
388
0
      return false;
389
0
    }
390
0
    f << "name=" << name << ",";
391
0
    if (!input->checkPosition(input->tell()+4)) {
392
0
      MWAW_DEBUG_MSG(("Canvas5Image::readImages9: the zone seems too short\n"));
393
0
      f << "###";
394
0
      ascFile.addPos(pos);
395
0
      ascFile.addNote(f.str().c_str());
396
0
      return false;
397
0
    }
398
0
    int id=int(input->readLong(4));
399
0
    f << "id=" << id << ",";
400
0
    ascFile.addPos(pos);
401
0
    ascFile.addNote(f.str().c_str());
402
0
    MWAWEmbeddedObject object;
403
0
    if (!Canvas5Structure::readBitmapDAD58Bim(*stream, vers, object))
404
0
      return false;
405
0
    if (m_state->m_idToObject.find(i+1) != m_state->m_idToObject.end()) {
406
0
      MWAW_DEBUG_MSG(("Canvas5Image::readImages9: id=%d already exists\n", i+1));
407
0
    }
408
0
    else
409
0
      m_state->m_idToObject[i+1]=object;
410
0
    if (!m_mainParser->checkTAG9(*stream, name, 1)) {
411
0
      MWAW_DEBUG_MSG(("Canvas5Image::readImages9: can not find the image tag\n"));
412
0
      ascFile.addPos(input->tell());
413
0
      ascFile.addNote("Image:###");
414
0
      return false;
415
0
    }
416
0
  }
417
0
  return true;
418
0
}
419
420
////////////////////////////////////////////////////////////
421
// macros
422
////////////////////////////////////////////////////////////
423
bool Canvas5Image::readMacroIndent(Canvas5Structure::Stream &stream, std::vector<unsigned> &id, std::string &extra)
424
0
{
425
0
  id.clear();
426
427
0
  auto input=stream.input();
428
0
  long pos=input ? input->tell() : 0;
429
430
0
  if (!input || !input->checkPosition(pos+20)) {
431
0
    MWAW_DEBUG_MSG(("Canvas5Image::readMacroIndent: can not read first MACO value\n"));
432
0
    extra="###";
433
0
    return false;
434
0
  }
435
436
0
  std::stringstream s;
437
0
  for (int k=0; k<8; ++k) { // f0,f1,f2: a date, f3,f4,f5: hour?
438
0
    unsigned val=unsigned(input->readULong(2));
439
0
    unsigned const expected[]= {1998,10,5,14,0,0,2,1100};
440
441
0
    if (k>=0 && k<=6)
442
0
      id.push_back(val);
443
0
    if (val==expected[k]) continue;
444
0
    if (k==7)
445
0
      s << "fl=" << std::hex << val << std::dec << ",";
446
0
    else
447
0
      s << "f" << k << "=" << val << ",";
448
0
  }
449
0
  int val=int(input->readLong(4));
450
0
  if (val)
451
0
    s << "id=" << val << ",";
452
0
  extra=s.str();
453
0
  return true;
454
0
}
455
456
bool Canvas5Image::readMACORsrc(std::shared_ptr<Canvas5Structure::Stream> stream)
457
0
{
458
0
  if (!stream) {
459
0
    MWAW_DEBUG_MSG(("Canvas5Parser::readMACORsrc: no stream\n"));
460
0
    return false;
461
0
  }
462
0
  auto input=stream->input();
463
0
  long pos=input ? input->tell() : 0;
464
0
  int const vers=version();
465
0
  auto &ascFile=stream->ascii();
466
0
  libmwaw::DebugStream f;
467
0
  f << "Entries(Macros):";
468
0
  if (!input || !input->checkPosition(pos+4)) {
469
0
    MWAW_DEBUG_MSG(("Canvas5Parser::readMACORsrc: can not read first MACO value\n"));
470
0
    f << "###";
471
0
    ascFile.addPos(pos);
472
0
    ascFile.addNote(f.str().c_str());
473
0
    return false;
474
0
  }
475
0
  int val=int(input->readULong(4));
476
0
  if (val!=0x77cc) f << "f0=" << std::hex << val << std::dec << ",";
477
0
  ascFile.addPos(pos);
478
0
  ascFile.addNote(f.str().c_str());
479
0
  if (input->isEnd())
480
0
    return true;
481
482
  // 32: name, dim, last part of DataShap Maco, another dim
483
0
  std::map<int, std::vector<unsigned> > idToUniqueIdMap;
484
0
  std::set<std::vector<unsigned> > uniqueIdSet;
485
0
  if (!m_mainParser->readExtendedHeader(stream, vers>=9 ? 0x80 : 0x58, "Macros",
486
0
  [this, vers, &idToUniqueIdMap, &uniqueIdSet](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) {
487
0
  auto lInput=lStream->input();
488
0
    libmwaw::DebugFile &asciiFile = lStream->ascii();
489
0
    long lPos=lInput->tell();
490
0
    libmwaw::DebugStream lF;
491
0
    std::string name;
492
0
    for (int i=0; i<32; ++i) {
493
0
      char c=char(lInput->readULong(1));
494
0
      if (!c)
495
0
        break;
496
0
      name+=c;
497
0
    }
498
0
    lF << name << ",";
499
0
    lInput->seek(lPos+32, librevenge::RVNG_SEEK_SET);
500
0
    for (int i=0; i<(vers<9 ? 2 : 4); ++i) { // checkme is g0 related to endian ordering?
501
0
      int lVal=int(lInput->readLong(2));
502
0
      if (lVal)
503
0
        lF << "g" << i << "=" << lVal << ",";
504
0
    }
505
0
    if (vers>=9) {
506
0
      double dim[4];
507
0
      bool isNan;
508
0
      for (auto &d : dim) {
509
0
        long actPos=lInput->tell();
510
0
        if (m_mainParser->readDouble(*lStream, d, isNan)) continue;
511
0
        d=0;
512
0
        lF << "###";
513
0
        lInput->seek(actPos+8, librevenge::RVNG_SEEK_SET);
514
0
      }
515
0
      lF << "box=" << MWAWBox2f(MWAWVec2f((float) dim[0], (float) dim[1]),
516
0
                                MWAWVec2f((float) dim[2], (float) dim[3])) << ",";
517
0
      std::vector<unsigned> mId;
518
0
      std::string extra;
519
520
0
      if (!readMacroIndent(*lStream, mId, extra) || uniqueIdSet.find(mId)!=uniqueIdSet.end()) {
521
0
        MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: oops, find multiple unique id\n"));
522
0
        lF << "###";
523
0
        lInput->seek(lPos+32+8+32+20, librevenge::RVNG_SEEK_SET);
524
0
      }
525
0
      else {
526
0
        idToUniqueIdMap[item.m_id]=mId;
527
0
        uniqueIdSet.insert(mId);
528
0
      }
529
0
      int lVal=int(lInput->readLong(4));
530
0
      if (lVal)
531
0
        lF << "g4=" << lVal << ",";
532
0
      for (auto &d : dim) {
533
0
        long actPos=lInput->tell();
534
0
        if (m_mainParser->readDouble(*lStream, d, isNan)) continue;
535
0
        d=0;
536
0
        lF << "###";
537
0
        lInput->seek(actPos+8, librevenge::RVNG_SEEK_SET);
538
0
      }
539
0
      lF << "box2=" << MWAWBox2f(MWAWVec2f((float) dim[0], (float) dim[1]),
540
0
                                 MWAWVec2f((float) dim[2], (float) dim[3])) << ",";
541
0
      asciiFile.addPos(item.m_pos);
542
0
      asciiFile.addNote(lF.str().c_str());
543
0
      return ;
544
0
    }
545
0
    float fDim[4];
546
0
    for (auto &d : fDim) d=float(lInput->readULong(4))/65536.f;
547
0
    lF << "box=" << MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]), MWAWVec2f(fDim[2], fDim[3])) << ",";
548
549
0
    std::vector<unsigned> mId;
550
0
    std::string extra;
551
552
0
    if (!readMacroIndent(*lStream, mId, extra) || uniqueIdSet.find(mId)!=uniqueIdSet.end()) {
553
0
      MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: oops, find multiple unique id\n"));
554
0
      lF << "###";
555
0
      lInput->seek(lPos+32+20+20, librevenge::RVNG_SEEK_SET);
556
0
    }
557
0
    else {
558
0
      idToUniqueIdMap[item.m_id]=mId;
559
0
      uniqueIdSet.insert(mId);
560
0
    }
561
0
    for (auto &d : fDim) d=float(lInput->readULong(4))/65536.f;
562
0
    lF << "box2=" << MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]), MWAWVec2f(fDim[2], fDim[3])) << ",";
563
0
    asciiFile.addPos(item.m_pos);
564
0
    asciiFile.addNote(lF.str().c_str());
565
0
  })) {
566
0
    return false;
567
0
  }
568
0
  if (input->isEnd())
569
0
    return true;;
570
0
  if (!m_mainParser->readIndexMap(stream, "Macros",
571
0
  [this, &idToUniqueIdMap](std::shared_ptr<Canvas5Structure::Stream> lStream, Canvas5Parser::Item const &item, std::string const &) {
572
0
  std::shared_ptr<Canvas5ImageInternal::VKFLImage> image;
573
0
  if (!readVKFL(lStream, item.m_length, image)) return;
574
0
    auto it=idToUniqueIdMap.find(item.m_id);
575
0
    if (it==idToUniqueIdMap.end()) {
576
0
      MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: oops, can not find an unique id for %d\n", item.m_id));
577
0
    }
578
0
    else
579
0
      m_state->m_idToMACO[it->second]=image;
580
0
  })) { // vkfl
581
0
    MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: can not read the first data value\n"));
582
0
    return false;
583
0
  }
584
0
  if (input->isEnd())
585
0
    return true;
586
0
  if (!m_mainParser->readUsed(*stream, "Macros")) {
587
0
    MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: can not read the used value\n"));
588
0
    return false;
589
0
  }
590
0
  pos=input->tell();
591
0
  f.str("");
592
0
  f << "Macros-F:";
593
0
  int N;
594
0
  if (!m_mainParser->readDataHeader(*stream, 0x14,N)) {
595
0
    MWAW_DEBUG_MSG(("Canvas5Image::readMACORsrc: can not read the last data value\n"));
596
0
    f << "###";
597
0
    ascFile.addPos(pos);
598
0
    ascFile.addNote(f.str().c_str());
599
0
    return false;
600
0
  }
601
0
  ascFile.addPos(pos);
602
0
  ascFile.addNote(f.str().c_str());
603
0
  for (int j=0; j<N; ++j) {
604
0
    pos=input->tell();
605
0
    f.str("");
606
0
    f << "Macros-F" << j << ":";
607
0
    std::vector<unsigned> mId;
608
0
    std::string extra;
609
0
    readMacroIndent(*stream, mId, extra);
610
0
    f << extra << ",";
611
0
    ascFile.addPos(pos);
612
0
    ascFile.addNote(f.str().c_str());
613
0
    input->seek(pos+0x14, librevenge::RVNG_SEEK_SET);
614
0
  }
615
616
0
  return true;
617
0
}
618
619
620
////////////////////////////////////////////////////////////
621
//
622
// VKFL
623
//
624
////////////////////////////////////////////////////////////
625
626
bool Canvas5Image::readAGIFRsrc(std::shared_ptr<Canvas5Structure::Stream> stream)
627
0
{
628
0
  if (!stream || !stream->input())
629
0
    return false;
630
0
  auto input=stream->input();
631
0
  long pos=input->tell();
632
0
  libmwaw::DebugStream f;
633
0
  auto &ascFile=stream->ascii();
634
0
  f << "RsrcAGIF:";
635
636
0
  if (!input->checkPosition(pos+56)) {
637
0
    MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: the zone seems too short\n"));
638
0
    f << "###";
639
0
    ascFile.addPos(pos);
640
0
    ascFile.addNote(f.str().c_str());
641
0
    return false;
642
0
  }
643
644
0
  int val=int(input->readLong(4));
645
0
  if (val!=2)
646
0
    f << "f0=" << val << ",";
647
0
  int N=int(input->readULong(4));
648
0
  f << "N=" << N << ",";
649
0
  if (N<1) {
650
0
    MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: the N value seems bad\n"));
651
0
    f << "###";
652
0
    ascFile.addPos(pos);
653
0
    ascFile.addNote(f.str().c_str());
654
0
    return false;
655
0
  }
656
0
  ascFile.addPos(pos);
657
0
  ascFile.addNote(f.str().c_str());
658
659
0
  for (int z=0; z<N; ++z) {
660
0
    pos=input->tell();
661
0
    f.str("");
662
0
    f << "RsrcAGIF" << z << ":";
663
664
0
    if (!input->checkPosition(pos+4)) {
665
0
      MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: the zone %d seems too short\n", z));
666
0
      f << "###";
667
0
      ascFile.addPos(pos);
668
0
      ascFile.addNote(f.str().c_str());
669
0
      return false;
670
0
    }
671
0
    val=int(input->readLong(4));
672
0
    if (val==0) {
673
0
      ascFile.addPos(pos);
674
0
      ascFile.addNote(f.str().c_str());
675
0
      continue;
676
0
    }
677
0
    if (val!=1 || !input->checkPosition(pos+20)) {
678
0
      MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: find unknown identifier for the sub zone %d\n", z));
679
0
      f << "###id=" << val << ",";
680
0
      ascFile.addPos(pos);
681
0
      ascFile.addNote(f.str().c_str());
682
0
      return false;
683
0
    }
684
0
    int N0=1;
685
0
    for (int i=0; i<4; ++i) {
686
0
      val=int(input->readLong(4));
687
0
      if (val==1) continue;
688
0
      if (i==1) {
689
0
        N0=val;
690
0
        f << "N[subZ]=" << N0 << ",";
691
0
      }
692
0
      else
693
0
        f << "f" << i << "=" << val << ",";
694
0
    }
695
696
0
    ascFile.addPos(pos);
697
0
    ascFile.addNote(f.str().c_str());
698
0
    for (int s=0; s<N0; ++s) {
699
0
      pos=input->tell();
700
0
      f.str("");
701
0
      f << "RsrcAGIF" << z << "-" << s << ":";
702
0
      if (!input->checkPosition(pos+24)) {
703
0
        MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: the sub zone %d-%d seems too short\n", z, s));
704
0
        f << "###";
705
0
        ascFile.addPos(pos);
706
0
        ascFile.addNote(f.str().c_str());
707
0
        return false;
708
0
      }
709
0
      val=int(input->readULong(4));
710
0
      if (val!=0)
711
0
        f << "unkn=" << std::hex << val << std::dec << ",";
712
0
      val=int(input->readULong(4));
713
0
      long len=long(input->readULong(4));
714
0
      if (val!=0x3e23d70a || pos+24+len<pos+24 || !input->checkPosition(pos+24+len)) {
715
0
        MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: the sub zone %d-%d seems bad\n", z, s));
716
0
        f << "###";
717
0
        ascFile.addPos(pos);
718
0
        ascFile.addNote(f.str().c_str());
719
0
        return false;
720
0
      }
721
0
      if (len) {
722
0
        std::shared_ptr<Canvas5ImageInternal::VKFLImage> image;
723
0
        if (!readVKFL(stream, len, image)) {
724
0
          f  << "###";
725
0
          input->seek(pos+12+len, librevenge::RVNG_SEEK_SET);
726
0
        }
727
0
        else
728
0
          m_state->m_idToGIF[s]=image;
729
0
        ascFile.addPos(pos);
730
0
        ascFile.addNote(f.str().c_str());
731
732
0
        pos=input->tell();
733
0
        f.str("");
734
0
        f << "RsrcAGIF" << z << "-" << s << "[B]:";
735
0
      }
736
0
      for (int i=0; i<3; ++i) { // g2=1 means continue
737
0
        val=int(input->readLong(4));
738
0
        int const expected[]= {0,1,0};
739
0
        if (val!=expected[i])
740
0
          f << "g" << i << "=" << val << ",";
741
0
      }
742
0
      ascFile.addPos(pos);
743
0
      ascFile.addNote(f.str().c_str());
744
0
    }
745
0
  }
746
0
  if (!input->isEnd()) {
747
0
    MWAW_DEBUG_MSG(("Canvas5Image::readAGIFRsrc: find extra data\n"));
748
0
    ascFile.addPos(input->tell());
749
0
    ascFile.addNote("RsrcAGIF-end:###extra");
750
0
  }
751
0
  return true;
752
0
}
753
754
bool Canvas5Image::readQkTmRsrc(Canvas5Structure::Stream &stream)
755
0
{
756
0
  auto input=stream.input();
757
0
  long pos=input->tell();
758
0
  libmwaw::DebugStream f;
759
0
  auto &ascFile=stream.ascii();
760
0
  f << "RsrcQkTm:";
761
762
0
  if (!input->checkPosition(pos+4)) {
763
0
    MWAW_DEBUG_MSG(("Canvas5Image::readQkTmRsrc: the zone seems too short\n"));
764
0
    f << "###";
765
0
    ascFile.addPos(pos);
766
0
    ascFile.addNote(f.str().c_str());
767
0
    return false;
768
0
  }
769
770
0
  int N=int(input->readULong(4));
771
0
  f << "N=" << N << ",";
772
0
  ascFile.addPos(pos);
773
0
  ascFile.addNote(f.str().c_str());
774
775
0
  for (int z=0; z<N; ++z) {
776
0
    pos=input->tell();
777
0
    f.str("");
778
0
    f << "RsrcQkTm-QK" << z+1 << ":";
779
0
    if (!input->checkPosition(pos+44)) {
780
0
      MWAW_DEBUG_MSG(("Canvas5Image::readQkTmRsrc: the %d zone seems too short\n", z));
781
0
      f << "###";
782
0
      ascFile.addPos(pos);
783
0
      ascFile.addNote(f.str().c_str());
784
0
      return false;
785
0
    }
786
0
    input->seek(pos+40, librevenge::RVNG_SEEK_SET);
787
0
    long len=input->readLong(4);
788
0
    if (len<0 || pos+44+len<pos+44 || !input->checkPosition(pos+44+len)) {
789
0
      MWAW_DEBUG_MSG(("Canvas5Image::readQkTmRsrc: the %d zone len seems bad\n", z));
790
0
      f << "###len=" << len << ",";
791
0
      ascFile.addPos(pos);
792
0
      ascFile.addNote(f.str().c_str());
793
0
      return false;
794
0
    }
795
0
    ascFile.addPos(pos);
796
0
    ascFile.addNote(f.str().c_str());
797
798
0
    if (len) {
799
0
      librevenge::RVNGBinaryData movie;
800
0
      if (!input->readDataBlock(len, movie)) {
801
0
        MWAW_DEBUG_MSG(("Canvas5Image::readQkTmRsrc: oops can not retrieve the %d movie\n", z));
802
0
        f << "###";
803
0
      }
804
0
      else {
805
0
        m_state->m_idToQkTm[z+1]=movie;
806
#ifdef DEBUG_WITH_FILES
807
        std::stringstream s;
808
        static int index=0;
809
        s << "movie" << ++index << ".mov";
810
        libmwaw::Debug::dumpFile(movie, s.str().c_str());
811
#endif
812
0
      }
813
0
      ascFile.skipZone(pos+44, pos+44+len-1);
814
0
    }
815
0
    input->seek(pos+44+len, librevenge::RVNG_SEEK_SET);
816
0
  }
817
0
  return true;
818
0
}
819
820
bool Canvas5Image::getArrow(std::shared_ptr<Canvas5ImageInternal::VKFLImage> image, MWAWGraphicStyle::Arrow &arrow) const
821
0
{
822
0
  arrow=MWAWGraphicStyle::Arrow::plain();
823
0
  if (!image) {
824
0
    MWAW_DEBUG_MSG(("Canvas5Image::getArrow: can not find the image\n"));
825
0
    return false;
826
0
  }
827
0
  std::vector<int> typeList;
828
0
  for (auto const &shape : image->m_shapes) {
829
0
    if (shape.m_type>=0 && shape.m_type!=11)
830
0
      typeList.push_back(shape.m_type);
831
0
  }
832
0
  if (typeList.size()==1) {
833
    // TODO: get the real shape and extract the path
834
0
    switch (typeList[0]) {
835
0
    case 1:
836
0
    case 2:
837
0
      arrow=MWAWGraphicStyle::Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,30)), "M1013 1491l118 89-567-1580-564 1580 114-85 136-68 148-46 161-17 161 13 153 46z", false);
838
0
      break;
839
0
    case 7:
840
0
      arrow=MWAWGraphicStyle::Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(1131,1131)), "M462 1118l-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z", false);
841
0
      break;
842
0
    case 10:
843
0
      arrow=MWAWGraphicStyle::Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,30)), "m10 0l-10 30h20z", false);
844
0
      break;
845
0
    default:
846
0
      MWAW_DEBUG_MSG(("Canvas5Image::readArrow: find unexpected arrow with type %d\n", typeList[0]));
847
0
      break;
848
0
    }
849
0
  }
850
0
  else if (typeList.size()==2 && typeList[0]==1 && typeList[1]==1)
851
0
    arrow=MWAWGraphicStyle::Arrow(10, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(40,35)), "m20 0l-20 0 l0 4 l20 0 l-10 30 l20 0 l-10 -30 l20 0 l0 -4z", false);
852
0
  else if (typeList.size()==2 && typeList[0]==2 && typeList[1]==2)
853
0
    arrow=MWAWGraphicStyle::Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,30)), "m0 3 h-20 v-3 h40 v3 h-20 l-10 30 h20z", false);
854
0
  else if (typeList.size()==3 && typeList[0]==10)
855
0
    arrow=MWAWGraphicStyle::Arrow(5, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,33)), "m10 0l-10 30 l10 3 l10 -3z", false);
856
0
  else {
857
0
    MWAW_DEBUG_MSG(("Canvas5Image::readArrow: find unexpected arrow with size=%d\n", int(typeList.size())));
858
0
  }
859
0
  return true;
860
0
}
861
862
bool Canvas5Image::getTexture(std::shared_ptr<Canvas5ImageInternal::VKFLImage> image, MWAWEmbeddedObject &texture, MWAWVec2i &textureDim, MWAWColor &averageColor) const
863
0
{
864
0
  if (!image) {
865
0
    MWAW_DEBUG_MSG(("Canvas5Image::getTexture: can not find the image\n"));
866
0
    return false;
867
0
  }
868
0
  bool bitmapFound=false;
869
0
  for (auto const &shape : image->m_shapes) {
870
0
    if (shape.m_type!=14 || shape.m_bitmap.isEmpty()) continue;
871
0
    if (bitmapFound) {
872
0
      MWAW_DEBUG_MSG(("Canvas5Image::getTexture: found multiple textures, return the first one\n"));
873
0
      return true;
874
0
    }
875
0
    bitmapFound=true;
876
0
    texture=shape.m_bitmap;
877
0
    textureDim=MWAWVec2i(shape.m_box.size());
878
0
    averageColor=shape.m_bitmapColor;
879
0
  }
880
0
  if (bitmapFound)
881
0
    return true;
882
0
  MWAW_DEBUG_MSG(("Canvas5Image::getTexture: can not find any texture\n"));
883
0
  return false;
884
0
}
885
886
bool Canvas5Image::readVKFL(std::shared_ptr<Canvas5Structure::Stream> stream, long len, std::shared_ptr<Canvas5ImageInternal::VKFLImage> &image)
887
0
{
888
0
  image.reset();
889
0
  if (!stream)
890
0
    return false;
891
0
  if (len==0)
892
0
    return true;
893
0
  auto input=stream->input();
894
0
  int const vers=version();
895
0
  long pos=input->tell();
896
0
  long endPos=pos+len;
897
0
  int const headerLen=vers<9 ? 180 : 288;
898
0
  if (len<headerLen || !input->checkPosition(endPos)) {
899
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: the zone seems too short\n"));
900
0
    return false;
901
0
  }
902
903
0
  auto &ascFile=stream->ascii();
904
0
  libmwaw::DebugStream f;
905
906
0
  f << "Entries(Vkfl):";
907
0
  int val=int(input->readLong(4));
908
0
  if (val!=256)
909
0
    f << "f0=" << val << ",";
910
0
  auto tBegin=long(input->readULong(4));
911
0
  auto tLen=long(input->readULong(4));
912
0
  f << "pos=" << tBegin << "<->" << tBegin+tLen << ",";
913
0
  if (tBegin+tLen<0 || tLen<36 || tBegin<headerLen || tBegin+tLen>len) {
914
0
    f << "###";
915
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: can not read the data length length\n"));
916
0
    ascFile.addPos(pos);
917
0
    ascFile.addNote(f.str().c_str());
918
0
    return false;
919
0
  }
920
0
  if (tBegin+tLen<len) {
921
0
    ascFile.addPos(pos+tBegin+tLen);
922
0
    ascFile.addNote("Vkfl-[end]:###");
923
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: find extra data\n"));
924
0
  }
925
926
0
  image=std::make_shared<Canvas5ImageInternal::VKFLImage>();
927
0
  if (vers>=9)
928
0
    input->seek(4, librevenge::RVNG_SEEK_CUR);
929
0
  float dim[4];
930
0
  for (auto &d : dim) d=float(m_mainParser->readDouble(*stream,vers<9 ? 4 : 8));
931
0
  if (vers<9)
932
0
    image->m_boxes[0]=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
933
0
  else
934
0
    image->m_boxes[0]=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
935
0
  f << "dim=" << image->m_boxes[0] << ",";
936
0
  for (int i=0; i<2; ++i) {
937
0
    val=int(input->readLong(4));
938
0
    if (val!=1-i)
939
0
      f << "f" << i+2 << "=" << val << ",";
940
0
  }
941
0
  for (auto &d : dim) d=float(m_mainParser->readDouble(*stream,vers<9 ? 4 : 8));
942
0
  if (vers<9)
943
0
    image->m_boxes[1]=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
944
0
  else
945
0
    image->m_boxes[1]=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
946
0
  if (image->m_boxes[0]!=image->m_boxes[1])
947
0
    f << "dim2=" << image->m_boxes[1] << ",";
948
0
  for (int st=0; st<2; ++st) {
949
0
    f << "mat" << st << "=[";
950
0
    for (auto &d : image->m_matrices[st]) {
951
0
      d=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8);
952
0
      f << d << ",";
953
0
    }
954
0
    f << "],";
955
0
  }
956
0
  for (int j=0; j<3; ++j) { // g1=54|6c
957
0
    val=int(input->readLong(4));
958
0
    if (val!=-1)
959
0
      f << "g" << j << "=" << val << ",";
960
0
  }
961
0
  int dDim[2]; // g1+48, g1+24
962
0
  for (auto &d : dDim) d=int(input->readLong(4));
963
0
  if (vers<9)
964
0
    f << "dim3=" << MWAWVec2i(dDim[1],dDim[0]) << ",";
965
0
  else
966
0
    f << "dim3=" << MWAWVec2i(dDim[0],dDim[1]) << ",";
967
968
0
  long firstBlockDecal=0;
969
0
  for (int j=0; j<5; ++j) {
970
0
    val=int(input->readLong(4));
971
0
    int const expected[]= {-1,-1,1,0,0};
972
0
    if (val==expected[j]) continue;
973
0
    if (j==3)
974
0
      firstBlockDecal=val;
975
0
    f << "g" << j+3 << "=" << val << ",";
976
0
  }
977
978
0
  f << "entries=[";
979
0
  for (auto &entry : image->m_data) {
980
0
    entry.setBegin(input->readLong(4)+pos);
981
0
    entry.setLength(input->readLong(4));
982
0
    f << std::hex << entry.begin() << ":" << entry.end() << std::dec << ",";
983
0
    if (entry.begin()<pos || entry.end()>pos+tBegin+tLen) {
984
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: unexpected subs size for an effect\n"));
985
0
      f << "###";
986
0
      entry.setLength(0);
987
0
    }
988
0
  }
989
0
  f << ",";
990
991
0
  ascFile.addPos(pos);
992
0
  ascFile.addNote(f.str().c_str());
993
994
0
  std::set<long> seen;
995
0
  long begPos=image->m_data[1].begin();
996
0
  if (image->m_data[1].valid() && firstBlockDecal>=0 && firstBlockDecal<=image->m_data[1].length()) {
997
0
    input->seek(begPos+firstBlockDecal, librevenge::RVNG_SEEK_SET);
998
0
    while (input->tell()<image->m_data[1].end()) {
999
0
      if (input->tell()<begPos || seen.find(input->tell())!=seen.end()) {
1000
0
        MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: oops find a loop\n"));
1001
0
        break;
1002
0
      }
1003
0
      seen.insert(input->tell());
1004
0
      if (!readVKFLShape(stream, *image))
1005
0
        break;
1006
0
    }
1007
0
  }
1008
0
  else if (firstBlockDecal>=0) {
1009
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: first block seems bad\n"));
1010
0
  }
1011
1012
0
  if (!image->m_data[0].valid()) {
1013
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: can not find any data0 zoone\n"));
1014
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1015
0
    return true;
1016
0
  }
1017
1018
0
  std::stack<std::pair<long,int> > dataStack;
1019
0
  for (auto const &shape : image->m_shapes) {
1020
0
    for (auto const &it : shape.m_idToDataPos) {
1021
0
      pos=begPos+it.second;
1022
0
      if (seen.find(pos)!=seen.end()) // already parsed or pb
1023
0
        continue;
1024
0
      seen.insert(pos);
1025
0
      dataStack.push(std::make_pair(pos, it.first));
1026
0
    }
1027
0
  }
1028
1029
0
  while (!dataStack.empty()) {
1030
0
    auto posId=dataStack.top();
1031
0
    dataStack.pop();
1032
1033
0
    pos=posId.first;
1034
0
    if (pos<begPos || pos+24>image->m_data[1].end()) {
1035
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: can not find sub zone0[%lx]\n", posId.first));
1036
0
      continue;
1037
0
    }
1038
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1039
0
    f.str("");
1040
0
    if (posId.second>=0)
1041
0
      f << "Vkfl-VK" << std::hex << pos-begPos << std::dec << "A[" << posId.second << "]:";
1042
0
    else
1043
0
      f << "Vkfl-VK" << std::hex << pos-begPos << std::dec << "A:";
1044
0
    unsigned dataType=unsigned(input->readULong(4));
1045
0
    auto unknPos=input->readULong(4);
1046
0
    if (unknPos!=0xFFFFFFFF) {
1047
0
      long childPos=begPos+long(unknPos);
1048
0
      f << "unkn=VK" << std::hex << long(unknPos) << std::dec << ",";
1049
0
      if (seen.find(childPos)==seen.end()) {
1050
0
        seen.insert(childPos);
1051
0
        dataStack.push(std::make_pair(childPos,-1));
1052
0
      }
1053
0
    }
1054
0
    long dataLength[2];
1055
0
    dataLength[0]=input->readLong(4);
1056
0
    val=int(input->readULong(4));
1057
0
    if (val) f << "f0=" << val << ",";
1058
0
    unsigned dataSubType=unsigned(input->readULong(4));
1059
0
    dataLength[1]=input->readLong(4);
1060
0
    image->m_posToTypesMap[pos-begPos]=std::make_pair(dataType, dataSubType);
1061
0
    if (dataLength[0]) {
1062
0
      MWAWEntry data;
1063
0
      data.setId(int(dataType));
1064
0
      data.setBegin(image->m_data[0].begin()+dataLength[1]);
1065
0
      data.setLength(dataLength[0]);
1066
0
      f << "data=[" << Canvas5Structure::getString(dataType) << "-" << Canvas5Structure::getString(dataSubType) << ","
1067
0
        << std::hex << data.begin() << "->" << data.end() << std::dec << "],";
1068
0
      std::vector<long> childFieldPos;
1069
0
      input->pushLimit(data.end());
1070
0
      readVKFLShapeOtherData(stream, *image, std::make_tuple(data, dataSubType, pos-begPos),
1071
0
                             childFieldPos, posId.second);
1072
0
      input->popLimit();
1073
0
      for (auto cPos : childFieldPos) {
1074
0
        if (cPos<0) continue;
1075
0
        long childPos=begPos+cPos;
1076
0
        if (seen.find(childPos)==seen.end()) {
1077
0
          seen.insert(childPos);
1078
0
          dataStack.push(std::make_pair(childPos,-1));
1079
0
        }
1080
0
      }
1081
0
    }
1082
0
    ascFile.addPos(pos);
1083
0
    ascFile.addNote(f.str().c_str());
1084
0
    input->seek(pos+24, librevenge::RVNG_SEEK_SET);
1085
0
    ascFile.addPos(pos+24);
1086
0
    ascFile.addNote("_");
1087
0
  }
1088
1089
#ifdef DEBUG_CANVAS_VKFL
1090
  MWAWGraphicEncoder graphicEncoder;
1091
  MWAWBox2f pictBox=image->m_boxes[0]; // 0: image size, 1: image + translation
1092
  pictBox.setMax(pictBox[1]+MWAWVec2f(100,100));
1093
  auto graphicListener=std::make_shared<MWAWGraphicListener>(*m_parserState, pictBox, &graphicEncoder);
1094
  graphicListener->startDocument();
1095
  MWAWTransformation transf;
1096
  auto const &mat=image->m_matrices[0];
1097
  if (mat[2]<-1e-3 || mat[2]>1e-3 || mat[5]<-1e-3 || mat[5]>1e-3) {
1098
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFL: image matrix will be ignored\n"));
1099
  }
1100
  else
1101
    transf=MWAWTransformation(MWAWVec3f((float)mat[0],(float)mat[3],(float)mat[6]), MWAWVec3f((float)mat[1],(float)mat[4],(float)mat[7]));
1102
1103
  send(image, graphicListener, pictBox, transf);
1104
  graphicListener->endDocument();
1105
  MWAWEmbeddedObject picture;
1106
  if (graphicEncoder.getBinaryResult(picture) && !picture.m_dataList.empty()) {
1107
    static int vkflId=0;
1108
    std::stringstream s;
1109
    s << "Vkfl" << ++vkflId << ".odg";
1110
    libmwaw::Debug::dumpFile(picture.m_dataList[0], s.str().c_str());
1111
  }
1112
#endif
1113
1114
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1115
0
  return true;
1116
0
}
1117
1118
bool Canvas5Image::readVKFLShape(std::shared_ptr<Canvas5Structure::Stream> stream, Canvas5ImageInternal::VKFLImage &image)
1119
0
{
1120
0
  if (!stream || !image.m_data[1].valid()) {
1121
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShape: the image data1 is not valid\n"));
1122
0
    return false;
1123
0
  }
1124
1125
0
  auto input=stream->input();
1126
0
  int const vers=version();
1127
0
  long pos=input->tell();
1128
0
  long begPos=image.m_data[1].begin();
1129
0
  long endPos=image.m_data[1].end();
1130
0
  auto &ascFile=stream->ascii();
1131
0
  libmwaw::DebugStream f;
1132
1133
0
  int id=1+int(image.m_shapes.size());
1134
0
  f << "Vkfl-s" << id << ":";
1135
0
  int const headerLen=vers<9 ? 44 : 64;
1136
0
  if (pos+headerLen>endPos) {
1137
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShape: the zone seems too short\n"));
1138
0
    f << "###";
1139
0
    ascFile.addPos(pos);
1140
0
    ascFile.addNote(f.str().c_str());
1141
0
    return false;
1142
0
  }
1143
0
  image.m_shapes.push_back(Canvas5ImageInternal::VKFLShape());
1144
0
  auto &shape=image.m_shapes.back();
1145
0
  shape.m_type=int(input->readLong(4)); // find 1-14
1146
0
  f << "type=" << Canvas5ImageInternal::VKFLShape::getTypeName(shape.m_type) << ",";
1147
0
  if (vers>=9)
1148
0
    input->seek(4, librevenge::RVNG_SEEK_CUR);
1149
0
  float dim[4];
1150
0
  for (auto &d : dim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1151
0
  if (vers<9)
1152
0
    shape.m_box=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
1153
0
  else
1154
0
    shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
1155
0
  f << "dim=" << shape.m_box << ",";
1156
0
  int val=int(input->readULong(4)); // 0|8000
1157
0
  if (val) f << "fl0=" << std::hex << val << std::dec << ",";
1158
0
  auto fl=input->readULong(4); // [347]|[01]ff
1159
0
  if (fl)  f << "fl1=" << std::hex << fl << std::dec << ",";
1160
0
  auto decal=input->readULong(4);
1161
0
  long nextPos=decal==0xFFFFFFFF ? endPos : begPos+long(decal);
1162
0
  if (nextPos<=begPos || (nextPos>=pos && nextPos<pos+44) || nextPos>endPos) {
1163
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShape: the zone seems too short\n"));
1164
0
    f << "###";
1165
0
    ascFile.addPos(pos);
1166
0
    ascFile.addNote(f.str().c_str());
1167
0
    return false;
1168
0
  }
1169
0
  long dataLength[2];
1170
0
  dataLength[0]=input->readLong(4);
1171
0
  shape.m_subType=unsigned(input->readULong(4));
1172
0
  dataLength[1]=input->readLong(4);
1173
0
  if (dataLength[0])
1174
0
    f << "data=[" << Canvas5Structure::getString(shape.m_subType) << "," << std::hex << image.m_data[0].begin()+dataLength[1] << "->" << image.m_data[0].begin()+dataLength[0]+dataLength[1] << std::dec << "],";
1175
0
  else if (shape.m_subType && shape.m_type==11)
1176
0
    f << "N=" << shape.m_subType << ",";
1177
0
  else if (shape.m_subType)
1178
0
    f << "unkn=" << Canvas5Structure::getString(shape.m_subType) << ",";
1179
1180
0
  unsigned dec=1;
1181
0
  for (int i=0; i<12; ++i, dec*=2) {
1182
0
    if ((fl&dec)==0) continue;
1183
0
    if (input->tell()+4>nextPos) {
1184
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShape: the zone seems too short\n"));
1185
0
      f << "###";
1186
0
      ascFile.addPos(pos);
1187
0
      ascFile.addNote(f.str().c_str());
1188
0
      break;
1189
0
    }
1190
0
    long decalData=long(input->readLong(4));
1191
0
    if (decalData>=0) {
1192
0
      shape.m_idToDataPos[i]=decalData;
1193
0
      char const *wh[]= {"surfColor", "lineColor", "stroke", "matrix", "matrix1",
1194
0
                         "matrix2", nullptr, nullptr, nullptr, "name"
1195
0
                        };
1196
0
      if (i<10 && wh[i])
1197
0
        f << "beg[" << wh[i] << "]=VK" << std::hex << decalData << std::dec << ",";
1198
0
      else
1199
0
        f << "beg[t" << i << "]=VK" << std::hex << decalData << std::dec << ",";
1200
0
    }
1201
0
  }
1202
0
  ascFile.addPos(pos);
1203
0
  ascFile.addNote(f.str().c_str());
1204
0
  ascFile.addPos(input->tell());
1205
0
  ascFile.addNote("_");
1206
1207
0
  if (dataLength[0]) {
1208
0
    MWAWEntry data;
1209
0
    data.setBegin(image.m_data[0].begin()+dataLength[1]);
1210
0
    data.setLength(dataLength[0]);
1211
0
    readVKFLShapeMainData(stream, image, shape, data);
1212
0
  }
1213
1214
0
  input->seek(nextPos, librevenge::RVNG_SEEK_SET);
1215
0
  return true;
1216
0
}
1217
1218
bool Canvas5Image::readVKFLShapeMainData(std::shared_ptr<Canvas5Structure::Stream> stream, Canvas5ImageInternal::VKFLImage &image, Canvas5ImageInternal::VKFLShape &shape, MWAWEntry const &data)
1219
0
{
1220
0
  if (!data.valid() || !stream)
1221
0
    return true;
1222
1223
0
  auto input=stream->input();
1224
0
  int const vers=version();
1225
0
  if (!input || !input->checkPosition(data.end()) || data.begin()<image.m_data[0].begin() || data.end()>image.m_data[0].end()) {
1226
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: the entry seems bad\n"));
1227
0
    return false;
1228
0
  }
1229
1230
0
  libmwaw::DebugStream f;
1231
0
  auto &ascFile=stream->ascii();
1232
0
  f << "Vkfl-s" << image.m_shapes.size() << "M[" << Canvas5ImageInternal::VKFLShape::getTypeName(shape.m_type) << ":" << Canvas5Structure::getString(shape.m_subType) << "]:";
1233
0
  input->seek(data.begin(), librevenge::RVNG_SEEK_SET);
1234
1235
0
  int val;
1236
0
  switch (shape.m_type) {
1237
0
  case 1: // poly?
1238
0
  case 2: { // unsure a list of 16/20 points, many are similar
1239
0
    if (data.length()<8) {
1240
0
      f << "###";
1241
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData[poly]: the zone seems too short\n"));
1242
0
      break;
1243
0
    }
1244
0
    int nPts;
1245
0
    if (vers<9) {
1246
0
      val=int(input->readULong(4)); // checkme: either N or a number less than N
1247
0
      if (val)
1248
0
        f << "f0=" << val << ",";
1249
0
      nPts=int(input->readULong(4));
1250
0
    }
1251
0
    else
1252
0
      nPts=m_mainParser->readInteger(*stream, 8);
1253
0
    int const fieldSize=vers<9 ? 8 : 16;
1254
0
    f << "N=" << nPts << ",";
1255
0
    if (nPts<0 || 8+fieldSize*nPts<0 || nPts>(data.length()-8)/fieldSize || 8+fieldSize*nPts>data.length()) {
1256
0
      f << "###";
1257
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData[poly]: can not read the number of points\n"));
1258
0
      break;
1259
0
    }
1260
0
    f << "pts=[";
1261
0
    shape.m_vertices.resize(size_t(nPts));
1262
0
    for (auto &pt : shape.m_vertices) {
1263
0
      float coord[2];
1264
0
      for (auto &d : coord) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1265
0
      pt=MWAWVec2f(coord[1], coord[0]);
1266
0
      f << pt << ",";
1267
0
    }
1268
0
    f << "],";
1269
0
    break;
1270
0
  }
1271
  // 6,7: rect, circle: no data
1272
0
  case 8:
1273
0
    if (data.length()!=(vers<9 ? 8 : 16)) {
1274
0
      f << "###";
1275
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData[rectOval]: the zone seems too short\n"));
1276
0
      break;
1277
0
    }
1278
0
    f << "oval[sz]=[";
1279
0
    for (auto &v : shape.m_locals)
1280
0
      v=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1281
0
    f << MWAWVec2f(shape.m_locals[1],shape.m_locals[0]) << ",";
1282
0
    break;
1283
0
  case 9: // line
1284
0
    if (data.length()<(vers<9 ? 16 : 32)) {
1285
0
      f << "###";
1286
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData[type9]: the zone seems too short\n"));
1287
0
      break;
1288
0
    }
1289
0
    f << "pts=[";
1290
0
    shape.m_vertices.resize(2);
1291
0
    for (auto &pt : shape.m_vertices) {
1292
0
      float coord[2];
1293
0
      for (auto &d : coord) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1294
0
      if (vers<9)
1295
0
        pt=MWAWVec2f(coord[1], coord[0]);
1296
0
      else
1297
0
        pt=MWAWVec2f(coord[0], coord[1]);
1298
0
      f << pt << ",";
1299
0
    }
1300
0
    f << "],";
1301
0
    break;
1302
0
  case 10:
1303
0
    if (data.length()!=(vers<9 ? 8 : 16)) {
1304
0
      f << "###";
1305
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData[arc]: the zone seems too short\n"));
1306
0
      break;
1307
0
    }
1308
0
    for (auto &v : shape.m_locals) {
1309
0
      v=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1310
0
      if (vers>=9) v*=float(180/M_PI);
1311
0
    }
1312
0
    f << "angles=[" << shape.m_locals[0] << "," << shape.m_locals[1] << "],";
1313
0
    break;
1314
  // 11, 12:  no dat
1315
0
  case 14: { // special
1316
0
    switch (shape.m_subType) {
1317
0
    case 0x706f626a: // special a pobj which contains a bitmap
1318
0
      if (!Canvas5Structure::readBitmap(*stream, vers, shape.m_bitmap, &shape.m_bitmapColor)) {
1319
0
        f << "###";
1320
0
        MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: can not retrieve the bitmap\n"));
1321
0
      }
1322
0
      if (input->tell()!=data.end()) {
1323
0
        ascFile.addPos(input->tell());
1324
0
        ascFile.addNote("Vkfl-end");
1325
0
      }
1326
0
      break;
1327
0
    case 0x8F909d96: { // special a bitmap in a mac/windows files
1328
0
      bool readInverted=input->readInverted();
1329
0
      input->setReadInverted(!readInverted);
1330
0
      if (!Canvas5Structure::readBitmap(*stream, vers, shape.m_bitmap, &shape.m_bitmapColor)) {
1331
0
        f << "###";
1332
0
        MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: can not retrieve the bitmap\n"));
1333
0
      }
1334
0
      input->setReadInverted(readInverted);
1335
0
      if (input->tell()!=data.end()) {
1336
0
        ascFile.addPos(input->tell());
1337
0
        ascFile.addNote("Vkfl-end");
1338
0
      }
1339
0
      break;
1340
0
    }
1341
0
    case 0x4d41434f: { // MACO
1342
0
      if (data.length()<(vers<9 ? 96 : 116)) {
1343
0
        f << "###";
1344
0
        MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: can not retrieve the MACO vkfl\n"));
1345
0
        break;
1346
0
      }
1347
      // see also Canvas5Image::readMACORsrc
1348
0
      f << "unkn=" << std::hex << input->readULong(4) << std::dec << ",";
1349
0
      std::string name;
1350
0
      for (int i=0; i<32; ++i) {
1351
0
        char c=char(input->readULong(1));
1352
0
        if (!c)
1353
0
          break;
1354
0
        name+=c;
1355
0
      }
1356
0
      f << name << ",";
1357
0
      input->seek(data.begin()+4+32, librevenge::RVNG_SEEK_SET);
1358
0
      for (int k=0; k<2; ++k) {
1359
0
        val=int(input->readLong(2));
1360
0
        if (val!=(k==0 ? 256 : 0))
1361
0
          f << "g" << k << "=" << val << ",";
1362
0
      }
1363
0
      if (vers>=9)
1364
0
        input->seek(4, librevenge::RVNG_SEEK_CUR);
1365
0
      float fDim[4];
1366
0
      for (auto &d : fDim) d=float(m_mainParser->readDouble(*stream, vers<9 ? 4 : 8));
1367
0
      if (vers<9)
1368
0
        f << "box=" << MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]), MWAWVec2f(fDim[2], fDim[3])) << ",";
1369
0
      else
1370
0
        f << "box=" << MWAWBox2f(MWAWVec2f(fDim[1], fDim[0]), MWAWVec2f(fDim[3], fDim[2])) << ",";
1371
1372
0
      long actPos=input->tell();
1373
0
      std::vector<unsigned> mId;
1374
0
      std::string extra;
1375
0
      readMacroIndent(*stream, mId, extra);
1376
0
      f << "id=[" << extra << "],";
1377
0
      input->seek(actPos+20, librevenge::RVNG_SEEK_SET);
1378
1379
0
      for (auto &d : fDim) d=float(input->readULong(4))/65536.f;
1380
0
      f << "box2=" << MWAWBox2f(MWAWVec2f(fDim[0], fDim[1]), MWAWVec2f(fDim[2], fDim[3])) << ",";
1381
1382
0
      long imageLen=input->readLong(4);
1383
0
      if (96+imageLen<96 || 96+imageLen>data.length()) {
1384
0
        f << "###";
1385
0
        MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: can not retrieve the vkfl length\n"));
1386
0
        break;
1387
0
      }
1388
0
      if (!imageLen)
1389
0
        break;
1390
0
      if (!readVKFL(stream, imageLen, shape.m_macoImage))
1391
0
        f << "###";
1392
0
      break;
1393
0
    }
1394
0
    case 0x44494d4e: // MACO
1395
0
    case 0x54656368: // Tech
1396
0
      if (vers>=9) {
1397
0
        if (data.length()<=4)
1398
0
          break;
1399
0
        val=int(input->readLong(4));
1400
0
        if (val!=1) f << "f0=" << val << ",";
1401
0
        std::string extra;
1402
0
        shape.m_special=m_mainParser->m_graphParser->readSpecialData(stream, data.length()-4, shape.m_subType, shape.m_box, extra);
1403
0
        if (!shape.m_special)
1404
0
          f << "###";
1405
0
        f << extra;
1406
0
        break;
1407
0
      }
1408
0
      MWAW_FALLTHROUGH;
1409
0
    case 0x54585420: {
1410
0
      std::string extra;
1411
0
      shape.m_special=m_mainParser->m_graphParser->readSpecialData(stream, data.length(), shape.m_subType, shape.m_box, extra);
1412
0
      if (!shape.m_special)
1413
0
        f << "###";
1414
0
      f << extra;
1415
0
      break;
1416
0
    }
1417
0
    default: {
1418
0
      std::string extra;
1419
0
      shape.m_special=m_mainParser->m_graphParser->readSpecialData(stream, data.length(), shape.m_subType, shape.m_box, extra);
1420
0
      if (!shape.m_special)
1421
0
        f << "###";
1422
0
      f << extra;
1423
0
      break;
1424
0
    }
1425
0
    }
1426
0
    break;
1427
0
  }
1428
0
  default:
1429
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeMainData: find unexpected data for type=%d\n", shape.m_type));
1430
0
    f << "##";
1431
0
    break;
1432
0
  }
1433
1434
0
  ascFile.addPos(data.begin());
1435
0
  ascFile.addNote(f.str().c_str());
1436
0
  return true;
1437
0
}
1438
1439
bool Canvas5Image::readVKFLShapeOtherData
1440
(std::shared_ptr<Canvas5Structure::Stream> stream, Canvas5ImageInternal::VKFLImage &image,
1441
 std::tuple<MWAWEntry, unsigned, long> const &dataTypePos,
1442
 std::vector<long> &childFieldPos, int subId)
1443
0
{
1444
0
  if (!stream || !stream->input())
1445
0
    return false;
1446
0
  MWAWEntry data;
1447
0
  unsigned subType;
1448
0
  long idPos;
1449
0
  std::tie(data, subType, idPos)=dataTypePos;
1450
0
  auto input=stream->input();
1451
0
  if (!input->checkPosition(data.end()) || data.begin()<image.m_data[0].begin() || data.end()>image.m_data[0].end()) {
1452
0
    MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData: the entry seems bad\n"));
1453
0
    return false;
1454
0
  }
1455
1456
0
  int const vers=version();
1457
0
  libmwaw::DebugStream f;
1458
0
  auto &ascFile=stream->ascii();
1459
0
  f << "Vkfl-B" << Canvas5Structure::getString(unsigned(data.id())) << "-" << Canvas5Structure::getString(subType);
1460
0
  if (subId>=0)
1461
0
    f << "[" << subId << "]";
1462
0
  f << ":";
1463
0
  input->seek(data.begin(), librevenge::RVNG_SEEK_SET);
1464
0
  switch (data.id()) {
1465
0
  case 1: {
1466
0
    f << "color,";
1467
0
    auto color=getStyleManager()->readColorStyle(stream, subType, data.length());
1468
0
    if (!color) {
1469
0
      f << "###";
1470
0
      break;
1471
0
    }
1472
1473
0
    image.m_posToColorMap[idPos]=color;
1474
0
    break;
1475
0
  }
1476
0
  case 2: {
1477
0
    f << "stroke,";
1478
0
    if (data.length()!=20) {
1479
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData: can not read a style field\n"));
1480
0
      f << "##";
1481
0
      break;
1482
0
    }
1483
0
    Canvas5ImageInternal::Stroke stroke;
1484
0
    stroke.m_type=unsigned(input->readULong(4));
1485
0
    if (stroke.m_type!=1) f << "type=" << Canvas5Structure::getString(stroke.m_type) << ",";
1486
0
    for (int i=0; i<4; ++i) {
1487
0
      long cPos=input->readLong(4);
1488
0
      if (cPos<0) continue;
1489
0
      char const *wh[]= { "penId", "dashId", "arrow[beg]", "arrow[end]"};
1490
0
      childFieldPos.push_back(cPos);
1491
0
      switch (i) {
1492
0
      case 0:
1493
0
        stroke.m_penPos=cPos;
1494
0
        break;
1495
0
      case 1:
1496
0
        stroke.m_dashPos=cPos;
1497
0
        break;
1498
0
      default:
1499
0
        stroke.m_arrowPos[i-2]=cPos;
1500
0
        break;
1501
0
      }
1502
0
      f << wh[i] << "=Vk" << std::hex << cPos << std::dec << ",";
1503
0
    }
1504
0
    image.m_posToStrokeMap[idPos]=stroke;
1505
0
    break;
1506
0
  }
1507
0
  case 3: {
1508
0
    f << "pen,";
1509
0
    auto pen=getStyleManager()->readPenStyle(*stream, subType, data.length());
1510
0
    if (!pen) {
1511
0
      f << "###";
1512
0
      break;
1513
0
    }
1514
1515
0
    image.m_posToPenMap[idPos]=pen;
1516
0
    break;
1517
0
  }
1518
0
  case 4: {
1519
0
    f << "matrix,";
1520
0
    if (data.length()!=(vers<9 ? 72 : 144)) {
1521
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData: can not read a matrix field\n"));
1522
0
      f << "##";
1523
0
      break;
1524
0
    }
1525
0
    for (size_t st=0; st<2; ++st) {
1526
0
      f << "mat" << st << "=[";
1527
0
      std::array<double,9> matrix;
1528
0
      for (auto &d : matrix) {
1529
0
        d=m_mainParser->readDouble(*stream, vers<9 ? 4 : 8);
1530
0
        f << d << ",";
1531
0
      }
1532
0
      f << "],";
1533
0
      if (st==0)
1534
0
        image.m_posToMatrixMap[idPos]=matrix;
1535
0
    }
1536
0
    break;
1537
0
  }
1538
0
  case 5: {
1539
0
    f << "arrow,";
1540
0
    MWAWGraphicStyle::Arrow arrow;
1541
0
    if (!getStyleManager()->readArrow(stream, arrow, subType, data.length())) {
1542
0
      f << "###";
1543
0
      break;
1544
0
    }
1545
0
    image.m_posToArrowMap[idPos]=arrow;
1546
0
    break;
1547
0
  }
1548
0
  case 6: {
1549
0
    f << "dashes,";
1550
0
    std::vector<float> dashes;
1551
0
    if (!getStyleManager()->readDash(*stream, dashes, subType, data.length())) {
1552
0
      f << "###";
1553
0
      break;
1554
0
    }
1555
0
    image.m_posToDashMap[idPos]=dashes;
1556
0
    break;
1557
0
  }
1558
0
  case 8: {
1559
0
    f << "styles,";
1560
0
    switch (subType) {
1561
0
    case 0x54585420: { // TXT
1562
0
      Canvas5StyleManager::CharStyle font;
1563
0
      if (!getStyleManager()->readCharStyle(*stream, 0, font, false)) {
1564
0
        f << "###";
1565
0
        break;
1566
0
      }
1567
1568
0
      bool ok=true;
1569
0
      libmwaw::DebugStream f2;
1570
0
      while (true) {
1571
0
        long pos=input->tell();
1572
0
        f2.str("");
1573
0
        f2 << "Vkfl-B8-TXT [B]:";
1574
0
        if (!input->checkPosition(pos+4)) {
1575
0
          MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData[8,TXT ]: zone seems too short\n"));
1576
0
          f << "###";
1577
0
          ascFile.addPos(pos);
1578
0
          ascFile.addNote(f2.str().c_str());
1579
0
          ok=false;
1580
0
          break;
1581
0
        }
1582
1583
0
        int N=int(input->readLong(2));
1584
0
        int type=int(input->readLong(2));
1585
0
        if (N==0) {
1586
0
          ascFile.addPos(pos);
1587
0
          ascFile.addNote(f2.str().c_str());
1588
0
          break;
1589
0
        }
1590
0
        int expectedLength=type==2 ? 64 : 0;
1591
0
        if (N<0 || expectedLength==0 || (input->size()-pos-4)/expectedLength<N || pos+4+expectedLength*N>input->size()) {
1592
0
          MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData[8,TXT ]: can not read the number of data\n"));
1593
0
          f << "###";
1594
0
          ascFile.addPos(pos);
1595
0
          ascFile.addNote(f2.str().c_str());
1596
0
          ok=false;
1597
0
          break;
1598
0
        }
1599
0
        ascFile.addPos(pos);
1600
0
        ascFile.addNote(f2.str().c_str());
1601
1602
0
        for (int k=0; k<N; ++k) {
1603
0
          pos=input->tell();
1604
0
          if (!getStyleManager()->readStyleEnd(stream)) {
1605
0
            ascFile.addPos(pos);
1606
0
            ascFile.addNote("Vkfl-B8-TXT [B]###:");
1607
0
          }
1608
0
          input->seek(pos+64, librevenge::RVNG_SEEK_SET);
1609
0
        }
1610
0
      }
1611
0
      if (!ok) break;
1612
0
      ascFile.addPos(input->tell());
1613
0
      ascFile.addNote("Vkfl-B8-TXT [C]");
1614
      // 000000004e6f726d616c0000000000000000000000000000000000000000000000000000 + (color)*
1615
0
      break;
1616
0
    }
1617
    // also 0x70636567: pceg which contains a text link
1618
0
    default:
1619
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData[8]: unknown subtype=%s\n", Canvas5Structure::getString(subType).c_str()));
1620
0
      f << "###";
1621
0
      break;
1622
0
    }
1623
0
    break;
1624
0
  }
1625
0
  case 10: {
1626
0
    f << "name,";
1627
0
    std::string name;
1628
0
    for (int i=0; i<data.length(); ++i) {
1629
0
      char c=char(input->readLong(1));
1630
0
      if (!c) break;
1631
0
      name+=c;
1632
0
    }
1633
0
    f << name << ",";
1634
0
    break;
1635
0
  }
1636
0
  case 11: {
1637
0
    long len=input->readLong(4);
1638
    // v5-v8:36, v9:64
1639
0
    if (len<36 || len>data.length()) {
1640
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData[11]: can not read the header length\n"));
1641
0
      f << "###";
1642
0
      break;
1643
0
    }
1644
    // 0, pobj, MACO
1645
0
    f << "type=" << Canvas5Structure::getString(unsigned(input->readULong(4))) << ",";
1646
0
    if (len!=data.length()) { // only if type=0
1647
      // N+1 block of size 56: v<9 or 96: v==9
1648
      // XOBJ, 3e8, endian, ...
1649
0
      ascFile.addPos(data.begin()+len);
1650
0
      ascFile.addNote("Vkfl-B11-0[data]:");
1651
0
    }
1652
0
    break;
1653
0
  }
1654
0
  case 12: //  similar to some XObd data 2 block
1655
0
    if (data.length()!=40) {
1656
0
      MWAW_DEBUG_MSG(("Canvas5Image::readVKFLShapeOtherData: can not read a type12 field\n"));
1657
0
      f << "##";
1658
0
      break;
1659
0
    }
1660
0
    f << "unkn=["; // find [-62.4277,0,3,127.855,127.855,127.855,0,0,3,127.855]
1661
0
    for (int i=0; i<10; ++i)
1662
0
      f << float(input->readLong(4))/65536 << ",";
1663
0
    f << "],";
1664
0
    break;
1665
0
  default:
1666
0
    f << "##";
1667
0
    break;
1668
0
  }
1669
1670
0
  ascFile.addPos(data.begin());
1671
0
  ascFile.addNote(f.str().c_str());
1672
0
  return true;
1673
0
}
1674
1675
////////////////////////////////////////////////////////////
1676
//
1677
// Low level
1678
//
1679
////////////////////////////////////////////////////////////
1680
1681
////////////////////////////////////////////////////////////
1682
// send data to the listener
1683
////////////////////////////////////////////////////////////
1684
1685
bool Canvas5Image::send(std::shared_ptr<Canvas5ImageInternal::VKFLImage> image, MWAWListenerPtr listener,
1686
                        MWAWBox2f const &box, MWAWTransformation const &transformation) const
1687
0
{
1688
0
  if (!listener || !image) {
1689
0
    MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the image or the listener\n"));
1690
0
    return false;
1691
0
  }
1692
1693
0
  size_t shapeId=0;
1694
0
  MWAWGraphicStyle style=MWAWGraphicStyle::emptyStyle();
1695
0
  float scale[2]= {1,1};
1696
0
  for (int i=0; i<2; ++i) {
1697
0
    if (image->m_boxes[1].size()[i]>0)
1698
0
      scale[i]=box.size()[i]/image->m_boxes[1].size()[i];
1699
0
  }
1700
0
  MWAWTransformation lTransformation=transformation*
1701
0
                                     MWAWTransformation(MWAWVec3f(scale[0],0,box[0][0]-scale[0]*image->m_boxes[1][0][0]), MWAWVec3f(0,scale[1],box[0][1]-scale[0]*image->m_boxes[1][0][1]));
1702
0
  while (shapeId<image->m_shapes.size()) {
1703
0
    if (!send(*image, shapeId, listener, style, lTransformation))
1704
0
      return false;
1705
0
  }
1706
0
  return true;
1707
0
}
1708
1709
bool Canvas5Image::send(Canvas5ImageInternal::VKFLImage const &image, size_t &shapeId, MWAWListenerPtr listener,
1710
                        MWAWGraphicStyle const &/*style*/, MWAWTransformation const &transformation) const
1711
0
{
1712
0
  if (shapeId>=image.m_shapes.size()) {
1713
0
    MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the shape %d\n", int(shapeId)));
1714
0
    return false;
1715
0
  }
1716
0
  auto const &shape=image.m_shapes[shapeId++];
1717
0
  MWAWGraphicStyle lStyle;
1718
0
  auto sIt=shape.m_idToDataPos.find(0);
1719
0
  if (sIt!=shape.m_idToDataPos.end()) {
1720
0
    auto cIt=image.m_posToColorMap.find(sIt->second);
1721
0
    if (cIt==image.m_posToColorMap.end() || !cIt->second) {
1722
0
      MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the surface color %x\n", unsigned(sIt->second)));
1723
0
    }
1724
0
    else
1725
0
      getStyleManager()->updateSurfaceColor(*cIt->second, lStyle);
1726
0
  }
1727
0
  sIt=shape.m_idToDataPos.find(1);
1728
0
  if (sIt!=shape.m_idToDataPos.end()) {
1729
0
    auto cIt=image.m_posToColorMap.find(sIt->second);
1730
0
    if (cIt==image.m_posToColorMap.end() || !cIt->second) {
1731
0
      MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the line color %x\n", unsigned(sIt->second)));
1732
0
    }
1733
0
    else
1734
0
      getStyleManager()->updateLineColor(*cIt->second, lStyle);
1735
0
  }
1736
0
  lStyle.m_lineWidth=0;
1737
0
  sIt=shape.m_idToDataPos.find(2);
1738
0
  if (sIt!=shape.m_idToDataPos.end()) {
1739
0
    auto cIt=image.m_posToStrokeMap.find(sIt->second);
1740
0
    if (cIt==image.m_posToStrokeMap.end()) {
1741
0
      MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the surface stroke %x\n", unsigned(sIt->second)));
1742
0
    }
1743
0
    else {
1744
0
      auto const &stroke=cIt->second;
1745
0
      if (stroke.m_penPos>=0) {
1746
0
        auto pIt=image.m_posToPenMap.find(stroke.m_penPos);
1747
0
        if (pIt==image.m_posToPenMap.end() || !pIt->second) {
1748
0
          MWAW_DEBUG_MSG(("Canvas5Image::send: can not find pen %ld\n", stroke.m_penPos));
1749
0
        }
1750
0
        else {
1751
0
          int numLines;
1752
0
          getStyleManager()->updateLine(*pIt->second, lStyle, numLines, 0, nullptr);
1753
0
        }
1754
0
      }
1755
0
      if (stroke.m_dashPos>=0) {
1756
0
        auto dIt=image.m_posToDashMap.find(stroke.m_dashPos);
1757
0
        if (dIt==image.m_posToDashMap.end()) {
1758
0
          MWAW_DEBUG_MSG(("Canvas5Image::send: can not find dash %ld\n", stroke.m_dashPos));
1759
0
        }
1760
0
        else
1761
0
          lStyle.m_lineDashWidth=dIt->second;
1762
0
      }
1763
0
      for (int i=0; i<2; ++i) {
1764
0
        if (stroke.m_arrowPos[i]<0)
1765
0
          continue;
1766
0
        auto dIt=image.m_posToArrowMap.find(stroke.m_arrowPos[i]);
1767
0
        if (dIt==image.m_posToArrowMap.end()) {
1768
0
          MWAW_DEBUG_MSG(("Canvas5Image::send: can not find arrow %ld\n", stroke.m_arrowPos[i]));
1769
0
        }
1770
0
        else
1771
0
          lStyle.m_arrows[i]=dIt->second;
1772
0
      }
1773
0
    }
1774
0
  }
1775
0
  auto lTransformation(transformation);
1776
0
  for (int m=3; m<6; ++m) {
1777
0
    sIt=shape.m_idToDataPos.find(m);
1778
0
    if (sIt==shape.m_idToDataPos.end())
1779
0
      continue;
1780
0
    auto mIt=image.m_posToMatrixMap.find(sIt->second);
1781
0
    if (mIt==image.m_posToMatrixMap.end()) {
1782
0
      MWAW_DEBUG_MSG(("Canvas5Image::send: can not find the surface matrix %x\n", unsigned(sIt->second)));
1783
0
      continue;
1784
0
    }
1785
0
    if (m!=3)
1786
0
      continue;
1787
0
    auto const &mat=mIt->second;
1788
0
    if (mat[2]<-1e-3 || mat[2]>1e-3 || mat[5]<-1e-3 || mat[5]>1e-3) {
1789
0
      MWAW_DEBUG_MSG(("Canvas5Image::send: image matrix will be ignored\n"));
1790
0
    }
1791
0
    else
1792
0
      lTransformation*=MWAWTransformation(MWAWVec3f((float)mat[0],(float)mat[3],(float)mat[6]), MWAWVec3f((float)mat[1],(float)mat[4],(float)mat[7]));
1793
0
  }
1794
0
  MWAWGraphicShape fShape;
1795
0
  switch (shape.m_type) {
1796
0
  case 1:
1797
0
    fShape=MWAWGraphicShape::polygon(shape.m_box);
1798
0
    fShape.m_vertices=shape.m_vertices;
1799
0
    break;
1800
0
  case 2: {
1801
0
    if (shape.m_vertices.size()<2 || (shape.m_vertices.size()%4)) {
1802
0
      MWAW_DEBUG_MSG(("Canvas5Image::send[spline]: find bad N\n"));
1803
0
      return true;
1804
0
    }
1805
0
    fShape=MWAWGraphicShape::path(shape.m_box);
1806
0
    auto &path=fShape.m_path;
1807
0
    path.push_back(MWAWGraphicShape::PathData('M', shape.m_vertices[0]));
1808
0
    for (size_t p=3; p < shape.m_vertices.size(); p+=4) {
1809
0
      if (p>=4 && shape.m_vertices[p-4]!=shape.m_vertices[p-3])
1810
0
        path.push_back(MWAWGraphicShape::PathData('M', shape.m_vertices[p-3]));
1811
0
      bool hasFirstC=shape.m_vertices[p-3]!=shape.m_vertices[p-2];
1812
0
      bool hasSecondC=shape.m_vertices[p-1]!=shape.m_vertices[p];
1813
0
      if (!hasFirstC && !hasSecondC)
1814
0
        path.push_back(MWAWGraphicShape::PathData('L', shape.m_vertices[p]));
1815
0
      else
1816
0
        path.push_back(MWAWGraphicShape::PathData('C', shape.m_vertices[p], shape.m_vertices[p-2], shape.m_vertices[p-1]));
1817
0
    }
1818
0
    if (lStyle.hasSurface())
1819
0
      path.push_back(MWAWGraphicShape::PathData('Z'));
1820
0
    break;
1821
0
  }
1822
0
  case 6:
1823
0
    fShape=MWAWGraphicShape::rectangle(shape.m_box);
1824
0
    break;
1825
0
  case 7:
1826
0
    fShape=MWAWGraphicShape::circle(shape.m_box);
1827
0
    break;
1828
0
  case 8:
1829
0
    fShape=MWAWGraphicShape::rectangle(shape.m_box, MWAWVec2f(shape.m_locals[0], shape.m_locals[1]));
1830
0
    break;
1831
0
  case 9: // checkme: maybe better to use shape.m_vertices[0-1] if it exists...
1832
0
    if (shape.m_vertices.size()==2)
1833
0
      fShape=MWAWGraphicShape::line(shape.m_vertices[0], shape.m_vertices[1]);
1834
0
    else
1835
0
      fShape=MWAWGraphicShape::line(shape.m_box[0], shape.m_box[1]);
1836
0
    break;
1837
0
  case 10: {
1838
0
    float angles[]= {shape.m_locals[0], shape.m_locals[1]};
1839
0
    int angle[2] = { int(90-angles[0]), int(90-angles[0]-angles[1]) };
1840
0
    if (angles[0]<0)
1841
0
      std::swap(angle[0],angle[1]);
1842
0
    else if (angles[0]>=360)
1843
0
      angle[0]-=359;
1844
0
    if (angle[1]>360) {
1845
0
      int numLoop=int(angle[1]/360)-1;
1846
0
      angle[0]-=numLoop*360;
1847
0
      angle[1]-=numLoop*360;
1848
0
      while (angle[1] > 360) {
1849
0
        angle[0]-=360;
1850
0
        angle[1]-=360;
1851
0
      }
1852
0
    }
1853
0
    if (angle[0] < -360) {
1854
0
      int numLoop=int(angle[0]/360)+1;
1855
0
      angle[0]-=numLoop*360;
1856
0
      angle[1]-=numLoop*360;
1857
0
      while (angle[0] < -360) {
1858
0
        angle[0]+=360;
1859
0
        angle[1]+=360;
1860
0
      }
1861
0
    }
1862
    // we must compute the real bd box
1863
0
    float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
1864
0
    int limitAngle[2];
1865
0
    for (int i = 0; i < 2; ++i)
1866
0
      limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
1867
0
    for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) {
1868
0
      float ang = (bord == limitAngle[0]) ? float(angle[0]) :
1869
0
                  (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord);
1870
0
      ang *= float(M_PI/180.);
1871
0
      float actVal[2] = { std::cos(ang), -std::sin(ang)};
1872
0
      if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
1873
0
      else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
1874
0
      if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
1875
0
      else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
1876
0
    }
1877
0
    MWAWBox2f circleBox=shape.m_box;
1878
    // we have the shape box, we need to reconstruct the circle box
1879
0
    if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) {
1880
0
      float scaling[2]= { (shape.m_box[1][0]-shape.m_box[0][0])/(maxVal[0]-minVal[0]),
1881
0
                          (shape.m_box[1][1]-shape.m_box[0][1])/(maxVal[1]-minVal[1])
1882
0
                        };
1883
0
      for (auto &s : scaling) {
1884
0
        if (s>1e7)
1885
0
          s=100;
1886
0
        else if (s<-1e7)
1887
0
          s=-100;
1888
0
      }
1889
0
      float constant[2]= { shape.m_box[0][0]-minVal[0] *scaling[0], shape.m_box[0][1]-minVal[1] *scaling[1]};
1890
0
      circleBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]),
1891
0
                          MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1]));
1892
0
    }
1893
0
    fShape = MWAWGraphicShape::pie(shape.m_box, circleBox, MWAWVec2f(float(angle[0]), float(angle[1])));
1894
0
    break;
1895
0
  }
1896
0
  case 11:
1897
0
  case 12: {
1898
0
    if (shapeId+size_t(shape.m_subType)<shapeId ||
1899
0
        shapeId+size_t(shape.m_subType)>image.m_shapes.size()) {
1900
0
      MWAW_DEBUG_MSG(("Canvas5Image::send[group]: find bad N=%d\n", int(shape.m_subType)));
1901
0
      return true;
1902
0
    }
1903
0
    if (shape.m_subType<=1)
1904
0
      return true;
1905
0
    MWAWPosition pos(MWAWVec2f(0,0), MWAWVec2f(100,100), librevenge::RVNG_POINT); // checkme shape box is not valid
1906
0
    pos.m_anchorTo = MWAWPosition::Page;
1907
0
    listener->openGroup(pos);
1908
0
    for (size_t i=0; i<size_t(shape.m_subType); ++i) {
1909
0
      if (!send(image, shapeId, listener, lStyle, lTransformation))
1910
0
        break;
1911
0
    }
1912
0
    listener->closeGroup();
1913
0
    return true;
1914
0
  }
1915
0
  case 14:
1916
0
    switch (shape.m_subType) {
1917
0
    case 0x706f626a:
1918
0
    case 0x8F909d96: {
1919
0
      if (shape.m_bitmap.isEmpty()) {
1920
0
        MWAW_DEBUG_MSG(("Canvas5Image::send[pobj]: can not find the bitmap\n"));
1921
0
        return true;
1922
0
      }
1923
1924
0
      MWAWTransformation transf;
1925
0
      float rotation=0;
1926
0
      MWAWVec2f shearing;
1927
0
      if (!lTransformation.isIdentity() && lTransformation.decompose(rotation,shearing,transf,shape.m_box.center())) {
1928
0
        MWAWBox2f shapeBox=transf*shape.m_box;
1929
0
        MWAWPosition pos(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
1930
0
        pos.m_anchorTo = MWAWPosition::Page;
1931
0
        lStyle.m_rotate=-rotation;
1932
0
        listener->insertPicture(pos, shape.m_bitmap, lStyle);
1933
0
      }
1934
0
      else {
1935
0
        MWAWPosition pos(shape.m_box[0], shape.m_box.size(), librevenge::RVNG_POINT);
1936
0
        pos.m_anchorTo = MWAWPosition::Page;
1937
0
        listener->insertPicture(pos, shape.m_bitmap, lStyle);
1938
0
      }
1939
0
      return true;
1940
0
    }
1941
0
    case 0x4d41434f: { // MACO
1942
0
      if (!shape.m_macoImage) {
1943
0
        MWAW_DEBUG_MSG(("Canvas5Image::send[pobj]: can not find the macro imag\n"));
1944
0
        return true;
1945
0
      }
1946
0
      return send(shape.m_macoImage, listener, shape.m_box, lTransformation);
1947
0
    }
1948
0
    default:
1949
0
      if (!shape.m_special) {
1950
0
        MWAW_DEBUG_MSG(("Canvas5Image::send[special]: can not find the special data\n"));
1951
0
        return true;
1952
0
      }
1953
0
      else {
1954
0
        Canvas5Graph::LocalState lState;
1955
0
        lState.m_position=MWAWPosition(shape.m_box[0], shape.m_box.size(), librevenge::RVNG_POINT);
1956
0
        lState.m_position.m_anchorTo = MWAWPosition::Page;
1957
0
        lState.m_style=lStyle;
1958
0
        lState.m_transform=lTransformation;
1959
0
        return m_mainParser->m_graphParser->sendSpecial(listener, *shape.m_special, lState);
1960
0
      }
1961
0
      break;
1962
0
    }
1963
0
    break;
1964
0
  default:
1965
0
    MWAW_DEBUG_MSG(("Canvas5Image::send: sending type=%d is not implemented\n", shape.m_type));
1966
0
    return true;
1967
0
  }
1968
0
  if (!lTransformation.isIdentity())
1969
0
    fShape=fShape.transform(lTransformation);
1970
0
  MWAWBox2f shapeBox=fShape.getBdBox();
1971
0
  MWAWPosition sPosition(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
1972
0
  listener->insertShape(sPosition, fShape, lStyle);
1973
0
  return true;
1974
0
}
1975
1976
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: