Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/CorelPainterParser.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 <iomanip>
35
#include <iostream>
36
#include <limits>
37
#include <set>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWFontConverter.hxx"
43
#include "MWAWGraphicListener.hxx"
44
#include "MWAWGraphicShape.hxx"
45
#include "MWAWHeader.hxx"
46
#include "MWAWParagraph.hxx"
47
#include "MWAWPictBitmap.hxx"
48
#include "MWAWPictData.hxx"
49
#include "MWAWPosition.hxx"
50
#include "MWAWSubDocument.hxx"
51
52
#include "CorelPainterParser.hxx"
53
54
/** Internal: the structures of a CorelPainterParser */
55
namespace CorelPainterParserInternal
56
{
57
////////////////////////////////////////////////////////////
58
//! Internal: a node of a CorelPainterParser
59
struct Node {
60
  //! constructor
61
  Node()
62
4.55k
  {
63
9.10k
    for (auto &v: m_values) v=0;
64
4.55k
  }
65
  //! the child
66
  std::shared_ptr<Node> m_childs[2];
67
  //! the values
68
  int m_values[2];
69
};
70
////////////////////////////////////////////////////////////
71
//! Internal: a zone header of a CorelPainterParser
72
struct ZoneHeader {
73
  //! constructor
74
  ZoneHeader()
75
11.7k
    : m_isMainZone(false)
76
11.7k
    , m_dimension()
77
11.7k
    , m_origin()
78
11.7k
    , m_pixelByInch(0)
79
11.7k
    , m_numTreeNodes(0)
80
11.7k
    , m_tree()
81
11.7k
    , m_bitmapPos(0)
82
11.7k
    , m_rsrcDataPos(0)
83
11.7k
    , m_nextPos(0)
84
11.7k
    , m_rsrcMap()
85
11.7k
  {
86
23.5k
    for (auto &f : m_flags) f=0;
87
11.7k
  }
88
  //! check if it is a picture header
89
  bool isBitmap() const
90
9.09k
  {
91
9.09k
    if (m_dimension[0]<=2 || m_dimension[1]<=2) return false;
92
8.51k
    long endPos=m_rsrcDataPos>0 ? m_rsrcDataPos : m_nextPos;
93
8.51k
    if (m_bitmapPos>=endPos) return false;
94
8.43k
    if ((m_flags[1]&1) && m_bitmapPos+4*long(m_dimension[0])*long(m_dimension[1])>endPos)
95
403
      return false;
96
8.02k
    return true;
97
8.43k
  }
98
  //! a flag to know if this is the main picture
99
  bool m_isMainZone;
100
  //! the bitmap dimension
101
  MWAWVec2i m_dimension;
102
  //! the bitmap origin
103
  MWAWVec2i m_origin;
104
  //! number of pixel by inch
105
  int m_pixelByInch;
106
  /// the number of Huffman node
107
  int m_numTreeNodes;
108
  /// the Huffman tree
109
  std::shared_ptr<Node> m_tree;
110
  /// the bitmap position
111
  long m_bitmapPos;
112
  //! the resource data position
113
  long m_rsrcDataPos;
114
  //! the next zone position
115
  long m_nextPos;
116
  //! the main zone flags
117
  int m_flags[2];
118
  //! the different rsrc zone (v7)
119
  std::map<std::string, MWAWEntry> m_rsrcMap;
120
};
121
122
////////////////////////////////////////
123
//! Internal: the state of a CorelPainterParser
124
struct State {
125
  //! constructor
126
  State()
127
19.9k
    : m_zoneList()
128
19.9k
    , m_pixelByInch(0)
129
19.9k
  {
130
19.9k
  }
131
  //! the main zone header
132
  std::vector<ZoneHeader> m_zoneList;
133
  //! number of pixel by inch
134
  int m_pixelByInch;
135
};
136
137
////////////////////////////////////////
138
//! Internal: the subdocument of a CorelPainterParser
139
class SubDocument final : public MWAWSubDocument
140
{
141
public:
142
  SubDocument(CorelPainterParser &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry, MWAWEntry const &unicodeEntry)
143
0
    : MWAWSubDocument(&pars, input, entry)
144
0
    , m_unicodeEntry(unicodeEntry)
145
0
  {
146
0
  }
147
148
  //! destructor
149
0
  ~SubDocument() final {}
150
151
  //! operator!=
152
  bool operator!=(MWAWSubDocument const &doc) const final
153
0
  {
154
0
    if (MWAWSubDocument::operator!=(doc)) return true;
155
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
156
0
    if (!sDoc) return true;
157
0
    return m_unicodeEntry!=sDoc->m_unicodeEntry;
158
0
  }
159
  //! the parser function
160
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
161
162
private:
163
  //! the unicode entry
164
  MWAWEntry m_unicodeEntry;
165
166
  SubDocument(SubDocument const &orig) = delete;
167
  SubDocument &operator=(SubDocument const &orig) = delete;
168
};
169
170
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType)
171
0
{
172
0
  if (!listener || !listener->canWriteText()) {
173
0
    MWAW_DEBUG_MSG(("CorelPainterParserInternal::SubDocument::parse: no listener\n"));
174
0
    return;
175
0
  }
176
0
  auto *parser=dynamic_cast<CorelPainterParser *>(m_parser);
177
0
  if (!parser) {
178
0
    MWAW_DEBUG_MSG(("CorelPainterParserInternal::SubDocument::parse: no parser\n"));
179
0
    return;
180
0
  }
181
0
  long pos = m_input->tell();
182
0
  parser->sendText(m_zone, m_unicodeEntry);
183
0
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
184
0
}
185
186
}
187
188
////////////////////////////////////////////////////////////
189
// constructor/destructor, ...
190
////////////////////////////////////////////////////////////
191
CorelPainterParser::CorelPainterParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
192
9.36k
  : MWAWGraphicParser(input, rsrcParser, header)
193
9.36k
  , m_state()
194
9.36k
{
195
9.36k
  init();
196
9.36k
}
197
198
CorelPainterParser::~CorelPainterParser()
199
9.36k
{
200
9.36k
}
201
202
void CorelPainterParser::init()
203
9.36k
{
204
9.36k
  resetGraphicListener();
205
9.36k
  setAsciiName("main-1");
206
207
9.36k
  m_state.reset(new CorelPainterParserInternal::State);
208
209
9.36k
  getPageSpan().setMargins(0.1);
210
9.36k
}
211
212
////////////////////////////////////////////////////////////
213
// the parser
214
////////////////////////////////////////////////////////////
215
void CorelPainterParser::parse(librevenge::RVNGDrawingInterface *docInterface)
216
1.17k
{
217
1.17k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
218
1.17k
  bool ok = false;
219
1.17k
  try {
220
    // create the asciiFile
221
1.17k
    ascii().setStream(getInput());
222
1.17k
    ascii().open(asciiName());
223
1.17k
    checkHeader(nullptr);
224
1.17k
    ok = createZones();
225
1.17k
    if (ok) {
226
1.17k
      createDocument(docInterface);
227
1.17k
      for (auto const &z : m_state->m_zoneList) {
228
1.17k
        if (z.isBitmap())
229
1.17k
          sendBitmap(z);
230
5
        else
231
5
          sendZone(z);
232
1.17k
      }
233
1.17k
    }
234
1.17k
    ascii().reset();
235
1.17k
  }
236
1.17k
  catch (...) {
237
0
    MWAW_DEBUG_MSG(("CorelPainterParser::parse: exception catched when parsing\n"));
238
0
    ok = false;
239
0
  }
240
241
1.17k
  resetGraphicListener();
242
1.17k
  if (!ok) throw(libmwaw::ParseException());
243
1.17k
}
244
245
////////////////////////////////////////////////////////////
246
// create the document
247
////////////////////////////////////////////////////////////
248
void CorelPainterParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
249
1.17k
{
250
1.17k
  if (!documentInterface) return;
251
1.17k
  if (getGraphicListener()) {
252
0
    MWAW_DEBUG_MSG(("CorelPainterParser::createDocument: listener already exist\n"));
253
0
    return;
254
0
  }
255
1.17k
  if (m_state->m_zoneList.empty()) {
256
0
    MWAW_DEBUG_MSG(("CorelPainterParser::createDocument: can not find any zone\n"));
257
0
    return;
258
0
  }
259
1.17k
  auto const &zone=m_state->m_zoneList[0];
260
1.17k
  int const &pixelByInch=m_state->m_pixelByInch;
261
1.17k
  if (pixelByInch>0 && pixelByInch<0xFFFF) { // time to update the page dimension
262
841
    getPageSpan().setFormWidth(0.2+double(zone.m_dimension[0])/double(pixelByInch));
263
841
    getPageSpan().setFormLength(0.2+double(zone.m_dimension[1])/double(pixelByInch));
264
841
  }
265
  // create the page list
266
1.17k
  MWAWPageSpan ps(getPageSpan());
267
1.17k
  ps.setPageSpan(1);
268
1.17k
  std::vector<MWAWPageSpan> pageList(1,ps);
269
1.17k
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
270
1.17k
  setGraphicListener(listen);
271
1.17k
  listen->startDocument();
272
1.17k
}
273
274
275
////////////////////////////////////////////////////////////
276
//
277
// Intermediate level
278
//
279
////////////////////////////////////////////////////////////
280
bool CorelPainterParser::createZones()
281
1.17k
{
282
1.17k
  MWAWInputStreamPtr input = getInput();
283
1.17k
  input->seek(0, librevenge::RVNG_SEEK_SET);
284
2.34k
  while (!input->isEnd()) {
285
1.26k
    long pos=input->tell();
286
1.26k
    CorelPainterParserInternal::ZoneHeader zone;
287
1.26k
    if (!readZoneHeader(zone) || input->tell()>zone.m_nextPos) {
288
84
      MWAW_DEBUG_MSG(("CorelPainterParser::createZones: find extra data\n"));
289
84
      ascii().addPos(pos);
290
84
      ascii().addNote("Entries(UnknownD):###extra");
291
84
      break;
292
84
    }
293
1.17k
    if (zone.m_rsrcDataPos>0)
294
594
      readResourcesList(zone);
295
1.17k
    m_state->m_zoneList.push_back(zone);
296
1.17k
    input->seek(zone.m_nextPos, librevenge::RVNG_SEEK_SET);
297
1.17k
  }
298
1.17k
  if (m_state->m_zoneList.empty() || !m_state->m_zoneList[0].isBitmap()) {
299
0
    MWAW_DEBUG_MSG(("CorelPainterParser::createZones: oops the first zone is not a picture\n"));
300
0
    return false;
301
0
  }
302
303
1.17k
  return true;
304
1.17k
}
305
306
std::shared_ptr<MWAWPict> CorelPainterParser::readBitmap(CorelPainterParserInternal::ZoneHeader const &zone)
307
1.17k
{
308
1.17k
  MWAWInputStreamPtr input = getInput();
309
1.17k
  auto const &dim=zone.m_dimension;
310
1.17k
  long endPos= zone.m_rsrcDataPos>0 ? zone.m_rsrcDataPos : zone.m_nextPos;
311
1.17k
  if (dim[0]<2 || dim[1]<2 || input->tell()>=endPos) return nullptr;
312
  // in the main zone, the alpha channel is used to store the selected
313
  // zone, so we must not retrieve it....
314
1.17k
  auto bitmap=std::make_shared<MWAWPictBitmapColor>(MWAWVec2i(dim[0],dim[1]), !zone.m_isMainZone);
315
1.17k
  std::vector<MWAWColor> listColor;
316
1.17k
  if (!zone.m_numTreeNodes) { // uncompressed
317
633
    libmwaw::DebugStream f;
318
633
    listColor.resize(size_t(dim[0]));
319
33.2k
    for (int i=0; i<dim[1]; ++i) {
320
33.1k
      long pos=input->tell();
321
33.1k
      f.str("");
322
33.1k
      f << "BitmapRow[unc]:";
323
33.1k
      if (pos+4*dim[0]>endPos) {
324
575
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmap: can not read some row\n"));
325
575
        f << "###";
326
575
        ascii().addPos(pos);
327
575
        ascii().addNote(f.str().c_str());
328
575
        return nullptr;
329
575
      }
330
400k
      for (size_t c=0; c<size_t(dim[0]); ++c) {
331
367k
        unsigned char data[4];
332
1.47M
        for (auto &d : data) d=static_cast<unsigned char>(input->readULong(1));
333
367k
        listColor[c]=MWAWColor(data[1],data[2],data[3],data[0]);
334
367k
      }
335
32.6k
      bitmap->setRow(i, listColor.data());
336
32.6k
      ascii().addPos(pos);
337
32.6k
      ascii().addNote(f.str().c_str());
338
32.6k
    }
339
633
  }
340
538
  else { // compressed
341
538
    std::vector<unsigned char> previousValues;
342
538
    previousValues.resize(size_t(4*dim[0]),0);
343
729
    for (int i=0; i<dim[1]; ++i) {
344
729
      long pos=input->tell();
345
729
      if (!readBitmapRow(zone, listColor, previousValues) || input->tell()>endPos) {
346
538
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmap: can not read some row\n"));
347
538
        ascii().addPos(pos);
348
538
        ascii().addNote("Entries(UnknownB):###extra");
349
538
        return nullptr;
350
538
      }
351
191
      bitmap->setRow(i, listColor.data());
352
191
    }
353
538
  }
354
58
  return bitmap;
355
1.17k
}
356
357
bool CorelPainterParser::readBitmapRow(CorelPainterParserInternal::ZoneHeader const &zone,
358
                                       std::vector<MWAWColor> &colorList, std::vector<unsigned char> &previousValues)
359
729
{
360
729
  MWAWInputStreamPtr input = getInput();
361
729
  long pos=input->tell();
362
729
  int const &dim=zone.m_dimension[0];
363
729
  if (!input->checkPosition(pos+4) || dim<=0) return false;
364
707
  libmwaw::DebugStream f;
365
707
  f << "Entries(BitmapRow):";
366
707
  int type=int(input->readLong(1)); // 0,2
367
707
  if (type==0)
368
386
    f << "huffman,";
369
321
  else if (type!=2) f << "##type=" << type << ",";
370
707
  unsigned char firstData=static_cast<unsigned char>(input->readULong(1));
371
707
  if (firstData) f << "d0=" << std::hex << int(firstData) << std::dec << ",";
372
707
  int sz=int(input->readULong(2));
373
707
  long endPos=pos+sz;
374
707
  if (sz<4 || !input->checkPosition(endPos)) {
375
253
    input->seek(pos, librevenge::RVNG_SEEK_SET);
376
253
    return false;
377
253
  }
378
454
  bool ok=true;
379
454
  std::vector<unsigned char> listColorData;
380
454
  int expectedNumData=4*dim;
381
454
  listColorData.reserve(size_t(expectedNumData));
382
454
  listColorData.push_back(firstData);
383
454
  switch (type) {
384
296
  case 0: { // use Huffman tree
385
296
    f << "*[";
386
296
    int buffer, numBitsInBuffer=0;
387
52.8k
    for (int i=0; i<expectedNumData-1; ++i) {
388
52.6k
      int value;
389
52.6k
      if (!decompressData(zone, endPos, value, buffer, numBitsInBuffer)) {
390
77
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: oops, problem when decompressing the data\n"));
391
77
        ok=false;
392
77
        f << "###";
393
77
        break;
394
77
      }
395
52.5k
      if (i<10)
396
2.83k
        f << std::hex << value << std::dec << ",";
397
52.5k
      listColorData.push_back(static_cast<unsigned char>(value));
398
52.5k
    }
399
296
    f << "...],";
400
296
    break;
401
0
  }
402
  // case 1: never seems in v1.2, maybe exists in v1.0 or v1.1 ?
403
125
  case 2: { // basic compression: 0:(n+1) following values, 1:(n+1)*val1
404
731
    while (input->tell()<endPos && listColorData.size() < size_t(expectedNumData)) {
405
693
      long actPos=input->tell();
406
693
      int subType=int(input->readULong(1));
407
693
      if (subType==0) {
408
552
        int dSz=int(input->readULong(1));
409
552
        long lastPos=actPos+3+dSz;
410
552
        if (lastPos>endPos) {
411
23
          input->seek(actPos, librevenge::RVNG_SEEK_SET);
412
23
          break;
413
23
        }
414
529
        f << "0[";
415
2.82k
        for (int i=0; i<dSz+1; ++i) {
416
2.29k
          listColorData.push_back(static_cast<unsigned char>(input->readULong(1)));
417
2.29k
          if (i<3)
418
692
            f << std::hex << int(listColorData.back()) << std::dec << ",";
419
1.60k
          else if (i==3)
420
60
            f << "...";
421
2.29k
        }
422
529
        f << "],";
423
529
      }
424
141
      else if (subType==1) {
425
83
        if (actPos+3>endPos) {
426
6
          MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: can not read the color data\n"));
427
6
          input->seek(actPos, librevenge::RVNG_SEEK_SET);
428
6
          break;
429
6
        }
430
77
        int nData=int(input->readULong(1));
431
77
        unsigned char value=static_cast<unsigned char>(input->readULong(1));
432
77
        f << "1[" << std::hex << int(value) << std::dec << "x" << (nData+1) << "],";
433
2.95k
        for (int i=0; i<nData+1; ++i) listColorData.push_back(value);
434
77
      }
435
58
      else {
436
58
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
437
58
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: unknown sub type %d\n", subType));
438
58
        ok=false;
439
58
        f << "###subType=" << subType;
440
58
        break;
441
58
      }
442
693
    }
443
125
    break;
444
0
  }
445
33
  default:
446
33
    MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: unknown type %d\n", type));
447
33
    ok=false;
448
33
    break;
449
454
  }
450
454
  if (ok && listColorData.size() != size_t(expectedNumData)) {
451
66
    MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: bad number of data\n"));
452
66
    f << "###numData,";
453
66
    ok=false;
454
66
  }
455
454
  if (input->tell()!=endPos && input->tell()+1!=endPos)
456
336
    ascii().addDelimiter(input->tell(),'|');
457
454
  if (ok && previousValues.size()!=listColorData.size()) {
458
0
    MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: oops bad previous values\n"));
459
0
    f << "###prevValues,";
460
0
    ok=false;
461
0
  }
462
454
  ascii().addPos(pos);
463
454
  ascii().addNote(f.str().c_str());
464
454
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
465
454
  if (!ok) return false;
466
  // before compressing a row, a difference to the previous row is done,
467
  // then in this row, a difference "value less previous value" is done.
468
  //
469
  // so ...
470
220
  unsigned char actCol=0;
471
41.9k
  for (size_t i=0; i<listColorData.size(); ++i) {
472
41.7k
    actCol = static_cast<unsigned char>(actCol+listColorData[i]);
473
41.7k
    previousValues[i] = static_cast<unsigned char>(previousValues[i]+actCol);
474
41.7k
  }
475
476
220
  colorList.resize(size_t(dim));
477
10.6k
  for (size_t i=0; i<size_t(dim); ++i)
478
10.4k
    colorList[i]=MWAWColor(previousValues[i+size_t(dim)], previousValues[i+2*size_t(dim)],previousValues[i+3*size_t(dim)],static_cast<unsigned char>(255-previousValues[i]));
479
220
  return true;
480
454
}
481
482
bool CorelPainterParser::decompressData(CorelPainterParserInternal::ZoneHeader const &zone,
483
                                        long endPos, int &value, int &buffer, int &numBitsInBuffer)
484
52.6k
{
485
52.6k
  if (!zone.m_tree) {
486
0
    MWAW_DEBUG_MSG(("CorelPainterParser::decompressData: can not find the main tree node\n"));
487
0
    return false;
488
0
  }
489
52.6k
  MWAWInputStreamPtr input = getInput();
490
52.6k
  long pos=input->tell();
491
52.6k
  auto node=zone.m_tree;
492
53.7k
  while (!input->isEnd()) {
493
53.7k
    if (numBitsInBuffer<=0) {
494
6.87k
      if (input->tell()>=endPos) break;
495
6.80k
      buffer=int(input->readULong(1));
496
6.80k
      numBitsInBuffer=8;
497
6.80k
    }
498
53.7k
    int c=(buffer>>(--numBitsInBuffer))&1;
499
53.7k
    if (node->m_childs[c]) {
500
1.13k
      node=node->m_childs[c];
501
1.13k
      continue;
502
1.13k
    }
503
52.5k
    value=node->m_values[c];
504
52.5k
    return true;
505
53.7k
  }
506
77
  input->seek(pos, librevenge::RVNG_SEEK_SET);
507
77
  return false;
508
52.6k
}
509
510
bool CorelPainterParser::readDouble(double &res)
511
0
{
512
0
  MWAWInputStreamPtr input = getInput();
513
0
  long pos=input->tell();
514
0
  if (!input->checkPosition(pos+4)) {
515
0
    MWAW_DEBUG_MSG(("CorelPainterParser::readDouble: can not read a double\n"));
516
0
    return false;
517
0
  }
518
0
  auto exp=int(input->readULong(1));
519
0
  int fVal=int(input->readULong(1));
520
0
  exp=(exp<<1)+(fVal>>7);
521
0
  double mantisse=(fVal&0x7f)/128., factor=1./128./256.;
522
0
  for (int j=0; j<2; ++j, factor/=256)
523
0
    mantisse+=double(input->readULong(1))*factor;
524
0
  if (exp==0 && mantisse<=0) { // initialized ?
525
0
    res=0;
526
0
    return true;
527
0
  }
528
0
  int sign = 1;
529
0
  if (exp & 0x100) {
530
0
    exp &= 0xff;
531
0
    sign = -1;
532
0
  }
533
0
  exp -= 0x7f;
534
0
  res = std::ldexp(1+mantisse, exp);
535
0
  if (sign == -1)
536
0
    res *= -1.;
537
0
  return true;
538
0
}
539
540
////////////////////////////////////////////////////////////
541
// send data
542
////////////////////////////////////////////////////////////
543
MWAWPosition CorelPainterParser::getZonePosition(CorelPainterParserInternal::ZoneHeader const &zone) const
544
58
{
545
58
  MWAWPageSpan const &page=getPageSpan();
546
58
  int pixelByInch=zone.m_pixelByInch;
547
58
  if (pixelByInch<=0 || pixelByInch>=0xffff) pixelByInch=m_state->m_pixelByInch;
548
58
  if (pixelByInch<=0 || pixelByInch>=0xffff) {
549
33
    MWAW_DEBUG_MSG(("CorelPainterParser::updatePosition: can not find the number of pixel by inch\n"));
550
33
    pixelByInch=1;
551
33
  }
552
58
  MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight()))
553
58
                   +1.f/float(pixelByInch)*MWAWVec2f(zone.m_origin),
554
58
                   1.f/float(pixelByInch)*MWAWVec2f(zone.m_dimension), librevenge::RVNG_INCH);
555
58
  pos.setRelativePosition(MWAWPosition::Page);
556
58
  pos.m_wrapping = MWAWPosition::WNone;
557
58
  return pos;
558
58
}
559
560
bool CorelPainterParser::sendBitmap(CorelPainterParserInternal::ZoneHeader const &zone)
561
1.17k
{
562
1.17k
  if (!zone.isBitmap()) {
563
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendBitmap: oops, the zone is not a bitmap\n"));
564
0
    return false;
565
0
  }
566
1.17k
  MWAWGraphicListenerPtr listener=getGraphicListener();
567
1.17k
  if (!listener) {
568
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendBitmap: can not find the listener\n"));
569
0
    return false;
570
0
  }
571
572
1.17k
  auto input=getInput();
573
1.17k
  input->seek(zone.m_bitmapPos, librevenge::RVNG_SEEK_SET);
574
1.17k
  auto bitmap=readBitmap(zone);
575
1.17k
  if (!bitmap) return false;
576
577
  // let finish to read the zone
578
58
  if (zone.m_rsrcDataPos>0 &&input->tell()<zone.m_rsrcDataPos) {
579
13
    ascii().addPos(input->tell());
580
13
    ascii().addNote("Entries(UnknownB):");
581
13
    input->seek(zone.m_rsrcDataPos, librevenge::RVNG_SEEK_SET);
582
13
  }
583
  // send the bitmap
584
58
  MWAWEmbeddedObject picture;
585
58
  if (!bitmap->getBinary(picture)) return false;
586
587
#ifdef DEBUG_WITH_FILES
588
  if (!picture.m_dataList.empty() && !picture.m_dataList[0].empty()) {
589
    static int volatile pictName = 0;
590
    libmwaw::DebugStream f;
591
    f << "Pict-" << ++pictName << ".png";
592
    libmwaw::Debug::dumpFile(picture.m_dataList[0], f.str().c_str());
593
  }
594
#endif
595
596
58
  listener->insertPicture(getZonePosition(zone), picture);
597
58
  return true;
598
58
}
599
600
bool CorelPainterParser::sendZone(CorelPainterParserInternal::ZoneHeader const &zone)
601
5
{
602
5
  MWAWGraphicListenerPtr listener=getGraphicListener();
603
5
  if (!listener) {
604
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: can not find the listener\n"));
605
0
    return false;
606
0
  }
607
608
5
  auto it=zone.m_rsrcMap.find("TEXT");
609
5
  auto unicodeIt=zone.m_rsrcMap.find("utxt");
610
5
  if (it!=zone.m_rsrcMap.end()) {
611
0
    it->second.setParsed(true);
612
0
    auto position=getZonePosition(zone);
613
0
    position.setSize(MWAWVec2f(-0.1f,-0.1f));
614
0
    std::shared_ptr<MWAWSubDocument> doc
615
0
    (new CorelPainterParserInternal::SubDocument(*this, getInput(), it->second, unicodeIt!=zone.m_rsrcMap.end() ? unicodeIt->second : MWAWEntry()));
616
0
    listener->insertTextBox(position, doc, MWAWGraphicStyle::emptyStyle());
617
0
    return true;
618
0
  }
619
620
5
  MWAWInputStreamPtr input = getInput();
621
5
  if (zone.isBitmap() || zone.m_rsrcDataPos!=0 || zone.m_bitmapPos+2 >= zone.m_nextPos) {
622
2
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: oops, unexpected zone\n"));
623
2
    return false;
624
2
  }
625
626
3
  input->seek(zone.m_bitmapPos,librevenge::RVNG_SEEK_SET);
627
3
  long pos=input->tell();
628
  // CHECKME: do we need to check the zone flags, ie find a poly with zone.m_flags[1]=4[13]10
629
3
  MWAWGraphicShape shape;
630
3
  MWAWGraphicStyle style;
631
3
  if (readPolygon(zone.m_nextPos, shape, style)) {
632
    // we must rescale the shape
633
0
    int pixelByInch=zone.m_pixelByInch;
634
0
    if (pixelByInch<=0 || pixelByInch>=0xffff) pixelByInch=m_state->m_pixelByInch;
635
0
    if (pixelByInch>0 && pixelByInch<0xff00) { // must be enough to avoid special case
636
0
      float const factor=72.f/float(pixelByInch);
637
0
      shape.scale(MWAWVec2f(factor,factor));
638
0
    }
639
0
    listener->insertShape(getZonePosition(zone), shape, style);
640
0
  }
641
3
  else {
642
3
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: sending not spline zone is not implemented\n"));
643
3
    input->seek(pos, librevenge::RVNG_SEEK_SET);
644
3
  }
645
3
  if (input->tell()!=zone.m_nextPos) {
646
3
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: find extra data\n"));
647
3
    ascii().addPos(input->tell());
648
3
    ascii().addNote("Entries(Shape):###extra");
649
3
  }
650
651
3
  return false;
652
5
}
653
654
bool CorelPainterParser::sendText(MWAWEntry const &entry, MWAWEntry const &unicodeEntry)
655
0
{
656
0
  MWAWGraphicListenerPtr listener=getGraphicListener();
657
0
  if (!listener) {
658
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendText: can not find the listener\n"));
659
0
    return false;
660
0
  }
661
662
0
  MWAWInputStreamPtr input = getInput();
663
0
  if (!entry.valid() || !input->checkPosition(entry.end()) || entry.length()<140) {
664
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendText: bad entry\n"));
665
0
    return false;
666
0
  }
667
0
  libmwaw::DebugStream f;
668
0
  f << "Entries(TextZone):";
669
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
670
0
  int val=int(input->readLong(2));
671
0
  if (val!=4) f << "f0=" << val << ",";
672
0
  int dSz=int(input->readULong(2));
673
0
  if (dSz<140 || dSz>entry.length()) {
674
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendText: unexpected data size value\n"));
675
0
    f << "###dSz=" << dSz << ",";
676
0
    ascii().addPos(entry.begin());
677
0
    ascii().addNote(f.str().c_str());
678
0
    return false;
679
0
  }
680
0
  else if (dSz!=entry.length())
681
0
    f << "header[size]=" << dSz << ",";
682
0
  int sizes[2];
683
0
  for (auto &s : sizes) s=int(input->readULong(2));
684
0
  if (sizes[0]+sizes[1]+140>dSz) {
685
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendText: unexpected size value\n"));
686
0
    f << "###text[size]=" << sizes[0] << ",";
687
0
    f << "###font[size]=" << sizes[1] << ",";
688
0
    ascii().addPos(entry.begin());
689
0
    ascii().addNote(f.str().c_str());
690
0
    return false;
691
0
  }
692
0
  f << "text[size]=" << sizes[0] << ",";
693
0
  f << "fontname[size]=" << sizes[1] << ",";
694
0
  MWAWFont font;
695
0
  MWAWParagraph para;
696
0
  double value;
697
0
  for (int i=0; i<2; ++i) { // value0=0.5?
698
0
    if (!readDouble(value)) { // must not happen as we have check the input size
699
0
      f << "###value" << i;
700
0
    }
701
0
    else {
702
0
      if (i==0) font.setSize(float(value));
703
0
      if (value<0||value>0) f << (i==0 ? "font[size]" : "value0") << "=" << value << ",";
704
0
    }
705
0
  }
706
0
  for (int i=0; i<4; ++i) {
707
0
    val=int(input->readULong(2));
708
0
    int const expected[]= {0, 0, 0, 0};
709
0
    if (val!=expected[i]) f << "f" << i+2 << "=" << std::hex << val << std::dec << ",";
710
0
  }
711
0
  double opacity=1;
712
0
  for (int i=0; i<5; ++i) {
713
0
    readDouble(value);
714
0
    double const expectedValue[]= {0,1,1,0, 0};
715
0
    if (value<expectedValue[i]||value>expectedValue[i]) {
716
0
      char const *what[]= {"traking", "leading", "opacity", "blur", "direction[rad]"};
717
0
      if (i==2) opacity=value;
718
0
      f << what[i] << "=" << value << ",";
719
0
    }
720
0
  }
721
0
  int dim[2]; // begin of first line position?
722
0
  for (auto &d : dim) d=int(input->readLong(2));
723
0
  f << "pos?=" << MWAWVec2i(dim[1],dim[0]) << ",";
724
0
  readDouble(value);
725
0
  if (value<1 || value>1) f << "value1=" << value << ",";
726
0
  for (int i=0; i<11; ++i) { // g6=0|40, g9=0|100,
727
0
    val=int(input->readULong(2));
728
0
    int const expected[]= {0, 0, 0, 0, 4, 4,
729
0
                           0, 0, 0, 0, 1
730
0
                          };
731
0
    if (i==9) {
732
0
      uint32_t fontFlags=0;
733
0
      switch ((val>>8)&3) {
734
0
      default:
735
0
      case 0:
736
0
        break;
737
0
      case 1:
738
0
        f << "shadow,";
739
0
        fontFlags |= MWAWFont::shadowBit;
740
0
        break;
741
0
      case 2:
742
0
        f << "engraved,";
743
0
        fontFlags |= MWAWFont::engraveBit;
744
0
        break;
745
0
      case 3:
746
0
        f << "##shadow=3,";
747
0
        break;
748
0
      }
749
0
      font.setFlags(fontFlags);
750
0
      val &= 0xfcff;
751
0
    }
752
0
    if (val!=expected[i]) f << "g" << i << "=" << std::hex << val << std::dec << ",";
753
0
  }
754
0
  val=int(input->readULong(1));
755
0
  switch (val) {
756
0
  case 0: // left
757
0
    break;
758
0
  case 1:
759
0
    para.m_justify = MWAWParagraph::JustificationCenter;
760
0
    f << "align=center,";
761
0
    break;
762
0
  case 2:
763
0
    para.m_justify = MWAWParagraph::JustificationRight;
764
0
    f << "align=right,";
765
0
    break;
766
0
  default:
767
0
    f << "###align=" << val << ",";
768
0
    break;
769
0
  }
770
0
  input->seek(1, librevenge::RVNG_SEEK_CUR); // unused
771
0
  ascii().addPos(entry.begin());
772
0
  ascii().addNote(f.str().c_str());
773
774
0
  long begTextPos=input->tell();
775
0
  input->seek(sizes[0], librevenge::RVNG_SEEK_CUR);
776
777
0
  long pos=input->tell();
778
0
  f.str("");
779
0
  f << "TextZone-II:";
780
0
  std::string fontName;
781
0
  for (int i=0; i<sizes[1]; ++i) fontName+=char(input->readULong(1));
782
0
  f << fontName << ",";
783
0
  if (!fontName.empty()) font.setId(getFontConverter()->getId(fontName));
784
0
  val=int(input->readULong(2));
785
0
  if (val) f << "f0=" << val << ",";
786
0
  MWAWColor color(uint32_t(input->readULong(4))>>8);
787
0
  if (!color.isBlack()) f << "col=" << color << ",";
788
0
  if (opacity>=0 && opacity<1) {
789
0
    uint32_t opValue=uint32_t(opacity*255);
790
0
    font.setColor(MWAWColor((color.value()&0xffffff)|(opValue<<24)));
791
0
  }
792
0
  else
793
0
    font.setColor(color);
794
0
  MWAWColor shadowColor(uint32_t(input->readULong(4)));
795
0
  if (!shadowColor.isBlack()) f << "col[shadow]=" << shadowColor << ",";
796
0
  for (int i=0; i<5; ++i) { // f2=0|1, f3=1
797
0
    val=int(input->readLong(2));
798
0
    if (!val) continue;
799
0
    if (i==0)
800
0
      f << "curve[type]=" << val << ","; // useme
801
0
    else
802
0
      f << "f" << i+1 << "=" << val << ",";
803
0
  }
804
0
  for (int i=0; i<6; ++i) {
805
0
    readDouble(value);
806
0
    double const expected[]= {0, 70, -70, 130, -70, 200};
807
0
    if (value<expected[i]||value>expected[i]) {
808
0
      if (i==0)
809
0
        f << "centering=" << value << ",";
810
0
      else
811
0
        f << "val" << i << "=" << value << ",";
812
0
    }
813
0
  }
814
0
  for (int i=0; i<6; ++i) { // 0
815
0
    val=int(input->readLong(2));
816
0
    if (val==0) continue;
817
0
    if (i==4)
818
0
      f << "composite[method]=" << val << ",";
819
0
    else
820
0
      f << "g" << i << "=" << val << ",";
821
0
  }
822
0
  float cDim[2];
823
0
  for (auto &d : cDim) {
824
0
    readDouble(value);
825
0
    d=float(value);
826
0
  }
827
0
  MWAWVec2f corner(cDim[0],cDim[1]); // checkme
828
0
  if (corner!=MWAWVec2f(4,4)) f << "corner?=" << corner << ",";
829
830
0
  if (input->tell()!=entry.end() && input->tell()+1!=entry.end()) {
831
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendText: find extra data\n"));
832
0
    f << "###extra,";
833
0
    if (input->tell()!=pos)
834
0
      ascii().addDelimiter(input->tell(),'|');
835
0
  }
836
0
  ascii().addPos(pos);
837
0
  ascii().addNote(f.str().c_str());
838
839
  // time to send the data
840
0
  input->seek(begTextPos, librevenge::RVNG_SEEK_SET);
841
0
  listener->setFont(font);
842
0
  listener->setParagraph(para);
843
0
  f.str("");
844
0
  f << "TextZone[txt]:";
845
0
  if (unicodeEntry.valid()) {
846
0
    for (int i=0; i<sizes[0]; ++i) {
847
0
      auto c=char(input->readULong(1));
848
0
      if (c==0)
849
0
        f << "#[0]";
850
0
      else
851
0
        f << c;
852
0
    }
853
0
    ascii().addPos(begTextPos);
854
0
    ascii().addNote(f.str().c_str());
855
856
0
    f.str("");
857
0
    f << "Rsrc[utxt]:";
858
0
    input->seek(unicodeEntry.begin(), librevenge::RVNG_SEEK_SET);
859
0
    while (input->tell() < unicodeEntry.end()) {
860
0
      auto c=static_cast<unsigned char>(input->readULong(1));
861
0
      if (c&0x80) {
862
        // send one unicode character (to be sure to create consistant utf8 string)
863
0
        unsigned char outbuf[9];
864
0
        int i=0;
865
0
        while ((c&0x40) && i<7 && input->tell() < unicodeEntry.end()) {
866
0
          outbuf[i++] = c;
867
0
          f << "#[" << std::hex << int(c) << std::dec << "]";
868
0
          c=static_cast<unsigned char>(input->readULong(1));
869
0
        }
870
0
        f << "#[" << std::hex << int(c) << std::dec << "]";
871
0
        outbuf[i++] = c;
872
0
        outbuf[i++] = 0;
873
0
        librevenge::RVNGString unicodeString;
874
0
        unicodeString.append(reinterpret_cast<char const *>(outbuf));
875
0
        listener->insertUnicodeString(unicodeString);
876
0
        continue;
877
0
      }
878
0
      if (c==0) break;
879
0
      f << c;
880
0
      switch (c) {
881
0
      case 9:
882
0
        listener->insertTab();
883
0
        break;
884
0
      case 0xd:
885
0
        listener->insertEOL();
886
0
        break;
887
0
      default:
888
0
        listener->insertCharacter(c);
889
0
        break;
890
0
      }
891
0
    }
892
0
    ascii().addPos(unicodeEntry.begin());
893
0
    ascii().addNote(f.str().c_str());
894
0
    return true;
895
0
  }
896
0
  else {
897
0
    for (int i=0; i<sizes[0]; ++i) {
898
0
      auto c=char(input->readULong(1));
899
0
      if (c==0) {
900
0
        MWAW_DEBUG_MSG(("CorelPainterParser::sendText: find char 0\n"));
901
0
        f << "#[0]";
902
0
        continue;
903
0
      }
904
0
      f << c;
905
0
      switch (c) {
906
0
      case 9:
907
0
        listener->insertTab();
908
0
        break;
909
0
      case 0xd:
910
0
        listener->insertEOL();
911
0
        break;
912
0
      default:
913
0
        listener->insertCharacter(static_cast<unsigned char>(c));
914
0
        break;
915
0
      }
916
0
    }
917
0
  }
918
0
  ascii().addPos(begTextPos);
919
0
  ascii().addNote(f.str().c_str());
920
921
0
  return true;
922
0
}
923
924
////////////////////////////////////////////////////////////
925
// read the header
926
//
927
// there exists also the movie files
928
//   00000003003c0030000000020000001400001680 (then list of colors)
929
// maybe 0 numFrame dimY dimX 0 2[some format?] 14: begin of data 1680: end of data?
930
////////////////////////////////////////////////////////////
931
bool CorelPainterParser::checkHeader(MWAWHeader *header, bool strict)
932
10.5k
{
933
10.5k
  *m_state = CorelPainterParserInternal::State();
934
10.5k
  MWAWInputStreamPtr input = getInput();
935
10.5k
  if (!input || !input->hasDataFork())
936
0
    return false;
937
938
10.5k
  input->seek(0,librevenge::RVNG_SEEK_SET);
939
10.5k
  MWAWDocument::Type type=MWAWDocument::MWAW_T_CORELPAINTER;
940
10.5k
  int const vers=1;
941
942
10.5k
  CorelPainterParserInternal::ZoneHeader zone;
943
10.5k
  if (!readZoneHeader(zone) || !zone.isBitmap())
944
6.02k
    return false;
945
4.51k
  if (strict) {
946
1.48k
    auto const &flags=zone.m_flags[1];
947
1.48k
    auto const &numTree = zone.m_numTreeNodes;
948
1.48k
    bool uncompressed=flags&1;
949
1.48k
    if ((uncompressed && numTree!=0) || (!uncompressed && numTree==0)) return false;
950
1.48k
  }
951
3.76k
  m_state->m_pixelByInch=zone.m_pixelByInch;
952
3.76k
  setVersion(vers);
953
3.76k
  if (header)
954
1.42k
    header->reset(type, vers, MWAWDocument::MWAW_K_PAINT);
955
3.76k
  return true;
956
4.51k
}
957
958
std::shared_ptr<CorelPainterParserInternal::Node> CorelPainterParser::readCompressionTree(long endPos, int numNodes)
959
3.59k
{
960
3.59k
  MWAWInputStreamPtr input = getInput();
961
3.59k
  long pos=input->tell();
962
3.59k
  if (numNodes==0) return nullptr;
963
3.59k
  if (numNodes<=0 || endPos<pos+4*numNodes) {
964
0
    MWAW_DEBUG_MSG(("CorelPainterParser::readCompressionTree: the number of nodes seems bad\n"));
965
0
    return nullptr;
966
0
  }
967
3.59k
  libmwaw::DebugStream f;
968
3.59k
  f << "Entries(Compression):";
969
3.59k
  std::vector<std::shared_ptr<CorelPainterParserInternal::Node> > nodesList;
970
3.59k
  nodesList.resize(size_t(numNodes));
971
3.59k
  nodesList[0]=std::make_shared<CorelPainterParserInternal::Node>();
972
7.18k
  for (size_t i=0; i<size_t(numNodes); ++i) {
973
4.71k
    auto &node=nodesList[i];
974
4.71k
    if (!node) {
975
527
      MWAW_DEBUG_MSG(("CorelPainterParser::readCompressionTree: can not find node %d\n", int(i)));
976
527
      return nullptr;
977
527
    }
978
11.6k
    for (int c=0; c<2; ++c) {
979
8.03k
      int val=int(input->readULong(2));
980
8.03k
      if (val&0x8000) {
981
6.48k
        node->m_values[c]=(val&0xff);
982
6.48k
        f << std::hex << node->m_values[c] << std::dec;
983
6.48k
      }
984
1.54k
      else {
985
1.54k
        int id=(val/4);
986
1.54k
        if (id>=numNodes || nodesList[size_t(id)]) {
987
588
          MWAW_DEBUG_MSG(("CorelPainterParser::readCompressionTree: problem with id=%d\n", int(id)));
988
588
          return nullptr;
989
588
        }
990
960
        nodesList[size_t(id)]=node->m_childs[c]=std::make_shared<CorelPainterParserInternal::Node>();
991
960
        f << "N" << id;
992
960
      }
993
7.44k
      if (c==0) f << "-";
994
7.44k
    }
995
3.59k
    f << ",";
996
3.59k
    nodesList.push_back(node);
997
3.59k
  }
998
2.47k
  ascii().addPos(pos);
999
2.47k
  ascii().addNote(f.str().c_str());
1000
2.47k
  return nodesList[0];
1001
3.59k
}
1002
1003
bool CorelPainterParser::readResourcesList(CorelPainterParserInternal::ZoneHeader &zone)
1004
594
{
1005
594
  MWAWInputStreamPtr input = getInput();
1006
594
  if (zone.m_rsrcDataPos<=0 || !input->checkPosition(zone.m_rsrcDataPos) ||
1007
594
      zone.m_rsrcDataPos>=zone.m_nextPos)
1008
7
    return false;
1009
1010
587
  libmwaw::DebugStream f;
1011
587
  input->seek(zone.m_rsrcDataPos, librevenge::RVNG_SEEK_SET);
1012
587
  long const &endPos = zone.m_nextPos;
1013
636
  while (input->tell()+4<=endPos && !input->isEnd()) {
1014
627
    long pos=input->tell();
1015
627
    int sz=int(input->readULong(4));
1016
627
    if (sz==0) {
1017
57
      ascii().addPos(pos);
1018
57
      ascii().addNote("_");
1019
57
      return true;
1020
57
    }
1021
570
    long endRsrcPos=pos+sz;
1022
570
    if (sz<16 || endRsrcPos>endPos) {
1023
426
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1024
426
      break;
1025
426
    }
1026
144
    f.str("");
1027
144
    f << "Entries(Rsrc):";
1028
144
    std::string type;
1029
720
    for (int i=0; i<4; ++i) type+=char(input->readULong(1));
1030
144
    f << type << ",";
1031
144
    long dSizes[2];
1032
288
    for (auto &d : dSizes) d=long(input->readULong(4));
1033
144
    if (dSizes[0]<18 || dSizes[1]<0 || dSizes[0]+dSizes[1]>sz) {
1034
95
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: the sizes seems bad\n"));
1035
95
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1036
95
      break;
1037
95
    }
1038
49
    MWAWEntry entry;
1039
49
    entry.setType(type);
1040
49
    entry.setBegin(pos+dSizes[0]);
1041
49
    entry.setEnd(endRsrcPos);
1042
49
    if (dSizes[0]>18) f << "header[sz]=" << dSizes[0] << ",";
1043
49
    if (dSizes[1]>0) {
1044
27
      if (zone.m_rsrcMap.find(type)!=zone.m_rsrcMap.end()) {
1045
0
        f << "##duplicated,";
1046
0
        MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: a entry with the same names already exist\n"));
1047
0
      }
1048
27
      else
1049
27
        zone.m_rsrcMap[type]=entry;
1050
27
      f << "data[sz]=" << dSizes[1] << ",";
1051
27
    }
1052
1053
49
    int nameSz=int(input->readULong(2));
1054
49
    if (18+nameSz>dSizes[0]) {
1055
12
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: the name size seems bad\n"));
1056
12
      f << "###name[sz]=" << nameSz << ",";
1057
12
    }
1058
37
    else if (nameSz) {
1059
      // PCOL => "Paper Color", FSKT => "Friskets", ANNO => "Annotations", NOTE => "Note Text"
1060
23
      int pSz=int(input->readULong(1));
1061
23
      if (pSz+1<=nameSz) {
1062
13
        std::string text;
1063
330
        for (int c=0; c<pSz; ++c) text+=char(input->readULong(1));
1064
13
        f << text << ",";
1065
13
      }
1066
23
    }
1067
1068
49
    if (input->tell()!=pos+dSizes[0] && input->tell()+1!=pos+dSizes[0]) {
1069
47
      f << "##extra,";
1070
47
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: find extra header data\n"));
1071
47
      ascii().addDelimiter(input->tell(),'|');
1072
47
    }
1073
49
    input->seek(pos+dSizes[0], librevenge::RVNG_SEEK_SET);
1074
49
    if (entry.valid())
1075
49
      readResource(entry);
1076
49
    ascii().addPos(pos);
1077
49
    ascii().addNote(f.str().c_str());
1078
49
    input->seek(endRsrcPos, librevenge::RVNG_SEEK_SET);
1079
49
  }
1080
530
  if (input->tell()<endPos) {
1081
530
    MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: find extra data\n"));
1082
530
    ascii().addPos(input->tell());
1083
530
    ascii().addNote("Rsrc:##extra");
1084
530
  }
1085
1086
530
  return true;
1087
587
}
1088
1089
bool CorelPainterParser::readResource(MWAWEntry const &entry)
1090
49
{
1091
49
  MWAWInputStreamPtr input = getInput();
1092
49
  if (!entry.valid() || !input->checkPosition(entry.end())) {
1093
0
    MWAW_DEBUG_MSG(("CorelPainterParser::readResource: bad entry\n"));
1094
0
    return false;
1095
0
  }
1096
49
  if (entry.isParsed() || entry.type()=="TEXT" || entry.type()=="utxt") return true;
1097
49
  entry.setParsed(true);
1098
49
  libmwaw::DebugStream f;
1099
49
  f << "Rsrc[" << entry.type() << "]:";
1100
49
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1101
  // find also ANNO,GUID with sz=0
1102
49
  int val;
1103
49
  if (entry.length()==2 && entry.type()=="TXGL") { // text extra? v8
1104
0
    val=int(input->readLong(2));
1105
0
    if (val!=1) f << "f0=" << val << ",";
1106
0
  }
1107
49
  else if (entry.length()==4 && entry.type()=="PCOL") {
1108
0
    MWAWColor col(uint32_t(input->readULong(4)));
1109
0
    if (!col.isWhite()) f << "bgColor=" << col << ",";
1110
0
  }
1111
49
  else if (entry.length()==8 && entry.type()=="MOSA") {
1112
0
    for (int i=0; i<4; ++i) { // f0=-2
1113
0
      val=int(input->readLong(2));
1114
0
      if (val) f << "f" << i << "=" << val << ",";
1115
0
    }
1116
0
  }
1117
49
  else if (entry.length()==12 && entry.type()=="WRAP") {
1118
0
    for (int i=0; i<6; ++i) { // 0
1119
0
      val=int(input->readLong(2));
1120
0
      if (val) f << "f" << i << "=" << val << ",";
1121
0
    }
1122
0
  }
1123
49
  else if (entry.length()==14 && entry.type()=="RULR") {
1124
0
    for (int i=0; i<7; ++i) { // f0=0|100, f1=2, f6=f0=0|100
1125
0
      val=int(input->readLong(2));
1126
0
      if (val) f << "f" << i << "=" << val << ",";
1127
0
    }
1128
0
  }
1129
49
  else if (entry.length()>=8 && entry.type()=="FSKT") {
1130
0
    std::string type;
1131
0
    for (int i=0; i<4; ++i) type+=char(input->readULong(1));
1132
0
    if (type!="FSKT") f << "type2=" << type << ",";
1133
0
    val=int(input->readULong(4));
1134
0
    if (val) f << "f0=" << val << ",";
1135
0
    if (val==1 && entry.length()>=24) {
1136
0
      val=int(input->readULong(4));
1137
0
      if (val!=0xc) f << "f1=" << val << ",";
1138
0
      long N=long(input->readULong(4));
1139
0
      long hSize=long(input->readULong(4));
1140
0
      if (hSize<24 || long((unsigned long)hSize+8*(unsigned long)N)<0 || hSize+8*N>entry.length()) {
1141
0
        MWAW_DEBUG_MSG(("CorelPainterParser::readResource: unsure how to read a frisket zone\n"));
1142
0
        f << "###,";
1143
0
      }
1144
0
      else {
1145
0
        for (int i=0; i<2; ++i) { // fl0=0|4a80
1146
0
          val=int(input->readULong(2));
1147
0
          if (val) f << "fl" << i << "=" << std::hex << val << std::dec << ",";
1148
0
        }
1149
0
        if (hSize>24) {
1150
          // fl0=0: no data
1151
          // fl0=4a80: 000000000000ffff00000000000000040652656374203900 + 15 points, related to polygon?
1152
0
          ascii().addDelimiter(input->tell(),'|');
1153
0
        }
1154
0
        input->seek(entry.begin()+hSize, librevenge::RVNG_SEEK_SET);
1155
0
        if (N) {
1156
0
          long pos=input->tell();
1157
0
          libmwaw::DebugStream f2;
1158
0
          f2 << "Rsrc[FSKT-pt]:";
1159
0
          for (long i=0; i<N; ++i) {
1160
0
            float dim[2];
1161
0
            for (auto &d : dim) d=float(input->readLong(4))/float(65536);
1162
0
            f2 << MWAWVec2f(dim[0],dim[1]) << ",";
1163
0
          }
1164
0
          ascii().addPos(pos);
1165
0
          ascii().addNote(f2.str().c_str());
1166
0
        }
1167
0
      }
1168
0
    }
1169
0
  }
1170
49
  else if (entry.length()==256 && entry.type()=="NOTE") {
1171
0
    int noteSz=int(input->readULong(1));
1172
0
    std::string note;
1173
0
    for (int i=0; i<noteSz; ++i) note+=char(input->readULong(1));
1174
0
    f << note << ",";
1175
0
    input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
1176
0
  }
1177
49
  else if (entry.length()==544 && entry.type()=="IPAR") {
1178
0
    for (int i=0; i<16; ++i) { // f2=0|10,f5=0|100,f14=1,f15=-1
1179
0
      val=int(input->readLong(2));
1180
0
      if (val) f << "f" << i << "=" << val << ",";
1181
0
    }
1182
0
    int sSz=int(input->readULong(1));
1183
0
    if (sSz && sSz<=31) {
1184
0
      std::string name;
1185
0
      for (int i=0; i<sSz; ++i) name+=char(input->readULong(1));
1186
0
      f << name << ",";
1187
0
    }
1188
0
    else if (sSz) {
1189
0
      MWAW_DEBUG_MSG(("CorelPainterParser::readResource: can not read a name\n"));
1190
0
      f << "##sSz=" << sSz << ",";
1191
0
    }
1192
0
    input->seek(entry.begin()+64, librevenge::RVNG_SEEK_SET);
1193
0
    for (int i=0; i<240; ++i) { // 0
1194
0
      val=int(input->readLong(2));
1195
0
      if (val) f << "g" << i << "=" << val << ",";
1196
0
    }
1197
0
  }
1198
  // v18
1199
49
  else if (entry.length()==6 && entry.type()=="CSPR") {
1200
0
    for (int i=0; i<3; ++i) { // f1=3f00
1201
0
      val=int(input->readULong(2));
1202
0
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1203
0
    }
1204
0
  }
1205
49
  else if (entry.length()==2 && entry.type()=="CSTI") { // 0
1206
0
    val=int(input->readLong(2));
1207
0
    if (val) f << "f0=" << val << ",";
1208
0
  }
1209
#ifdef DEBUG_WITH_FILES
1210
  // v10
1211
  else if (entry.length()>8 && entry.type()=="RETP") { // Painter-X small preview bitmap (one by file)
1212
    int dim[4];
1213
    for (auto &d : dim) d=int(input->readULong(2));
1214
    f << "dim=" << MWAWVec2i(dim[1],dim[0]) << "x" << MWAWVec2i(dim[3],dim[2]) << ",";
1215
    if (entry.length()!=8+4*long(dim[2])*long(dim[3])) {
1216
      MWAW_DEBUG_MSG(("CorelPainterParser::readResource: bitmap size seem bad\n"));
1217
      f << "##";
1218
      ascii().addPos(entry.begin());
1219
      ascii().addNote(f.str().c_str());
1220
      return true;
1221
    }
1222
1223
    ascii().addPos(entry.begin());
1224
    ascii().addNote(f.str().c_str());
1225
1226
    MWAWPictBitmapColor bitmap(MWAWVec2i(dim[3],dim[2]), false);
1227
    std::vector<MWAWColor> listColor;
1228
    listColor.resize(size_t(dim[3]));
1229
    for (int i=0; i<dim[2]; ++i) {
1230
      long pos=input->tell();
1231
      f.str("");
1232
      f << "Rsrc[RETP-" << i << ":";
1233
      if (pos+4*dim[2]>entry.end()) {
1234
        MWAW_DEBUG_MSG(("CorelPainterParser::readResource: can not read some row\n"));
1235
        f << "###";
1236
        ascii().addPos(pos);
1237
        ascii().addNote(f.str().c_str());
1238
        return false;
1239
      }
1240
      for (size_t c=0; c<size_t(dim[3]); ++c) {
1241
        unsigned char data[4];
1242
        for (auto &d : data) d=static_cast<unsigned char>(input->readULong(1));
1243
        listColor[c]=MWAWColor(data[1],data[2],data[3],data[0]);
1244
      }
1245
      bitmap.setRow(i, listColor.data());
1246
      ascii().addPos(pos);
1247
      ascii().addNote(f.str().c_str());
1248
    }
1249
    MWAWEmbeddedObject picture;
1250
    if (bitmap.getBinary(picture) && !picture.m_dataList.empty() && !picture.m_dataList[0].empty()) {
1251
      static int volatile pictName = 0;
1252
      libmwaw::DebugStream f2;
1253
      f2 << "Preview" << ++pictName << ".ppm";
1254
      libmwaw::Debug::dumpFile(picture.m_dataList[0], f2.str().c_str());
1255
    }
1256
    return true;
1257
  }
1258
  else if (entry.type()=="PRFL" && entry.length()>0) {
1259
    // look like a standard .icc file
1260
    MWAW_DEBUG_MSG(("CorelPainterParser::readResouce: this file contains a color profile, unimplemented\n"));
1261
    librevenge::RVNGBinaryData file;
1262
    input->readDataBlock(entry.length(), file);
1263
    libmwaw::Debug::dumpFile(file, "profile.icc");
1264
    ascii().skipZone(entry.begin(), entry.end()-1);
1265
    return true;
1266
  }
1267
  // v18
1268
  else if (entry.type()=="TJPG" && entry.length()>0) {
1269
    librevenge::RVNGBinaryData file;
1270
    input->readDataBlock(entry.length(), file);
1271
    static int volatile pictName = 0;
1272
    libmwaw::DebugStream f2;
1273
    f2 << "Pict" << ++pictName << ".jpg";
1274
    libmwaw::Debug::dumpFile(file, f2.str().c_str());
1275
    ascii().skipZone(entry.begin(), entry.end()-1);
1276
    return true;
1277
  }
1278
  else if (entry.type()=="FSPG" && entry.length()>22) { // paper texture bitamp
1279
    val=int(input->readLong(2));
1280
    if (val!=2) f << "f0=" << val << ",";
1281
    int dim[2];
1282
    for (auto &d : dim) d=int(input->readULong(2));
1283
    f << "dim=" << MWAWVec2i(dim[0], dim[1]) << ",";
1284
    for (int i=0; i<8; ++i) { // f2=1[number of plane?], f8=22?
1285
      val=int(input->readLong(2));
1286
      if (val) f << "f" << i+1 << "=" << val << ",";
1287
    }
1288
    if (dim[0]<=0 || dim[1]<=0 || (entry.length()-22)/dim[0]!=dim[1]) {
1289
      MWAW_DEBUG_MSG(("CorelPainterParser::readResouce[FSPG]: can not read the color paper\n"));
1290
      f << "###";
1291
    }
1292
    else {
1293
      MWAWPictBitmapIndexed bitmap(MWAWVec2i(dim[0],dim[1]));
1294
      std::vector<MWAWColor> indexes;
1295
      indexes.reserve(256);
1296
      for (int i=0; i<=255; ++i) indexes.push_back(MWAWColor(static_cast<unsigned char>(i),static_cast<unsigned char>(i),static_cast<unsigned char>(i)));
1297
      bitmap.setColors(indexes);
1298
      bool ok=true;
1299
      for (int r=0; r<dim[1]; ++r) {
1300
        unsigned long numReads;
1301
        uint8_t const *values=input->read(size_t(dim[0]), numReads);
1302
        if (!values || numReads!=static_cast<unsigned long>(dim[0])) {
1303
          MWAW_DEBUG_MSG(("CorelPainterParser::readResouce[FSPG]: can not read row %d\n", r));
1304
          f << "###";
1305
          ok=false;
1306
          break;
1307
        }
1308
        bitmap.setRow(r, reinterpret_cast<unsigned char const *>(values));
1309
      }
1310
      MWAWEmbeddedObject picture;
1311
      if (ok && bitmap.getBinary(picture) && !picture.isEmpty() && !picture.m_dataList[0].empty()) {
1312
        static int volatile pictName = 0;
1313
        libmwaw::DebugStream f2;
1314
        f2 << "PaperTexture" << ++pictName << ".png";
1315
        libmwaw::Debug::dumpFile(picture.m_dataList[0], f2.str().c_str());
1316
        ascii().skipZone(entry.begin(), entry.end()-1);
1317
        return true;
1318
      }
1319
    }
1320
  }
1321
  // else if (entry.type()=="APSF" && entry.length()>=1096) some preferences' file? probably safe to ignore...
1322
#endif
1323
49
  if (input->tell()!=entry.end()) {
1324
49
    f << "#extra,";
1325
49
    if (input->tell()!=entry.begin())
1326
0
      ascii().addDelimiter(input->tell(),'|');
1327
49
  }
1328
49
  ascii().addPos(entry.begin());
1329
49
  ascii().addNote(f.str().c_str());
1330
49
  return true;
1331
49
}
1332
1333
bool CorelPainterParser::readZoneHeader(CorelPainterParserInternal::ZoneHeader &zone)
1334
11.7k
{
1335
11.7k
  MWAWInputStreamPtr input = getInput();
1336
11.7k
  libmwaw::DebugStream f;
1337
11.7k
  long pos=input->tell();
1338
11.7k
  if (!input->checkPosition(pos+64) || input->readULong(2)!=2) return false;
1339
11.6k
  f << "Entries(ZoneHeader):";
1340
1341
11.6k
  int headerSize=64;
1342
11.6k
  zone.m_isMainZone=pos==0;
1343
11.6k
  zone.m_flags[0]=int(input->readULong(2)); // 2000: in painter v6 file
1344
11.6k
  if (zone.m_flags[0]&0x2000) f << "extra[pict],";
1345
11.6k
  if (zone.m_flags[0]&0xdfff) f << "fl0=" << std::hex << (zone.m_flags[0]&0xdfff) << std::dec << ",";
1346
11.6k
  int dim[2];
1347
23.3k
  for (auto &d : dim) d=int(input->readLong(2));
1348
11.6k
  zone.m_dimension=MWAWVec2i(dim[1],dim[0]);
1349
11.6k
  if (dim[0] || dim[1]) f << "dim=" << zone.m_dimension << ",";
1350
11.6k
  zone.m_flags[1]=int(input->readULong(2)); // main 2, subzone 510(bitmap?)|4110
1351
11.6k
  if (zone.m_flags[1]&1) f << "uncompressed,";
1352
11.6k
  if (zone.m_flags[1]&2) {
1353
1.36k
    f << "has[order],";
1354
1.36k
    headerSize+=256;
1355
1.36k
    if (!input->checkPosition(pos+headerSize)) return false;
1356
1.36k
  }
1357
  // zone.m_flags[1]&0x10 local shape?
1358
  // (zone.m_flags[1]>>16): 0 main picture, 5: floater with IPAR&FSKT, 7: floater with IPAR, 41: shape?
1359
11.5k
  if (zone.m_flags[1]&0xfffc)
1360
5.50k
    f << "fl1=" << std::hex << (zone.m_flags[1]&0xfffc) << std::dec << ",";
1361
11.5k
  int val;
1362
34.7k
  for (int i=0; i<2; ++i) { // checkme: f2=num of ordering?
1363
23.1k
    val=int(input->readULong(2));
1364
23.1k
    int const expected[] = {7,0x100};
1365
23.1k
    if (val!=expected[i]) f << "f" << i+1 << "=" << val << ",";
1366
23.1k
  }
1367
11.5k
  auto &bitmapPos=zone.m_bitmapPos;
1368
11.5k
  bitmapPos=long(input->readULong(4));
1369
11.5k
  if (bitmapPos<headerSize || !input->checkPosition(pos+bitmapPos)) return false;
1370
8.27k
  bitmapPos+=pos;
1371
41.3k
  for (int i=0; i<4; ++i) {
1372
33.0k
    val=int(input->readLong(2));
1373
33.0k
    if (val) f << "f" << i+3 << "=" << val << ",";
1374
33.0k
  }
1375
8.27k
  val=int(input->readULong(4));
1376
8.27k
  if (val && pos+val!=bitmapPos) f << "bitmap[pos2]=" << val << ","; // use me
1377
8.27k
  zone.m_pixelByInch=int(input->readULong(2));
1378
8.27k
  if (zone.m_pixelByInch == 0xFFFF)
1379
628
    f << "pixel[inch]=inherited,";
1380
7.64k
  else if (zone.m_pixelByInch)
1381
5.29k
    f << "pixel[inch]=" << zone.m_pixelByInch << ",";
1382
8.27k
  val=int(input->readULong(2));
1383
8.27k
  if (val) f << "f7=" << std::hex << val << std::dec << ",";
1384
8.27k
  auto &numTree=zone.m_numTreeNodes;
1385
8.27k
  numTree=int(input->readULong(2));
1386
8.27k
  if (numTree>=256 || pos+headerSize+4*numTree > bitmapPos) return false;
1387
15.7k
  for (auto &d : dim) d=int(input->readLong(2));
1388
7.86k
  zone.m_origin=MWAWVec2i(dim[1],dim[0]);
1389
7.86k
  if (dim[0] || dim[1])
1390
5.51k
    f << "orig=" << zone.m_origin << ",";
1391
7.86k
  long lVal=int(input->readULong(4));
1392
7.86k
  if (lVal==0x3fe66666)
1393
0
    f << "main,";
1394
7.86k
  else if (lVal)
1395
6.26k
    f << "zone[type]=" << std::hex << lVal << std::dec << ",";
1396
39.3k
  for (int i=0; i<4; ++i) { // 0
1397
31.4k
    val=int(input->readLong(2));
1398
31.4k
    if (val) f << "g" << i << "=" << val << ",";
1399
31.4k
  }
1400
7.86k
  long prevPos=bitmapPos;
1401
23.5k
  for (int z=0; z<2; ++z) {
1402
15.7k
    long newPos=long(input->readULong(4));
1403
15.7k
    if (newPos<=0) continue;
1404
13.9k
    newPos+=pos;
1405
13.9k
    if (input->checkPosition(newPos) && newPos>=prevPos) {
1406
3.53k
      if (z==0)
1407
2.96k
        zone.m_rsrcDataPos=newPos;
1408
571
      else
1409
571
        zone.m_nextPos=newPos;
1410
3.53k
      prevPos=newPos;
1411
3.53k
    }
1412
10.4k
    else {
1413
10.4k
      MWAW_DEBUG_MSG(("CorelPainterParser::readZoneHeader: zone pos%d seems bad\n", z));
1414
10.4k
      f << "###";
1415
10.4k
    }
1416
13.9k
    f << (z==0 ? "rsrc" : "next") << "[pos]=" << std::hex << newPos << std::dec << ",";
1417
13.9k
  }
1418
7.86k
  if (zone.m_nextPos==0) zone.m_nextPos=input->size();
1419
23.5k
  for (int i=0; i<2; ++i) { // 0
1420
15.7k
    val=int(input->readLong(2));
1421
15.7k
    if (val) f << "g" << i+2 << "=" << val << ",";
1422
15.7k
  }
1423
7.86k
  ascii().addPos(pos);
1424
7.86k
  ascii().addNote(f.str().c_str());
1425
1426
7.86k
  if (zone.m_flags[1]&2) { // read the ordering
1427
267
    pos=input->tell();
1428
267
    f.str("");
1429
267
    f << "Entries(Ordering):[";
1430
68.6k
    for (int i=0; i<256; ++i) {
1431
68.3k
      val=int(input->readULong(1));
1432
68.3k
      if (val!=i)
1433
68.0k
        f << val << ",";
1434
280
      else
1435
280
        f << "_,";
1436
68.3k
    }
1437
267
    f << "],";
1438
267
    ascii().addPos(pos);
1439
267
    ascii().addNote(f.str().c_str());
1440
267
  }
1441
1442
7.86k
  if (numTree>0) {
1443
3.59k
    zone.m_tree=readCompressionTree(bitmapPos, numTree);
1444
3.59k
    if (!zone.m_tree) return false;
1445
3.59k
  }
1446
6.75k
  if (input->tell()<bitmapPos) {
1447
    // before v10 flag&2000 => a zone of 40, v18 => a zone of 48
1448
6.48k
    long const extraSize=bitmapPos-input->tell();
1449
6.48k
    if ((zone.m_flags[0]&0x2000) && (extraSize==40 || extraSize==48)) {
1450
      // 40 char, like 00070000000004640000000000000000000000000000000000000000000000000000000000000000
1451
      // 48 char, like 00070000000004ec00000000000000000000000000000000000000000000000000000000000000000000000000000000
1452
91
      ascii().addPos(input->tell());
1453
91
      ascii().addNote("ZoneHeader[pict,extra]:");
1454
91
    }
1455
6.39k
    else {
1456
6.39k
      MWAW_DEBUG_MSG(("CorelPainterParser::readZoneHeader: find extra data\n"));
1457
6.39k
      ascii().addPos(input->tell());
1458
6.39k
      ascii().addNote("ZoneHeader:###extra");
1459
6.39k
    }
1460
6.48k
  }
1461
6.75k
  return true;
1462
7.86k
}
1463
1464
bool CorelPainterParser::readPolygon(long endPos, MWAWGraphicShape &shape, MWAWGraphicStyle &style)
1465
3
{
1466
3
  auto input=getInput();
1467
3
  MWAWGraphicStyle insideStyle;
1468
3
  for (int st=0; st<2; ++st) {
1469
3
    long pos=input->tell();
1470
3
    if (pos+0x6c>endPos)
1471
3
      return false;
1472
0
    int dSz=int(input->readULong(2));
1473
0
    if (dSz!=0x6c)
1474
0
      return false;
1475
0
    libmwaw::DebugStream f;
1476
0
    f << "Entries(Polygon):";
1477
0
    MWAWGraphicStyle &styl=st==0 ? style : insideStyle;
1478
0
    int val;
1479
0
    for (int i=0; i<2; ++i) {
1480
0
      val=int(input->readLong(2));
1481
0
      if (val!=2-2*i) f << "f" << i << "=" << val << ",";
1482
0
    }
1483
0
    int flags=int(input->readULong(2));
1484
0
    if (flags&1) f << "has[insidePoly],";
1485
0
    if (flags&0xfffe) f << "fl=" << std::hex << (flags&0xfffe) << std::dec << ",";
1486
0
    for (int i=0; i<2; ++i) { // f2=2, f3=2
1487
0
      val=int(input->readLong(2));
1488
0
      if (val!=2-i) f << "f" << i+2 << "=" << val << ",";
1489
0
    }
1490
0
    for (int i=0; i<2; ++i) { // fl0=1, fl1=0|1
1491
0
      val=int(input->readLong(1));
1492
0
      if (val!=1-i) f << "fl" << i << "=" << val << ",";
1493
0
    }
1494
0
    int dim[4];
1495
0
    for (auto &d : dim) d=int(input->readLong(2));
1496
0
    f << "box=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]),MWAWVec2i(dim[3],dim[2])) << ",";
1497
0
    val=int(input->readLong(2)); // 0
1498
0
    if (val) f << "f4=" << val << ",";
1499
0
    int flags2=int(input->readULong(2));
1500
0
    if (flags2&1) f << "line,";
1501
0
    if (flags2&2) f << "has[surface],";
1502
0
    if (flags2&4) f << "has[stroke],";
1503
0
    if ((flags2&8)==0) {
1504
0
      styl.m_fillRuleEvenOdd=true;
1505
0
      f << "fill[evenOdd],";
1506
0
    }
1507
0
    if (flags2&0xfff0) f << "flags=" << std::hex << (flags2&0xfff0) << std::dec << ",";
1508
0
    std::string name;
1509
0
    int pSz=int(input->readULong(1));
1510
0
    if (pSz>32) {
1511
0
      MWAW_DEBUG_MSG(("CorelPainterParser::readPolygon: can not read a name\n"));
1512
0
      f << "##pSz=" << pSz << ",";
1513
0
      pSz=0;
1514
0
    }
1515
0
    for (int i=0; i<pSz; ++i) {
1516
0
      char c=char(input->readULong(1));
1517
0
      if (!c) break;
1518
0
      name+=c;
1519
0
    }
1520
0
    f << "name=" << name << ","; // shape name or corresponding letter
1521
0
    input->seek(pos+64, librevenge::RVNG_SEEK_SET);
1522
0
    int type=int(input->readLong(2));
1523
0
    switch (type) {
1524
0
    case 100:
1525
0
      f << "spline,";
1526
0
      break;
1527
0
    case 101:
1528
0
      f << "rect,";
1529
0
      break;
1530
0
    case 102:
1531
0
      f << "oval,";
1532
0
      break;
1533
0
    default:
1534
0
      MWAW_DEBUG_MSG(("CorelPainterParser::readPolygon: find unknown type=%d\n",type));
1535
0
      f << "###type=" << type << ",";
1536
0
      break;
1537
0
    }
1538
0
    val=int(input->readULong(2));
1539
0
    switch ((val>>12)) {
1540
0
    case 0: // butt
1541
0
      break;
1542
0
    case 1:
1543
0
      styl.m_lineCap=MWAWGraphicStyle::C_Round;
1544
0
      f << "line[cap]=round,";
1545
0
      break;
1546
0
    case 2:
1547
0
      styl.m_lineCap=MWAWGraphicStyle::C_Square;
1548
0
      f << "line[cap]=square,";
1549
0
      break;
1550
0
    default:
1551
0
      f << "#line[cap]=" << (val>>12) << ",";
1552
0
      break;
1553
0
    }
1554
0
    switch ((val>>8)&0xf) {
1555
0
    case 0: // miter
1556
0
      break;
1557
0
    case 1:
1558
0
      styl.m_lineJoin=MWAWGraphicStyle::J_Round;
1559
0
      f << "line[join]=round,";
1560
0
      break;
1561
0
    case 2:
1562
0
      styl.m_lineJoin=MWAWGraphicStyle::J_Bevel;
1563
0
      f << "line[join]=bevel,";
1564
0
      break;
1565
0
    default:
1566
0
      f << "#line[join]=" << ((val>>8)&0xf) << ",";
1567
0
      break;
1568
0
    }
1569
0
    if (val&0xff)
1570
0
      f << "f5=" << (val&0xff) << ",";
1571
0
    MWAWColor colors[2];
1572
0
    for (int i=0; i<2; ++i) {
1573
0
      colors[i]=MWAWColor(uint32_t(input->readULong(4)));
1574
0
      if ((i==0 && !colors[0].isWhite()) || (i==1 && !colors[1].isBlack()))
1575
0
        f << "col[" << (i==0 ? "surface" : "stroke") << "]=" << colors[i] << ",";
1576
0
    }
1577
0
    val=int(input->readULong(4));
1578
0
    styl.m_lineWidth=float(val)/float(65536);
1579
0
    if (val!=0x30000) f << "stroke[w]=" << styl.m_lineWidth << ",";
1580
0
    val=int(input->readULong(4));
1581
0
    if (val!=0x70000) f << "mitter[limit]=" << float(val)/float(65536) << ",";
1582
0
    val=int(input->readLong(2)); // 1 ou 40
1583
0
    if (val!=40) f << "flatness=" << val << ",";
1584
0
    int N=int(input->readULong(2));
1585
0
    f << "N=" << N << ",";
1586
0
    float fDim[4];
1587
0
    for (auto &d : fDim) d=float(input->readLong(4))/65536.f;
1588
0
    MWAWBox2f box(MWAWVec2f(fDim[0],fDim[1]),MWAWVec2f(fDim[2],fDim[3]));
1589
0
    f << "box[float]=" << box << ",";
1590
0
    float opacity[2];
1591
0
    for (int i=0; i<2; ++i) {
1592
0
      opacity[i]=float(input->readULong(2))/float(65535);
1593
0
      if (opacity[i]<1.f)
1594
0
        f << "opacity[" << (i==0 ? "surface" : "stroke") << "=" << opacity[i] << ",";
1595
0
    }
1596
0
    if (flags2&2)
1597
0
      styl.setSurfaceColor(colors[0],opacity[0]);
1598
0
    if (flags2&4) {
1599
0
      styl.m_lineColor=colors[1];
1600
0
      styl.m_lineOpacity=opacity[1];
1601
0
    }
1602
0
    else
1603
0
      styl.m_lineWidth=0;
1604
0
    if (pos+dSz+40*(N+1)+2<pos+dSz+2 || pos+dSz+40*(N+1)+2>endPos) {
1605
0
      MWAW_DEBUG_MSG(("CorelPainterParser::readPolygon: the number of point seems bad\n"));
1606
0
      f << "###N";
1607
0
      ascii().addPos(pos);
1608
0
      ascii().addNote(f.str().c_str());
1609
0
      input->seek(pos+dSz, librevenge::RVNG_SEEK_SET);
1610
0
      return false;
1611
0
    }
1612
0
    ascii().addPos(pos);
1613
0
    ascii().addNote(f.str().c_str());
1614
0
    input->seek(pos+dSz, librevenge::RVNG_SEEK_SET);
1615
0
    if (st==0) shape=MWAWGraphicShape::path(box);
1616
1617
    // checkme: this must work for simple shape, for most complex
1618
    // shape, we need to understand what ptype codes
1619
0
    std::vector<MWAWVec2f> vertices;
1620
0
    vertices.reserve(3*size_t(N+1));
1621
0
    for (int i=0; i<=N; ++i) {
1622
0
      pos=input->tell();
1623
0
      f.str("");
1624
0
      f << "Polygon:";
1625
0
      int pType=int(input->readULong(2)); // find 0|1|11|a0
1626
0
      if (pType==0) // end of poly
1627
0
        f << "_,";
1628
0
      else if (pType==1 || pType==0x11) // 1 normal, 11: pt0=pt1
1629
0
        f << "point,";
1630
0
      else // a0: line
1631
0
        f << "point" << std::hex << pType << std::dec << ",";
1632
0
      if (pType || i!=N) {
1633
0
        val=int(input->readLong(2)); // 0
1634
0
        if (val) f << "f0=" << val << ",";
1635
0
        f << "pts=[";
1636
0
        for (int pt=0; pt<3; ++pt) {
1637
0
          float fPos[2];
1638
0
          for (auto &d : fPos) d=float(input->readLong(4))/65536.f;
1639
0
          if (pType==0 && pt==0 && (fPos[0]<fDim[0] || fPos[0]>fDim[2] || fPos[1]<fDim[1] || fPos[1]>fDim[3]))
1640
0
            break;
1641
0
          vertices.push_back(MWAWVec2f(fPos[0],fPos[1]));
1642
0
          f << vertices.back() << ",";
1643
0
        }
1644
0
        f << "],";
1645
        // then junk?
1646
0
      }
1647
0
      if ((i==N || pType==0) && !vertices.empty()) {
1648
        // TODO use point type to recreate the path
1649
0
        shape.m_path.push_back(MWAWGraphicShape::PathData('M', vertices[0]));
1650
0
        size_t numPts=vertices.size()/3;
1651
0
        for (size_t pt=1; pt<numPts; ++pt) {
1652
0
          if (vertices[3*pt-3]==vertices[3*pt-2] && vertices[3*pt-1]==vertices[3*pt])
1653
0
            shape.m_path.push_back(MWAWGraphicShape::PathData('L', vertices[3*pt]));
1654
0
          else
1655
0
            shape.m_path.push_back(MWAWGraphicShape::PathData('C', vertices[3*pt], vertices[3*pt-2], vertices[3*pt-1]));
1656
0
        }
1657
0
        if (i<=1 && (numPts==1 || (numPts==2 && vertices[0]==vertices[3]))) // line special case
1658
0
          shape.m_path.push_back(MWAWGraphicShape::PathData('L', vertices[2]));
1659
0
        else if (numPts>2 && vertices[0]==vertices[3*numPts-3])
1660
0
          shape.m_path.push_back(MWAWGraphicShape::PathData('Z'));
1661
0
        vertices.clear();
1662
0
      }
1663
1664
0
      ascii().addDelimiter(input->tell(),'|');
1665
0
      input->seek(pos+40, librevenge::RVNG_SEEK_SET);
1666
0
      ascii().addPos(pos);
1667
0
      ascii().addNote(f.str().c_str());
1668
0
    }
1669
0
    pos=input->tell();
1670
0
    if (pos+2>endPos) {
1671
0
      MWAW_DEBUG_MSG(("CorelPainterParser::readPolygon: can not find the end marker\n"));
1672
0
      return false;
1673
0
    }
1674
0
    f.str("");
1675
0
    f << "Polygon[end]:";
1676
0
    val=int(input->readULong(2));
1677
0
    if (val!=0) f << "f0=" << val << ",";
1678
0
    ascii().addPos(pos);
1679
0
    ascii().addNote(f.str().c_str());
1680
0
    if (st==0 && (flags&1)==0)
1681
0
      break;
1682
0
  }
1683
1684
0
  return true;
1685
3
}
1686
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: