Coverage Report

Created: 2026-09-14 06:37

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
5.16k
  {
63
10.3k
    for (auto &v: m_values) v=0;
64
5.16k
  }
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
12.5k
    : m_isMainZone(false)
76
12.5k
    , m_dimension()
77
12.5k
    , m_origin()
78
12.5k
    , m_pixelByInch(0)
79
12.5k
    , m_numTreeNodes(0)
80
12.5k
    , m_tree()
81
12.5k
    , m_bitmapPos(0)
82
12.5k
    , m_rsrcDataPos(0)
83
12.5k
    , m_nextPos(0)
84
12.5k
    , m_rsrcMap()
85
12.5k
  {
86
25.0k
    for (auto &f : m_flags) f=0;
87
12.5k
  }
88
  //! check if it is a picture header
89
  bool isBitmap() const
90
10.3k
  {
91
10.3k
    if (m_dimension[0]<=2 || m_dimension[1]<=2) return false;
92
9.78k
    long endPos=m_rsrcDataPos>0 ? m_rsrcDataPos : m_nextPos;
93
9.78k
    if (m_bitmapPos>=endPos) return false;
94
9.69k
    if ((m_flags[1]&1) && m_bitmapPos+4*long(m_dimension[0])*long(m_dimension[1])>endPos)
95
415
      return false;
96
9.27k
    return true;
97
9.69k
  }
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
20.7k
    : m_zoneList()
128
20.7k
    , m_pixelByInch(0)
129
20.7k
  {
130
20.7k
  }
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.68k
  : MWAWGraphicParser(input, rsrcParser, header)
193
9.68k
  , m_state()
194
9.68k
{
195
9.68k
  init();
196
9.68k
}
197
198
CorelPainterParser::~CorelPainterParser()
199
9.68k
{
200
9.68k
}
201
202
void CorelPainterParser::init()
203
9.68k
{
204
9.68k
  resetGraphicListener();
205
9.68k
  setAsciiName("main-1");
206
207
9.68k
  m_state.reset(new CorelPainterParserInternal::State);
208
209
9.68k
  getPageSpan().setMargins(0.1);
210
9.68k
}
211
212
////////////////////////////////////////////////////////////
213
// the parser
214
////////////////////////////////////////////////////////////
215
void CorelPainterParser::parse(librevenge::RVNGDrawingInterface *docInterface)
216
1.36k
{
217
1.36k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
218
1.36k
  bool ok = false;
219
1.36k
  try {
220
    // create the asciiFile
221
1.36k
    ascii().setStream(getInput());
222
1.36k
    ascii().open(asciiName());
223
1.36k
    checkHeader(nullptr);
224
1.36k
    ok = createZones();
225
1.36k
    if (ok) {
226
1.36k
      createDocument(docInterface);
227
1.37k
      for (auto const &z : m_state->m_zoneList) {
228
1.37k
        if (z.isBitmap())
229
1.36k
          sendBitmap(z);
230
9
        else
231
9
          sendZone(z);
232
1.37k
      }
233
1.36k
    }
234
1.36k
    ascii().reset();
235
1.36k
  }
236
1.36k
  catch (...) {
237
0
    MWAW_DEBUG_MSG(("CorelPainterParser::parse: exception catched when parsing\n"));
238
0
    ok = false;
239
0
  }
240
241
1.36k
  resetGraphicListener();
242
1.36k
  if (!ok) throw(libmwaw::ParseException());
243
1.36k
}
244
245
////////////////////////////////////////////////////////////
246
// create the document
247
////////////////////////////////////////////////////////////
248
void CorelPainterParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
249
1.36k
{
250
1.36k
  if (!documentInterface) return;
251
1.36k
  if (getGraphicListener()) {
252
0
    MWAW_DEBUG_MSG(("CorelPainterParser::createDocument: listener already exist\n"));
253
0
    return;
254
0
  }
255
1.36k
  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.36k
  auto const &zone=m_state->m_zoneList[0];
260
1.36k
  int const &pixelByInch=m_state->m_pixelByInch;
261
1.36k
  if (pixelByInch>0 && pixelByInch<0xFFFF) { // time to update the page dimension
262
1.02k
    getPageSpan().setFormWidth(0.2+double(zone.m_dimension[0])/double(pixelByInch));
263
1.02k
    getPageSpan().setFormLength(0.2+double(zone.m_dimension[1])/double(pixelByInch));
264
1.02k
  }
265
  // create the page list
266
1.36k
  MWAWPageSpan ps(getPageSpan());
267
1.36k
  ps.setPageSpan(1);
268
1.36k
  std::vector<MWAWPageSpan> pageList(1,ps);
269
1.36k
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
270
1.36k
  setGraphicListener(listen);
271
1.36k
  listen->startDocument();
272
1.36k
}
273
274
275
////////////////////////////////////////////////////////////
276
//
277
// Intermediate level
278
//
279
////////////////////////////////////////////////////////////
280
bool CorelPainterParser::createZones()
281
1.36k
{
282
1.36k
  MWAWInputStreamPtr input = getInput();
283
1.36k
  input->seek(0, librevenge::RVNG_SEEK_SET);
284
2.73k
  while (!input->isEnd()) {
285
1.45k
    long pos=input->tell();
286
1.45k
    CorelPainterParserInternal::ZoneHeader zone;
287
1.45k
    if (!readZoneHeader(zone) || input->tell()>zone.m_nextPos) {
288
85
      MWAW_DEBUG_MSG(("CorelPainterParser::createZones: find extra data\n"));
289
85
      ascii().addPos(pos);
290
85
      ascii().addNote("Entries(UnknownD):###extra");
291
85
      break;
292
85
    }
293
1.37k
    if (zone.m_rsrcDataPos>0)
294
701
      readResourcesList(zone);
295
1.37k
    m_state->m_zoneList.push_back(zone);
296
1.37k
    input->seek(zone.m_nextPos, librevenge::RVNG_SEEK_SET);
297
1.37k
  }
298
1.36k
  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.36k
  return true;
304
1.36k
}
305
306
std::shared_ptr<MWAWPict> CorelPainterParser::readBitmap(CorelPainterParserInternal::ZoneHeader const &zone)
307
1.36k
{
308
1.36k
  MWAWInputStreamPtr input = getInput();
309
1.36k
  auto const &dim=zone.m_dimension;
310
1.36k
  long endPos= zone.m_rsrcDataPos>0 ? zone.m_rsrcDataPos : zone.m_nextPos;
311
1.36k
  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.36k
  auto bitmap=std::make_shared<MWAWPictBitmapColor>(MWAWVec2i(dim[0],dim[1]), !zone.m_isMainZone);
315
1.36k
  std::vector<MWAWColor> listColor;
316
1.36k
  if (!zone.m_numTreeNodes) { // uncompressed
317
702
    libmwaw::DebugStream f;
318
702
    listColor.resize(size_t(dim[0]));
319
28.6k
    for (int i=0; i<dim[1]; ++i) {
320
28.5k
      long pos=input->tell();
321
28.5k
      f.str("");
322
28.5k
      f << "BitmapRow[unc]:";
323
28.5k
      if (pos+4*dim[0]>endPos) {
324
621
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmap: can not read some row\n"));
325
621
        f << "###";
326
621
        ascii().addPos(pos);
327
621
        ascii().addNote(f.str().c_str());
328
621
        return nullptr;
329
621
      }
330
308k
      for (size_t c=0; c<size_t(dim[0]); ++c) {
331
280k
        unsigned char data[4];
332
1.12M
        for (auto &d : data) d=static_cast<unsigned char>(input->readULong(1));
333
280k
        listColor[c]=MWAWColor(data[1],data[2],data[3],data[0]);
334
280k
      }
335
27.9k
      bitmap->setRow(i, listColor.data());
336
27.9k
      ascii().addPos(pos);
337
27.9k
      ascii().addNote(f.str().c_str());
338
27.9k
    }
339
702
  }
340
659
  else { // compressed
341
659
    std::vector<unsigned char> previousValues;
342
659
    previousValues.resize(size_t(4*dim[0]),0);
343
925
    for (int i=0; i<dim[1]; ++i) {
344
925
      long pos=input->tell();
345
925
      if (!readBitmapRow(zone, listColor, previousValues) || input->tell()>endPos) {
346
659
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmap: can not read some row\n"));
347
659
        ascii().addPos(pos);
348
659
        ascii().addNote("Entries(UnknownB):###extra");
349
659
        return nullptr;
350
659
      }
351
266
      bitmap->setRow(i, listColor.data());
352
266
    }
353
659
  }
354
81
  return bitmap;
355
1.36k
}
356
357
bool CorelPainterParser::readBitmapRow(CorelPainterParserInternal::ZoneHeader const &zone,
358
                                       std::vector<MWAWColor> &colorList, std::vector<unsigned char> &previousValues)
359
925
{
360
925
  MWAWInputStreamPtr input = getInput();
361
925
  long pos=input->tell();
362
925
  int const &dim=zone.m_dimension[0];
363
925
  if (!input->checkPosition(pos+4) || dim<=0) return false;
364
904
  libmwaw::DebugStream f;
365
904
  f << "Entries(BitmapRow):";
366
904
  int type=int(input->readLong(1)); // 0,2
367
904
  if (type==0)
368
478
    f << "huffman,";
369
426
  else if (type!=2) f << "##type=" << type << ",";
370
904
  unsigned char firstData=static_cast<unsigned char>(input->readULong(1));
371
904
  if (firstData) f << "d0=" << std::hex << int(firstData) << std::dec << ",";
372
904
  int sz=int(input->readULong(2));
373
904
  long endPos=pos+sz;
374
904
  if (sz<4 || !input->checkPosition(endPos)) {
375
312
    input->seek(pos, librevenge::RVNG_SEEK_SET);
376
312
    return false;
377
312
  }
378
592
  bool ok=true;
379
592
  std::vector<unsigned char> listColorData;
380
592
  int expectedNumData=4*dim;
381
592
  listColorData.reserve(size_t(expectedNumData));
382
592
  listColorData.push_back(firstData);
383
592
  switch (type) {
384
380
  case 0: { // use Huffman tree
385
380
    f << "*[";
386
380
    int buffer, numBitsInBuffer=0;
387
70.0k
    for (int i=0; i<expectedNumData-1; ++i) {
388
69.8k
      int value;
389
69.8k
      if (!decompressData(zone, endPos, value, buffer, numBitsInBuffer)) {
390
86
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: oops, problem when decompressing the data\n"));
391
86
        ok=false;
392
86
        f << "###";
393
86
        break;
394
86
      }
395
69.7k
      if (i<10)
396
3.64k
        f << std::hex << value << std::dec << ",";
397
69.7k
      listColorData.push_back(static_cast<unsigned char>(value));
398
69.7k
    }
399
380
    f << "...],";
400
380
    break;
401
0
  }
402
  // case 1: never seems in v1.2, maybe exists in v1.0 or v1.1 ?
403
165
  case 2: { // basic compression: 0:(n+1) following values, 1:(n+1)*val1
404
836
    while (input->tell()<endPos && listColorData.size() < size_t(expectedNumData)) {
405
789
      long actPos=input->tell();
406
789
      int subType=int(input->readULong(1));
407
789
      if (subType==0) {
408
584
        int dSz=int(input->readULong(1));
409
584
        long lastPos=actPos+3+dSz;
410
584
        if (lastPos>endPos) {
411
31
          input->seek(actPos, librevenge::RVNG_SEEK_SET);
412
31
          break;
413
31
        }
414
553
        f << "0[";
415
3.00k
        for (int i=0; i<dSz+1; ++i) {
416
2.45k
          listColorData.push_back(static_cast<unsigned char>(input->readULong(1)));
417
2.45k
          if (i<3)
418
777
            f << std::hex << int(listColorData.back()) << std::dec << ",";
419
1.67k
          else if (i==3)
420
75
            f << "...";
421
2.45k
        }
422
553
        f << "],";
423
553
      }
424
205
      else if (subType==1) {
425
124
        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
118
        int nData=int(input->readULong(1));
431
118
        unsigned char value=static_cast<unsigned char>(input->readULong(1));
432
118
        f << "1[" << std::hex << int(value) << std::dec << "x" << (nData+1) << "],";
433
3.96k
        for (int i=0; i<nData+1; ++i) listColorData.push_back(value);
434
118
      }
435
81
      else {
436
81
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
437
81
        MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: unknown sub type %d\n", subType));
438
81
        ok=false;
439
81
        f << "###subType=" << subType;
440
81
        break;
441
81
      }
442
789
    }
443
165
    break;
444
0
  }
445
47
  default:
446
47
    MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: unknown type %d\n", type));
447
47
    ok=false;
448
47
    break;
449
592
  }
450
592
  if (ok && listColorData.size() != size_t(expectedNumData)) {
451
81
    MWAW_DEBUG_MSG(("CorelPainterParser::readBitmapRow: bad number of data\n"));
452
81
    f << "###numData,";
453
81
    ok=false;
454
81
  }
455
592
  if (input->tell()!=endPos && input->tell()+1!=endPos)
456
462
    ascii().addDelimiter(input->tell(),'|');
457
592
  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
592
  ascii().addPos(pos);
463
592
  ascii().addNote(f.str().c_str());
464
592
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
465
592
  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
297
  unsigned char actCol=0;
471
55.7k
  for (size_t i=0; i<listColorData.size(); ++i) {
472
55.4k
    actCol = static_cast<unsigned char>(actCol+listColorData[i]);
473
55.4k
    previousValues[i] = static_cast<unsigned char>(previousValues[i]+actCol);
474
55.4k
  }
475
476
297
  colorList.resize(size_t(dim));
477
14.1k
  for (size_t i=0; i<size_t(dim); ++i)
478
13.8k
    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
297
  return true;
480
592
}
481
482
bool CorelPainterParser::decompressData(CorelPainterParserInternal::ZoneHeader const &zone,
483
                                        long endPos, int &value, int &buffer, int &numBitsInBuffer)
484
69.8k
{
485
69.8k
  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
69.8k
  MWAWInputStreamPtr input = getInput();
490
69.8k
  long pos=input->tell();
491
69.8k
  auto node=zone.m_tree;
492
71.8k
  while (!input->isEnd()) {
493
71.8k
    if (numBitsInBuffer<=0) {
494
9.15k
      if (input->tell()>=endPos) break;
495
9.07k
      buffer=int(input->readULong(1));
496
9.07k
      numBitsInBuffer=8;
497
9.07k
    }
498
71.7k
    int c=(buffer>>(--numBitsInBuffer))&1;
499
71.7k
    if (node->m_childs[c]) {
500
2.02k
      node=node->m_childs[c];
501
2.02k
      continue;
502
2.02k
    }
503
69.7k
    value=node->m_values[c];
504
69.7k
    return true;
505
71.7k
  }
506
86
  input->seek(pos, librevenge::RVNG_SEEK_SET);
507
86
  return false;
508
69.8k
}
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
81
{
545
81
  MWAWPageSpan const &page=getPageSpan();
546
81
  int pixelByInch=zone.m_pixelByInch;
547
81
  if (pixelByInch<=0 || pixelByInch>=0xffff) pixelByInch=m_state->m_pixelByInch;
548
81
  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
81
  MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight()))
553
81
                   +1.f/float(pixelByInch)*MWAWVec2f(zone.m_origin),
554
81
                   1.f/float(pixelByInch)*MWAWVec2f(zone.m_dimension), librevenge::RVNG_INCH);
555
81
  pos.setRelativePosition(MWAWPosition::Page);
556
81
  pos.m_wrapping = MWAWPosition::WNone;
557
81
  return pos;
558
81
}
559
560
bool CorelPainterParser::sendBitmap(CorelPainterParserInternal::ZoneHeader const &zone)
561
1.36k
{
562
1.36k
  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.36k
  MWAWGraphicListenerPtr listener=getGraphicListener();
567
1.36k
  if (!listener) {
568
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendBitmap: can not find the listener\n"));
569
0
    return false;
570
0
  }
571
572
1.36k
  auto input=getInput();
573
1.36k
  input->seek(zone.m_bitmapPos, librevenge::RVNG_SEEK_SET);
574
1.36k
  auto bitmap=readBitmap(zone);
575
1.36k
  if (!bitmap) return false;
576
577
  // let finish to read the zone
578
81
  if (zone.m_rsrcDataPos>0 &&input->tell()<zone.m_rsrcDataPos) {
579
15
    ascii().addPos(input->tell());
580
15
    ascii().addNote("Entries(UnknownB):");
581
15
    input->seek(zone.m_rsrcDataPos, librevenge::RVNG_SEEK_SET);
582
15
  }
583
  // send the bitmap
584
81
  MWAWEmbeddedObject picture;
585
81
  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
81
  listener->insertPicture(getZonePosition(zone), picture);
597
81
  return true;
598
81
}
599
600
bool CorelPainterParser::sendZone(CorelPainterParserInternal::ZoneHeader const &zone)
601
9
{
602
9
  MWAWGraphicListenerPtr listener=getGraphicListener();
603
9
  if (!listener) {
604
0
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: can not find the listener\n"));
605
0
    return false;
606
0
  }
607
608
9
  auto it=zone.m_rsrcMap.find("TEXT");
609
9
  auto unicodeIt=zone.m_rsrcMap.find("utxt");
610
9
  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
9
  MWAWInputStreamPtr input = getInput();
621
9
  if (zone.isBitmap() || zone.m_rsrcDataPos!=0 || zone.m_bitmapPos+2 >= zone.m_nextPos) {
622
5
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: oops, unexpected zone\n"));
623
5
    return false;
624
5
  }
625
626
4
  input->seek(zone.m_bitmapPos,librevenge::RVNG_SEEK_SET);
627
4
  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
4
  MWAWGraphicShape shape;
630
4
  MWAWGraphicStyle style;
631
4
  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
4
  else {
642
4
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: sending not spline zone is not implemented\n"));
643
4
    input->seek(pos, librevenge::RVNG_SEEK_SET);
644
4
  }
645
4
  if (input->tell()!=zone.m_nextPos) {
646
4
    MWAW_DEBUG_MSG(("CorelPainterParser::sendZone: find extra data\n"));
647
4
    ascii().addPos(input->tell());
648
4
    ascii().addNote("Entries(Shape):###extra");
649
4
  }
650
651
4
  return false;
652
9
}
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
11.0k
{
933
11.0k
  *m_state = CorelPainterParserInternal::State();
934
11.0k
  MWAWInputStreamPtr input = getInput();
935
11.0k
  if (!input || !input->hasDataFork())
936
0
    return false;
937
938
11.0k
  input->seek(0,librevenge::RVNG_SEEK_SET);
939
11.0k
  MWAWDocument::Type type=MWAWDocument::MWAW_T_CORELPAINTER;
940
11.0k
  int const vers=1;
941
942
11.0k
  CorelPainterParserInternal::ZoneHeader zone;
943
11.0k
  if (!readZoneHeader(zone) || !zone.isBitmap())
944
5.85k
    return false;
945
5.19k
  if (strict) {
946
1.70k
    auto const &flags=zone.m_flags[1];
947
1.70k
    auto const &numTree = zone.m_numTreeNodes;
948
1.70k
    bool uncompressed=flags&1;
949
1.70k
    if ((uncompressed && numTree!=0) || (!uncompressed && numTree==0)) return false;
950
1.70k
  }
951
4.36k
  m_state->m_pixelByInch=zone.m_pixelByInch;
952
4.36k
  setVersion(vers);
953
4.36k
  if (header)
954
1.64k
    header->reset(type, vers, MWAWDocument::MWAW_K_PAINT);
955
4.36k
  return true;
956
5.19k
}
957
958
std::shared_ptr<CorelPainterParserInternal::Node> CorelPainterParser::readCompressionTree(long endPos, int numNodes)
959
4.16k
{
960
4.16k
  MWAWInputStreamPtr input = getInput();
961
4.16k
  long pos=input->tell();
962
4.16k
  if (numNodes==0) return nullptr;
963
4.16k
  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
4.16k
  libmwaw::DebugStream f;
968
4.16k
  f << "Entries(Compression):";
969
4.16k
  std::vector<std::shared_ptr<CorelPainterParserInternal::Node> > nodesList;
970
4.16k
  nodesList.resize(size_t(numNodes));
971
4.16k
  nodesList[0]=std::make_shared<CorelPainterParserInternal::Node>();
972
8.29k
  for (size_t i=0; i<size_t(numNodes); ++i) {
973
5.30k
    auto &node=nodesList[i];
974
5.30k
    if (!node) {
975
530
      MWAW_DEBUG_MSG(("CorelPainterParser::readCompressionTree: can not find node %d\n", int(i)));
976
530
      return nullptr;
977
530
    }
978
13.2k
    for (int c=0; c<2; ++c) {
979
9.15k
      int val=int(input->readULong(2));
980
9.15k
      if (val&0x8000) {
981
7.50k
        node->m_values[c]=(val&0xff);
982
7.50k
        f << std::hex << node->m_values[c] << std::dec;
983
7.50k
      }
984
1.64k
      else {
985
1.64k
        int id=(val/4);
986
1.64k
        if (id>=numNodes || nodesList[size_t(id)]) {
987
643
          MWAW_DEBUG_MSG(("CorelPainterParser::readCompressionTree: problem with id=%d\n", int(id)));
988
643
          return nullptr;
989
643
        }
990
1.00k
        nodesList[size_t(id)]=node->m_childs[c]=std::make_shared<CorelPainterParserInternal::Node>();
991
1.00k
        f << "N" << id;
992
1.00k
      }
993
8.51k
      if (c==0) f << "-";
994
8.51k
    }
995
4.12k
    f << ",";
996
4.12k
    nodesList.push_back(node);
997
4.12k
  }
998
2.99k
  ascii().addPos(pos);
999
2.99k
  ascii().addNote(f.str().c_str());
1000
2.99k
  return nodesList[0];
1001
4.16k
}
1002
1003
bool CorelPainterParser::readResourcesList(CorelPainterParserInternal::ZoneHeader &zone)
1004
701
{
1005
701
  MWAWInputStreamPtr input = getInput();
1006
701
  if (zone.m_rsrcDataPos<=0 || !input->checkPosition(zone.m_rsrcDataPos) ||
1007
701
      zone.m_rsrcDataPos>=zone.m_nextPos)
1008
9
    return false;
1009
1010
692
  libmwaw::DebugStream f;
1011
692
  input->seek(zone.m_rsrcDataPos, librevenge::RVNG_SEEK_SET);
1012
692
  long const &endPos = zone.m_nextPos;
1013
762
  while (input->tell()+4<=endPos && !input->isEnd()) {
1014
754
    long pos=input->tell();
1015
754
    int sz=int(input->readULong(4));
1016
754
    if (sz==0) {
1017
62
      ascii().addPos(pos);
1018
62
      ascii().addNote("_");
1019
62
      return true;
1020
62
    }
1021
692
    long endRsrcPos=pos+sz;
1022
692
    if (sz<16 || endRsrcPos>endPos) {
1023
526
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1024
526
      break;
1025
526
    }
1026
166
    f.str("");
1027
166
    f << "Entries(Rsrc):";
1028
166
    std::string type;
1029
830
    for (int i=0; i<4; ++i) type+=char(input->readULong(1));
1030
166
    f << type << ",";
1031
166
    long dSizes[2];
1032
332
    for (auto &d : dSizes) d=long(input->readULong(4));
1033
166
    if (dSizes[0]<18 || dSizes[1]<0 || dSizes[0]+dSizes[1]>sz) {
1034
96
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: the sizes seems bad\n"));
1035
96
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1036
96
      break;
1037
96
    }
1038
70
    MWAWEntry entry;
1039
70
    entry.setType(type);
1040
70
    entry.setBegin(pos+dSizes[0]);
1041
70
    entry.setEnd(endRsrcPos);
1042
70
    if (dSizes[0]>18) f << "header[sz]=" << dSizes[0] << ",";
1043
70
    if (dSizes[1]>0) {
1044
28
      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
28
      else
1049
28
        zone.m_rsrcMap[type]=entry;
1050
28
      f << "data[sz]=" << dSizes[1] << ",";
1051
28
    }
1052
1053
70
    int nameSz=int(input->readULong(2));
1054
70
    if (18+nameSz>dSizes[0]) {
1055
16
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: the name size seems bad\n"));
1056
16
      f << "###name[sz]=" << nameSz << ",";
1057
16
    }
1058
54
    else if (nameSz) {
1059
      // PCOL => "Paper Color", FSKT => "Friskets", ANNO => "Annotations", NOTE => "Note Text"
1060
33
      int pSz=int(input->readULong(1));
1061
33
      if (pSz+1<=nameSz) {
1062
25
        std::string text;
1063
464
        for (int c=0; c<pSz; ++c) text+=char(input->readULong(1));
1064
25
        f << text << ",";
1065
25
      }
1066
33
    }
1067
1068
70
    if (input->tell()!=pos+dSizes[0] && input->tell()+1!=pos+dSizes[0]) {
1069
67
      f << "##extra,";
1070
67
      MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: find extra header data\n"));
1071
67
      ascii().addDelimiter(input->tell(),'|');
1072
67
    }
1073
70
    input->seek(pos+dSizes[0], librevenge::RVNG_SEEK_SET);
1074
70
    if (entry.valid())
1075
67
      readResource(entry);
1076
70
    ascii().addPos(pos);
1077
70
    ascii().addNote(f.str().c_str());
1078
70
    input->seek(endRsrcPos, librevenge::RVNG_SEEK_SET);
1079
70
  }
1080
630
  if (input->tell()<endPos) {
1081
629
    MWAW_DEBUG_MSG(("CorelPainterParser::readResourcesList: find extra data\n"));
1082
629
    ascii().addPos(input->tell());
1083
629
    ascii().addNote("Rsrc:##extra");
1084
629
  }
1085
1086
630
  return true;
1087
692
}
1088
1089
bool CorelPainterParser::readResource(MWAWEntry const &entry)
1090
67
{
1091
67
  MWAWInputStreamPtr input = getInput();
1092
67
  if (!entry.valid() || !input->checkPosition(entry.end())) {
1093
0
    MWAW_DEBUG_MSG(("CorelPainterParser::readResource: bad entry\n"));
1094
0
    return false;
1095
0
  }
1096
67
  if (entry.isParsed() || entry.type()=="TEXT" || entry.type()=="utxt") return true;
1097
67
  entry.setParsed(true);
1098
67
  libmwaw::DebugStream f;
1099
67
  f << "Rsrc[" << entry.type() << "]:";
1100
67
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1101
  // find also ANNO,GUID with sz=0
1102
67
  int val;
1103
67
  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
67
  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
67
  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
67
  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
67
  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
67
  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
67
  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
67
  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
67
  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
67
  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
67
  if (input->tell()!=entry.end()) {
1324
67
    f << "#extra,";
1325
67
    if (input->tell()!=entry.begin())
1326
0
      ascii().addDelimiter(input->tell(),'|');
1327
67
  }
1328
67
  ascii().addPos(entry.begin());
1329
67
  ascii().addNote(f.str().c_str());
1330
67
  return true;
1331
67
}
1332
1333
bool CorelPainterParser::readZoneHeader(CorelPainterParserInternal::ZoneHeader &zone)
1334
12.5k
{
1335
12.5k
  MWAWInputStreamPtr input = getInput();
1336
12.5k
  libmwaw::DebugStream f;
1337
12.5k
  long pos=input->tell();
1338
12.5k
  if (!input->checkPosition(pos+64) || input->readULong(2)!=2) return false;
1339
12.4k
  f << "Entries(ZoneHeader):";
1340
1341
12.4k
  int headerSize=64;
1342
12.4k
  zone.m_isMainZone=pos==0;
1343
12.4k
  zone.m_flags[0]=int(input->readULong(2)); // 2000: in painter v6 file
1344
12.4k
  if (zone.m_flags[0]&0x2000) f << "extra[pict],";
1345
12.4k
  if (zone.m_flags[0]&0xdfff) f << "fl0=" << std::hex << (zone.m_flags[0]&0xdfff) << std::dec << ",";
1346
12.4k
  int dim[2];
1347
24.8k
  for (auto &d : dim) d=int(input->readLong(2));
1348
12.4k
  zone.m_dimension=MWAWVec2i(dim[1],dim[0]);
1349
12.4k
  if (dim[0] || dim[1]) f << "dim=" << zone.m_dimension << ",";
1350
12.4k
  zone.m_flags[1]=int(input->readULong(2)); // main 2, subzone 510(bitmap?)|4110
1351
12.4k
  if (zone.m_flags[1]&1) f << "uncompressed,";
1352
12.4k
  if (zone.m_flags[1]&2) {
1353
1.31k
    f << "has[order],";
1354
1.31k
    headerSize+=256;
1355
1.31k
    if (!input->checkPosition(pos+headerSize)) return false;
1356
1.31k
  }
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
12.2k
  if (zone.m_flags[1]&0xfffc)
1360
5.37k
    f << "fl1=" << std::hex << (zone.m_flags[1]&0xfffc) << std::dec << ",";
1361
12.2k
  int val;
1362
36.7k
  for (int i=0; i<2; ++i) { // checkme: f2=num of ordering?
1363
24.5k
    val=int(input->readULong(2));
1364
24.5k
    int const expected[] = {7,0x100};
1365
24.5k
    if (val!=expected[i]) f << "f" << i+1 << "=" << val << ",";
1366
24.5k
  }
1367
12.2k
  auto &bitmapPos=zone.m_bitmapPos;
1368
12.2k
  bitmapPos=long(input->readULong(4));
1369
12.2k
  if (bitmapPos<headerSize || !input->checkPosition(pos+bitmapPos)) return false;
1370
9.06k
  bitmapPos+=pos;
1371
45.3k
  for (int i=0; i<4; ++i) {
1372
36.2k
    val=int(input->readLong(2));
1373
36.2k
    if (val) f << "f" << i+3 << "=" << val << ",";
1374
36.2k
  }
1375
9.06k
  val=int(input->readULong(4));
1376
9.06k
  if (val && pos+val!=bitmapPos) f << "bitmap[pos2]=" << val << ","; // use me
1377
9.06k
  zone.m_pixelByInch=int(input->readULong(2));
1378
9.06k
  if (zone.m_pixelByInch == 0xFFFF)
1379
684
    f << "pixel[inch]=inherited,";
1380
8.38k
  else if (zone.m_pixelByInch)
1381
6.05k
    f << "pixel[inch]=" << zone.m_pixelByInch << ",";
1382
9.06k
  val=int(input->readULong(2));
1383
9.06k
  if (val) f << "f7=" << std::hex << val << std::dec << ",";
1384
9.06k
  auto &numTree=zone.m_numTreeNodes;
1385
9.06k
  numTree=int(input->readULong(2));
1386
9.06k
  if (numTree>=256 || pos+headerSize+4*numTree > bitmapPos) return false;
1387
17.6k
  for (auto &d : dim) d=int(input->readLong(2));
1388
8.82k
  zone.m_origin=MWAWVec2i(dim[1],dim[0]);
1389
8.82k
  if (dim[0] || dim[1])
1390
6.43k
    f << "orig=" << zone.m_origin << ",";
1391
8.82k
  long lVal=int(input->readULong(4));
1392
8.82k
  if (lVal==0x3fe66666)
1393
0
    f << "main,";
1394
8.82k
  else if (lVal)
1395
7.11k
    f << "zone[type]=" << std::hex << lVal << std::dec << ",";
1396
44.1k
  for (int i=0; i<4; ++i) { // 0
1397
35.2k
    val=int(input->readLong(2));
1398
35.2k
    if (val) f << "g" << i << "=" << val << ",";
1399
35.2k
  }
1400
8.82k
  long prevPos=bitmapPos;
1401
26.4k
  for (int z=0; z<2; ++z) {
1402
17.6k
    long newPos=long(input->readULong(4));
1403
17.6k
    if (newPos<=0) continue;
1404
15.7k
    newPos+=pos;
1405
15.7k
    if (input->checkPosition(newPos) && newPos>=prevPos) {
1406
4.01k
      if (z==0)
1407
3.43k
        zone.m_rsrcDataPos=newPos;
1408
586
      else
1409
586
        zone.m_nextPos=newPos;
1410
4.01k
      prevPos=newPos;
1411
4.01k
    }
1412
11.7k
    else {
1413
11.7k
      MWAW_DEBUG_MSG(("CorelPainterParser::readZoneHeader: zone pos%d seems bad\n", z));
1414
11.7k
      f << "###";
1415
11.7k
    }
1416
15.7k
    f << (z==0 ? "rsrc" : "next") << "[pos]=" << std::hex << newPos << std::dec << ",";
1417
15.7k
  }
1418
8.82k
  if (zone.m_nextPos==0) zone.m_nextPos=input->size();
1419
26.4k
  for (int i=0; i<2; ++i) { // 0
1420
17.6k
    val=int(input->readLong(2));
1421
17.6k
    if (val) f << "g" << i+2 << "=" << val << ",";
1422
17.6k
  }
1423
8.82k
  ascii().addPos(pos);
1424
8.82k
  ascii().addNote(f.str().c_str());
1425
1426
8.82k
  if (zone.m_flags[1]&2) { // read the ordering
1427
302
    pos=input->tell();
1428
302
    f.str("");
1429
302
    f << "Entries(Ordering):[";
1430
77.6k
    for (int i=0; i<256; ++i) {
1431
77.3k
      val=int(input->readULong(1));
1432
77.3k
      if (val!=i)
1433
77.0k
        f << val << ",";
1434
284
      else
1435
284
        f << "_,";
1436
77.3k
    }
1437
302
    f << "],";
1438
302
    ascii().addPos(pos);
1439
302
    ascii().addNote(f.str().c_str());
1440
302
  }
1441
1442
8.82k
  if (numTree>0) {
1443
4.16k
    zone.m_tree=readCompressionTree(bitmapPos, numTree);
1444
4.16k
    if (!zone.m_tree) return false;
1445
4.16k
  }
1446
7.64k
  if (input->tell()<bitmapPos) {
1447
    // before v10 flag&2000 => a zone of 40, v18 => a zone of 48
1448
7.35k
    long const extraSize=bitmapPos-input->tell();
1449
7.35k
    if ((zone.m_flags[0]&0x2000) && (extraSize==40 || extraSize==48)) {
1450
      // 40 char, like 00070000000004640000000000000000000000000000000000000000000000000000000000000000
1451
      // 48 char, like 00070000000004ec00000000000000000000000000000000000000000000000000000000000000000000000000000000
1452
87
      ascii().addPos(input->tell());
1453
87
      ascii().addNote("ZoneHeader[pict,extra]:");
1454
87
    }
1455
7.26k
    else {
1456
7.26k
      MWAW_DEBUG_MSG(("CorelPainterParser::readZoneHeader: find extra data\n"));
1457
7.26k
      ascii().addPos(input->tell());
1458
7.26k
      ascii().addNote("ZoneHeader:###extra");
1459
7.26k
    }
1460
7.35k
  }
1461
7.64k
  return true;
1462
8.82k
}
1463
1464
bool CorelPainterParser::readPolygon(long endPos, MWAWGraphicShape &shape, MWAWGraphicStyle &style)
1465
4
{
1466
4
  auto input=getInput();
1467
4
  MWAWGraphicStyle insideStyle;
1468
4
  for (int st=0; st<2; ++st) {
1469
4
    long pos=input->tell();
1470
4
    if (pos+0x6c>endPos)
1471
3
      return false;
1472
1
    int dSz=int(input->readULong(2));
1473
1
    if (dSz!=0x6c)
1474
1
      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
4
}
1686
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: