Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/PixelPaintParser.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 "MWAWGraphicListener.hxx"
43
#include "MWAWHeader.hxx"
44
#include "MWAWPictBitmap.hxx"
45
#include "MWAWPictData.hxx"
46
#include "MWAWPosition.hxx"
47
48
#include "PixelPaintParser.hxx"
49
50
/** Internal: the structures of a PixelPaintParser */
51
namespace PixelPaintParserInternal
52
{
53
////////////////////////////////////////
54
//! Internal: the state of a PixelPaintParser
55
struct State {
56
  //! constructor
57
  State()
58
29.8k
    : m_bitmapSize(0,0)
59
29.8k
    , m_colorList()
60
29.8k
    , m_bitmap()
61
29.8k
  {
62
29.8k
  }
63
  //! the bitmap size(v1)
64
  MWAWVec2i m_bitmapSize;
65
  //! the color map
66
  std::vector<MWAWColor> m_colorList;
67
  /// the bitmap
68
  std::shared_ptr<MWAWPict> m_bitmap;
69
};
70
71
}
72
73
////////////////////////////////////////////////////////////
74
// constructor/destructor, ...
75
////////////////////////////////////////////////////////////
76
PixelPaintParser::PixelPaintParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
77
14.3k
  : MWAWGraphicParser(input, rsrcParser, header)
78
14.3k
  , m_state()
79
14.3k
{
80
14.3k
  init();
81
14.3k
}
82
83
PixelPaintParser::~PixelPaintParser()
84
14.3k
{
85
14.3k
}
86
87
void PixelPaintParser::init()
88
14.3k
{
89
14.3k
  resetGraphicListener();
90
14.3k
  setAsciiName("main-1");
91
92
14.3k
  m_state.reset(new PixelPaintParserInternal::State);
93
94
14.3k
  getPageSpan().setMargins(0.1);
95
14.3k
}
96
97
////////////////////////////////////////////////////////////
98
// the parser
99
////////////////////////////////////////////////////////////
100
void PixelPaintParser::parse(librevenge::RVNGDrawingInterface *docInterface)
101
1.19k
{
102
1.19k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
103
1.19k
  bool ok = false;
104
1.19k
  try {
105
    // create the asciiFile
106
1.19k
    ascii().setStream(getInput());
107
1.19k
    ascii().open(asciiName());
108
1.19k
    checkHeader(nullptr);
109
1.19k
    ok = createZones();
110
1.19k
    if (ok) {
111
179
      createDocument(docInterface);
112
179
      sendBitmap();
113
179
    }
114
1.19k
    ascii().reset();
115
1.19k
  }
116
1.19k
  catch (...) {
117
0
    MWAW_DEBUG_MSG(("PixelPaintParser::parse: exception catched when parsing\n"));
118
0
    ok = false;
119
0
  }
120
121
1.19k
  resetGraphicListener();
122
1.19k
  if (!ok) throw(libmwaw::ParseException());
123
1.19k
}
124
125
////////////////////////////////////////////////////////////
126
// create the document
127
////////////////////////////////////////////////////////////
128
void PixelPaintParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
129
179
{
130
179
  if (!documentInterface) return;
131
179
  if (getGraphicListener()) {
132
0
    MWAW_DEBUG_MSG(("PixelPaintParser::createDocument: listener already exist\n"));
133
0
    return;
134
0
  }
135
136
  // create the page list
137
179
  MWAWPageSpan ps(getPageSpan());
138
179
  ps.setPageSpan(1);
139
179
  std::vector<MWAWPageSpan> pageList(1,ps);
140
179
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
141
179
  setGraphicListener(listen);
142
179
  listen->startDocument();
143
179
}
144
145
146
////////////////////////////////////////////////////////////
147
//
148
// Intermediate level
149
//
150
////////////////////////////////////////////////////////////
151
bool PixelPaintParser::createZones()
152
1.19k
{
153
1.19k
  MWAWInputStreamPtr input = getInput();
154
1.19k
  int const vers=version();
155
1.19k
  if (input->size()<512) return false;
156
1.19k
  libmwaw::DebugStream f;
157
1.19k
  f << "FileHeader:";
158
1.19k
  input->seek(0, librevenge::RVNG_SEEK_SET); // seek file def
159
1.19k
  ascii().addPos(0);
160
1.19k
  ascii().addNote(f.str().c_str());
161
162
1.19k
  long pos;
163
1.19k
  if ((vers<=1&&!readFileHeaderV1()) || (vers>=2&&!readFileHeaderV2()))
164
0
    return false;
165
166
1.19k
  pos=input->tell();
167
1.19k
  if (!readColorMap()) {
168
0
    ascii().addPos(pos);
169
0
    ascii().addNote("Entries(ColorMap):###");
170
0
    return false;
171
0
  }
172
173
1.19k
  pos=input->tell();
174
1.19k
  if (!readPatternMap()) {
175
0
    ascii().addPos(pos);
176
0
    ascii().addNote("Entries(PatternMap):###");
177
0
    return false;
178
0
  }
179
1.19k
  if ((vers==1 && !readBitmapV1()) || (vers==2 && !readBitmapV2()))
180
1.01k
    return false;
181
179
  if (!input->isEnd()) {
182
169
    if (!input->checkPosition(input->tell()+8)) {
183
23
      ascii().addPos(input->tell());
184
23
      ascii().addNote("Entries(Unused):");
185
23
    }
186
146
    else {
187
146
      MWAW_DEBUG_MSG(("PixelPaintParser::createZones: find some extra data\n"));
188
146
      ascii().addPos(input->tell());
189
146
      ascii().addNote("Entries(Unused):###");
190
146
    }
191
169
  }
192
179
  return m_state->m_bitmap.get()!=nullptr;
193
1.19k
}
194
195
bool PixelPaintParser::readFileHeaderV1(bool onlyCheck)
196
4.68k
{
197
4.68k
  MWAWInputStreamPtr input = getInput();
198
4.68k
  if (!input->checkPosition(0x426)) {
199
102
    MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV1: file is too short\n"));
200
102
    return false;
201
102
  }
202
4.58k
  libmwaw::DebugStream f;
203
4.58k
  f << "Entries(Zone0):";
204
4.58k
  input->seek(4, librevenge::RVNG_SEEK_SET); // seek file def
205
4.58k
  long pos=4;
206
664k
  for (int i=0; i<144; ++i) { // always 0
207
659k
    auto val=static_cast<int>(input->readULong(2));
208
659k
    if (val) f << "f" << i << "=" << val << ",";
209
659k
  }
210
4.58k
  if (!onlyCheck) {
211
518
    ascii().addPos(pos);
212
518
    ascii().addNote(f.str().c_str());
213
518
  }
214
215
8.72k
  for (int z=0; z<8; ++z) {
216
8.20k
    pos=input->tell();
217
8.20k
    f.str("");
218
8.20k
    f << "Zone0-A" << z << ":";
219
8.20k
    int val;
220
8.20k
    val=static_cast<int>(input->readULong(2));
221
8.20k
    if (onlyCheck && z==0 && (val<1 || val>4)) return false;
222
7.94k
    switch (val) {
223
1.49k
    case 0:
224
1.49k
      break;
225
1.85k
    case 1:
226
1.85k
      f << "image=512x512,";
227
1.85k
      if (z==0)
228
1.69k
        m_state->m_bitmapSize=MWAWVec2i(512,512);
229
1.85k
      break;
230
1.41k
    case 2:
231
1.41k
      f << "image=720x576,";
232
1.41k
      if (z==0)
233
1.31k
        m_state->m_bitmapSize=MWAWVec2i(720,576);
234
1.41k
      break;
235
972
    case 3:
236
972
      f << "image=1024x768,";
237
972
      if (z==0)
238
886
        m_state->m_bitmapSize=MWAWVec2i(1024,768);
239
972
      break;
240
445
    case 4:
241
445
      f << "image=1024x1024,";
242
445
      if (z==0)
243
422
        m_state->m_bitmapSize=MWAWVec2i(1024,1024);
244
445
      break;
245
1.75k
    default:
246
1.75k
      MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV1: unknown image size\n"));
247
1.75k
      f << "###image=" << val << ",";
248
1.75k
      break;
249
7.94k
    }
250
39.7k
    for (int i=0; i<4; ++i) {
251
31.7k
      val=static_cast<int>(input->readULong(2));
252
31.7k
      if (val)
253
17.3k
        f << "f" << i << "=" << val << ",";
254
31.7k
    }
255
7.94k
    val=static_cast<int>(input->readULong(2));
256
7.94k
    if (val!=5) // always 5
257
6.38k
      f << "f5=" << val << ",";
258
7.94k
    int dim[4];
259
31.7k
    for (auto &d : dim) d=static_cast<int>(input->readULong(2));
260
7.94k
    if (dim[0]||dim[1]||dim[2]||dim[3])
261
6.37k
      f << "windows[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ",";
262
7.94k
    val=static_cast<int>(input->readULong(2));
263
7.94k
    if (val) // always 0
264
3.61k
      f << "f6=" << val << ",";
265
31.7k
    for (auto &d : dim) d=static_cast<int>(input->readULong(2));
266
7.94k
    if (dim[0]||dim[1]||dim[2]||dim[3])
267
6.31k
      f << "screen1[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ",";
268
71.4k
    for (int i=0; i<8; ++i) { // always 0
269
63.5k
      val=static_cast<int>(input->readULong(2));
270
63.5k
      if (val)
271
31.1k
        f << "f" << i+7 << "=" << val << ",";
272
63.5k
    }
273
31.7k
    for (auto &d : dim) d=static_cast<int>(input->readULong(2));
274
7.94k
    if (dim[0]||dim[1]||dim[2]||dim[3])
275
6.01k
      f << "screen1[sz]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ",";
276
23.8k
    for (int i=0; i<2; ++i) { // f15=1|8, f16=0|69
277
15.8k
      val=static_cast<int>(input->readULong(2));
278
15.8k
      if (val)
279
9.70k
        f << "f" << i+15 << "=" << val << ",";
280
15.8k
    }
281
23.8k
    for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2));
282
7.94k
    if (dim[0]||dim[1]) f << "width=[" << dim[0] << "," << dim[1] << "],";
283
39.7k
    for (int i=0; i<4; ++i) { // g2=1|3
284
31.7k
      val=static_cast<int>(input->readULong(2));
285
31.7k
      if (val)
286
16.4k
        f << "g" << i << "=" << val << ",";
287
31.7k
    }
288
31.7k
    for (int i=0; i<3; ++i) {
289
23.8k
      val=static_cast<int>(input->readULong(4));
290
23.8k
      if (val)
291
17.0k
        f << "ID" << i << "=" << std::hex << val << std::dec << ",";
292
23.8k
    }
293
7.94k
    val=static_cast<int>(input->readULong(2)); // always 0?
294
7.94k
    if (val) f << "g2=" << val << ",";
295
31.7k
    for (auto &d : dim) d=static_cast<int>(input->readULong(2));
296
7.94k
    if (dim[0]||dim[1]||dim[2]||dim[3])
297
6.17k
      f << "screen2[dim]=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ",";
298
7.94k
    if (onlyCheck) {
299
3.79k
      input->seek(0x426, librevenge::RVNG_SEEK_SET);
300
3.79k
      return true;
301
3.79k
    }
302
4.14k
    ascii().addPos(pos);
303
4.14k
    ascii().addNote(f.str().c_str());
304
4.14k
    input->seek(pos+92, librevenge::RVNG_SEEK_SET);
305
4.14k
  }
306
518
  pos=input->tell();
307
518
  f.str("");
308
518
  f << "Zone0-Prefs:";
309
518
  int val;
310
3.10k
  for (int i=0; i<5; ++i) { // always 0?
311
2.59k
    val=static_cast<int>(input->readULong(2));
312
2.59k
    if (val)
313
1.31k
      f << "f" << i << "=" << val << ",";
314
2.59k
  }
315
3.62k
  for (int i=0; i<6; ++i) {
316
3.10k
    val=static_cast<int>(input->readULong(2));
317
3.10k
    static int const expected[]= {1, 0x28, 0xaa, 3, 0xff, 9};
318
3.10k
    if (val==expected[i]) continue;
319
2.66k
    if (i==4)
320
513
      f << "font[sz]=" << val << ",";
321
2.15k
    else
322
2.15k
      f << "f" << i+5 << "=" << val << ",";
323
324
2.66k
  }
325
3.62k
  for (int i=0; i<6; ++i) {
326
3.10k
    val=static_cast<int>(input->readULong(1));
327
3.10k
    if (!val) continue;
328
1.45k
    static char const* const wh[]= {"setForAllTools", "noFullScreen[zoom]","fl2","autoscroll[fatbits]","center[createObject]","remap[color]"};
329
1.45k
    f << wh[i];
330
1.45k
    if (val!=1)
331
1.12k
      f << "=" << val;
332
1.45k
    f << ",";
333
1.45k
  }
334
518
  val=static_cast<int>(input->readLong(2));
335
518
  if (val<0) {
336
159
    f << "option[first]=invertPattern,";
337
159
    val*=-1;
338
159
  }
339
518
  switch (val) {
340
24
  case 1:
341
24
    break;
342
6
  case 2:
343
6
    f << "option[effect]=transp,";
344
6
    break;
345
7
  case 3:
346
7
    f << "option[effect]=invert,";
347
7
    break;
348
78
  case 4:
349
78
    f << "option[effect]=erase,";
350
78
    break;
351
403
  default:
352
403
    f << "###option[effect]=" << val << ",";
353
403
    break;
354
518
  }
355
518
  val=static_cast<int>(input->readLong(2)); // numColors?
356
518
  if (val!=0x100) f << "g0=" << val << ",";
357
518
  val=static_cast<int>(input->readLong(2));
358
518
  if (val!=0x80) f << "g1=" << val << ",";
359
518
  ascii().addPos(pos);
360
518
  ascii().addNote(f.str().c_str());
361
518
  input->seek(0x426, librevenge::RVNG_SEEK_SET);
362
518
  return true;
363
518
}
364
365
bool PixelPaintParser::readFileHeaderV2(bool onlyCheck)
366
6.01k
{
367
6.01k
  MWAWInputStreamPtr input = getInput();
368
6.01k
  if (!input->checkPosition(58)) {
369
0
    MWAW_DEBUG_MSG(("PixelPaintParser::readFileHeaderV2: file is too short\n"));
370
0
    return false;
371
0
  }
372
6.01k
  input->seek(4, librevenge::RVNG_SEEK_SET); // seek file def
373
6.01k
  libmwaw::DebugStream f;
374
6.01k
  f << "Entries(Zone0):";
375
6.01k
  long pos=4;
376
6.01k
  int val;
377
18.0k
  for (int i=0; i<2; ++i) {
378
12.0k
    val=static_cast<int>(input->readULong(2));
379
12.0k
    if (val)
380
7.73k
      f << "f" << i << "=" << val << ",";
381
12.0k
  }
382
6.01k
  int dim[2];
383
12.0k
  for (auto &d : dim) d=static_cast<int>(input->readULong(2));
384
6.01k
  if (dim[0]<=0||dim[0]>1024 || dim[1]<=0 || dim[1]>1024)
385
1.59k
    return false;
386
4.42k
  if (onlyCheck) {
387
3.74k
    input->seek(58, librevenge::RVNG_SEEK_SET);
388
3.74k
    return true;
389
3.74k
  }
390
679
  m_state->m_bitmapSize=MWAWVec2i(dim[1], dim[0]);
391
679
  f << "sz=" << m_state->m_bitmapSize << ",";
392
4.07k
  for (int i=0; i<5; ++i) {
393
3.39k
    val=static_cast<int>(input->readULong(2));
394
3.39k
    static int const expected[]= {8, 0, 0, 0, 0xff };
395
3.39k
    if (val==expected[i]) continue;
396
3.15k
    if (i==0) // checkme
397
650
      f << "font[sz]=" << val << ",";
398
2.50k
    else
399
2.50k
      f << "f" << i << "=" << val << ",";
400
3.15k
  }
401
12.9k
  for (int i=0; i<18; ++i) { // g9=256 : numColor?
402
12.2k
    val=static_cast<int>(input->readULong(2));
403
12.2k
    if (val)
404
9.89k
      f << "g" << i << "=" << val << ",";
405
12.2k
  }
406
679
  input->seek(58, librevenge::RVNG_SEEK_SET);
407
679
  ascii().addPos(pos);
408
679
  ascii().addNote(f.str().c_str());
409
679
  return true;
410
4.42k
}
411
412
bool PixelPaintParser::readColorMap(bool onlyCheck)
413
8.73k
{
414
8.73k
  MWAWInputStreamPtr input = getInput();
415
8.73k
  long pos=input->tell();
416
8.73k
  if (!input->checkPosition(pos+2048)) {
417
435
    MWAW_DEBUG_MSG(("PixelPaintParser::readColorMap: file is too short\n"));
418
435
    return false;
419
435
  }
420
8.30k
  if (onlyCheck) {
421
7.10k
    input->seek(pos+2048, librevenge::RVNG_SEEK_SET);
422
7.10k
    return true;
423
7.10k
  }
424
1.19k
  libmwaw::DebugStream f;
425
1.19k
  f << "Entries(ColorMap):";
426
1.19k
  m_state->m_colorList.resize(256);
427
306k
  for (auto &color : m_state->m_colorList) {
428
306k
    unsigned char c[4];
429
1.22M
    for (auto &col : c) col=static_cast<unsigned char>(input->readULong(2)>>8);
430
306k
    color=MWAWColor(c[1],c[2],c[3],static_cast<unsigned char>(255-c[0]));
431
306k
    f << color << ",";
432
306k
  }
433
1.19k
  ascii().addPos(pos);
434
1.19k
  ascii().addNote(f.str().c_str());
435
1.19k
  return true;
436
8.30k
}
437
438
bool PixelPaintParser::readPatternMap(bool onlyCheck)
439
8.30k
{
440
8.30k
  MWAWInputStreamPtr input = getInput();
441
8.30k
  long pos=input->tell();
442
8.30k
  if (!input->checkPosition(pos+144*8)) {
443
137
    MWAW_DEBUG_MSG(("PixelPaintParser::readPatternMap: file is too short\n"));
444
137
    return false;
445
137
  }
446
8.16k
  if (onlyCheck) {
447
6.96k
    input->seek(pos+144*8, librevenge::RVNG_SEEK_SET);
448
6.96k
    return true;
449
6.96k
  }
450
1.19k
  libmwaw::DebugStream f;
451
1.19k
  f << "Entries(PatternMap):";
452
1.19k
  ascii().addPos(pos);
453
1.19k
  ascii().addNote(f.str().c_str());
454
173k
  for (int i=0; i<144; ++i) {
455
172k
    pos=input->tell();
456
172k
    f.str("");
457
172k
    f << "PatternMap-" << i << ":";
458
172k
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
459
172k
    ascii().addPos(pos);
460
172k
    ascii().addNote(f.str().c_str());
461
172k
  }
462
1.19k
  return true;
463
8.16k
}
464
465
466
////////////////////////////////////////////////////////////
467
// send data
468
////////////////////////////////////////////////////////////
469
bool PixelPaintParser::sendBitmap()
470
179
{
471
179
  MWAWGraphicListenerPtr listener=getGraphicListener();
472
179
  if (!listener) {
473
0
    MWAW_DEBUG_MSG(("PixelPaintParser::sendBitmap: can not find the listener\n"));
474
0
    return false;
475
0
  }
476
477
179
  MWAWEmbeddedObject picture;
478
179
  if (!m_state->m_bitmap || !m_state->m_bitmap->getBinary(picture)) return false;
479
480
179
  MWAWPageSpan const &page=getPageSpan();
481
179
  MWAWPosition pos(MWAWVec2f(float(page.getMarginLeft()),float(page.getMarginRight())),
482
179
                   MWAWVec2f(float(page.getPageWidth()),float(page.getPageLength())), librevenge::RVNG_INCH);
483
179
  pos.setRelativePosition(MWAWPosition::Page);
484
179
  pos.m_wrapping = MWAWPosition::WNone;
485
179
  listener->insertPicture(pos, picture);
486
179
  return true;
487
179
}
488
489
bool PixelPaintParser::readBitmapV1(bool onlyCheck)
490
1.77k
{
491
1.77k
  MWAWInputStreamPtr input = getInput();
492
1.77k
  long pos=input->tell();
493
494
1.77k
  libmwaw::DebugStream f;
495
1.77k
  f << "Entries(Bitmap):";
496
1.77k
  std::shared_ptr<MWAWPictBitmapIndexed> pict;
497
1.77k
  int numColors=256;
498
1.77k
  if (!onlyCheck) {
499
518
    ascii().addPos(pos);
500
518
    ascii().addNote(f.str().c_str());
501
502
518
    if (m_state->m_bitmapSize[0]<=0||m_state->m_bitmapSize[0]>1024 ||
503
518
        m_state->m_bitmapSize[1]<=0||m_state->m_bitmapSize[1]>1024) {
504
0
      MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: argh can not find the bitmap size\n"));
505
0
      return false;
506
0
    }
507
518
    if (m_state->m_colorList.empty()) {
508
0
      MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: argh can not find the color list\n"));
509
0
      return false;
510
0
    }
511
518
    pict.reset(new MWAWPictBitmapIndexed(m_state->m_bitmapSize));
512
518
    numColors=static_cast<int>(m_state->m_colorList.size());
513
518
    pict->setColors(m_state->m_colorList);
514
518
  }
515
1.67M
  for (int i=0; i<16*1024; ++i) {
516
1.67M
    pos=input->tell();
517
1.67M
    auto sz=long(input->readULong(4));
518
1.67M
    long endPos=pos+4+sz;
519
1.67M
    if (sz<2 || !input->checkPosition(endPos)) {
520
799
      input->seek(pos, librevenge::RVNG_SEEK_SET);
521
799
      return false;
522
799
    }
523
1.67M
    int row=i/16;
524
1.67M
    int col=(i%16)*64;
525
1.67M
    f.str("");
526
1.67M
    f << "Bitmap[R" << row << "C" << col << "]:";
527
1.67M
    int nPixel=0;
528
3.81M
    while (input->tell()+2<=endPos) { // UnpackBits
529
2.14M
      auto n=static_cast<int>(input->readULong(1));
530
2.14M
      if (n>=0x81) {
531
1.85M
        auto color=static_cast<int>(input->readULong(1));
532
1.85M
        if (color>=numColors) {
533
0
          static bool first=true;
534
0
          if (first) {
535
0
            MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: find some bad index\n"));
536
0
            first=false;
537
0
          }
538
0
          f << "###id=" << color << ",";
539
0
          color=0;
540
0
        }
541
23.0M
        for (int c=0; c<0x101-n; ++c) {
542
22.7M
          if (!pict || row >= m_state->m_bitmapSize[1] || col >= m_state->m_bitmapSize[0])
543
1.49M
            break;
544
21.2M
          pict->set(col++, row, color);
545
21.2M
        }
546
1.85M
        nPixel+=0x101-n;
547
1.85M
      }
548
287k
      else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression)
549
287k
        if (input->tell()+n+1>endPos) {
550
684
          input->seek(-1, librevenge::RVNG_SEEK_CUR);
551
684
          break;
552
684
        }
553
286k
        nPixel+=n+1;
554
1.82M
        for (int c=0; c<=n; ++c) {
555
1.54M
          auto color=static_cast<int>(input->readULong(1));
556
1.54M
          if (color>=numColors) {
557
0
            static bool first=true;
558
0
            if (first) {
559
0
              MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV1: find some bad index\n"));
560
0
              first=false;
561
0
            }
562
0
            f << "###id=" << color << ",";
563
0
            color=0;
564
0
          }
565
1.54M
          if (!pict || row >= m_state->m_bitmapSize[1] || col >= m_state->m_bitmapSize[0])
566
1.44M
            continue;
567
91.7k
          pict->set(col++, row, color);
568
91.7k
        }
569
286k
      }
570
2.14M
    }
571
1.67M
    f << nPixel;
572
1.67M
    if (onlyCheck) {
573
1.07M
      if (nPixel!=64) return false;
574
1.07M
    }
575
597k
    else {
576
597k
      if (input->tell()!=endPos) {
577
482
        ascii().addDelimiter(input->tell(),'|');
578
482
        f << "###";
579
482
      }
580
597k
      ascii().addPos(pos);
581
597k
      ascii().addNote(f.str().c_str());
582
597k
    }
583
1.67M
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
584
1.67M
  }
585
15
  m_state->m_bitmap=pict;
586
15
  return true;
587
1.77k
}
588
589
bool PixelPaintParser::readBitmapV2(bool onlyCheck)
590
2.01k
{
591
2.01k
  MWAWInputStreamPtr input = getInput();
592
2.01k
  long pos=input->tell();
593
2.01k
  auto dataSz=static_cast<int>(input->readULong(2));
594
2.01k
  if (dataSz<136+2048 || !input->checkPosition(pos+dataSz))
595
146
    return false;
596
1.86k
  libmwaw::DebugStream f;
597
1.86k
  f << "Entries(Bitmap)[header]:";
598
1.86k
  int val;
599
5.60k
  for (int i=0; i<2; ++i) { // always 0
600
3.73k
    val=static_cast<int>(input->readULong(2));
601
3.73k
    if (val)
602
2.36k
      f << "f" << i << "=" << val << ",";
603
3.73k
  }
604
1.86k
  int dim[4];
605
5.60k
  for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2));
606
1.86k
  if (dim[0]<=0||dim[0]>1024 || dim[1]<=0 || dim[1]>1024)
607
210
    return false;
608
1.65k
  m_state->m_bitmapSize=MWAWVec2i(dim[1], dim[0]);
609
1.65k
  f << "sz=" << m_state->m_bitmapSize << ",";
610
9.94k
  for (int i=0; i<5; ++i) { // always 0
611
8.29k
    val=static_cast<int>(input->readULong(2));
612
8.29k
    if (val)
613
5.50k
      f << "f" << i+2 << "=" << val << ",";
614
8.29k
  }
615
16.5k
  for (int i=0; i<9; ++i) { // always 0
616
14.9k
    val=static_cast<int>(input->readULong(2));
617
14.9k
    if (val)
618
11.2k
      f << "f" << i+7 << "=" << val << ",";
619
14.9k
  }
620
9.94k
  for (int i=0; i<5; ++i) {
621
8.29k
    val=static_cast<int>(input->readLong(2));
622
8.29k
    static int const expected[]= {0x11, 0x2ff, 0xc00, -1, -1};
623
8.29k
    if (val!=expected[i])
624
7.84k
      f << "g" << i << "=" << val << ",";
625
8.29k
  }
626
8.29k
  for (int i=0; i<4; ++i) { // always 0
627
6.63k
    val=static_cast<int>(input->readULong(2));
628
6.63k
    if (val)
629
4.19k
      f << "g" << i+4 << "=" << val << ",";
630
6.63k
  }
631
1.65k
  if (!onlyCheck) {
632
619
    ascii().addPos(pos);
633
619
    ascii().addNote(f.str().c_str());
634
619
  }
635
1.65k
  pos=input->tell();
636
1.65k
  f.str("");
637
1.65k
  f << "Bitmap[headerA]:";
638
4.97k
  for (int i=0; i<2; ++i) {
639
3.31k
    val=static_cast<int>(input->readLong(2));
640
3.31k
    if (val!=m_state->m_bitmapSize[i])
641
3.08k
      f << "##dim" << i << "=" << val << ",";
642
3.31k
    val=static_cast<int>(input->readLong(2));
643
3.31k
    if (val)
644
2.00k
      f << "dim" << i << "[low]=" << val << ",";
645
3.31k
  }
646
16.5k
  for (int i=0; i<9; ++i) {
647
14.9k
    val=static_cast<int>(input->readLong(2));
648
14.9k
    static int const expected[]= {0, 0, 1, 0xa, 0, 0, 0x400, 0x400, 0x98 };
649
14.9k
    if (val!=expected[i])
650
13.3k
      f << "f" << i << "=" << val << ",";
651
14.9k
  }
652
1.65k
  val=static_cast<int>(input->readULong(2)); // 8248|8400
653
1.65k
  if (val) f << "fl?=" << std::hex << val << std::dec << ",";
654
4.97k
  for (int i=0; i<2; ++i) {
655
3.31k
    val=static_cast<int>(input->readLong(2));
656
3.31k
    if (val)
657
2.46k
      f << "g" << i << "=" << val << ",";
658
3.31k
  }
659
4.97k
  for (int i=0; i<2; ++i) dim[i]=static_cast<int>(input->readULong(2));
660
1.65k
  if (MWAWVec2i(dim[1], dim[0])!=m_state->m_bitmapSize)
661
1.62k
    f << "sz2=" << MWAWVec2i(dim[1], dim[0]) << ",";
662
663
8.29k
  for (int i=0; i<4; ++i) {
664
6.63k
    val=static_cast<int>(input->readLong(2));
665
6.63k
    if (val)
666
4.29k
      f << "g" << i+2 << "=" << val << ",";
667
6.63k
  }
668
26.5k
  for (int i=0; i<15; ++i) {
669
24.8k
    val=static_cast<int>(input->readLong(2));
670
24.8k
    static int const expected[]= {0x48, 0, 0x48, 0, 0, 8, 1, 8, 0, 0, 0, 0x1f10, 0, 0, 0 };
671
24.8k
    if (val!=expected[i])
672
19.4k
      f << "g" << i+6 << "=" << val << ",";
673
24.8k
  }
674
4.97k
  for (int i=0; i<2; ++i) {  // fl2=bc5|7bb9|bccc, fl3=8000
675
3.31k
    val=static_cast<int>(input->readULong(2));
676
3.31k
    if (val) f << "fl" << i+1 << "=" << std::hex << val << std::dec << ",";
677
3.31k
  }
678
1.65k
  val=static_cast<int>(input->readULong(2));
679
1.65k
  if (val!=255) f << "h0=" << val << ",";
680
1.65k
  if (!onlyCheck) {
681
619
    ascii().addPos(pos);
682
619
    ascii().addNote(f.str().c_str());
683
619
  }
684
685
1.65k
  pos=input->tell();
686
1.65k
  if (onlyCheck)
687
1.03k
    input->seek(pos+2048, librevenge::RVNG_SEEK_SET);
688
619
  else {
689
619
    f.str("");
690
619
    f << "Bitmap[color]:";
691
    // CHECKME: does we want to use this color list or the main color list ?
692
619
    m_state->m_colorList.resize(256);
693
158k
    for (auto &color : m_state->m_colorList) {
694
158k
      val=static_cast<int>(input->readULong(2));
695
158k
      unsigned char c[3];
696
475k
      for (auto &col : c) col=static_cast<unsigned char>(input->readULong(2)>>8);
697
158k
      color=MWAWColor(c[0],c[1],c[2]);
698
158k
      f << color;
699
158k
      if (val!=0x800)
700
151k
        f << "[" << std::hex << val << std::dec << "],";
701
7.04k
      else
702
7.04k
        f << ",";
703
158k
    }
704
705
619
    ascii().addPos(pos);
706
619
    ascii().addNote(f.str().c_str());
707
708
619
    input->seek(pos+2048, librevenge::RVNG_SEEK_SET);
709
619
  }
710
711
1.65k
  pos=input->tell();
712
1.65k
  if (!input->checkPosition(pos+18))
713
0
    return false;
714
1.65k
  if (!onlyCheck) {
715
619
    f.str("");
716
619
    f << "Bitmap[headerB]:";
717
1.85k
    for (int i=0; i<2; ++i) {
718
4.95k
      for (auto &d : dim) d=static_cast<int>(input->readULong(2));
719
1.23k
      if (dim[0]||dim[1]||m_state->m_bitmapSize!=MWAWVec2i(dim[3],dim[2]))
720
1.19k
        f << "dim" << i << "=" << MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2])) << ",";
721
1.23k
    }
722
619
    val=static_cast<int>(input->readLong(2)); // always 0 ?
723
619
    if (val) f << "f0=" << val << ",";
724
619
    ascii().addPos(pos);
725
619
    ascii().addNote(f.str().c_str());
726
619
  }
727
728
1.65k
  input->seek(pos+18, librevenge::RVNG_SEEK_SET);
729
1.65k
  int numColors=0;
730
1.65k
  std::shared_ptr<MWAWPictBitmapIndexed> pict;
731
1.65k
  if (!onlyCheck) {
732
619
    ascii().addPos(input->tell());
733
619
    ascii().addNote(f.str().c_str());
734
735
619
    if (m_state->m_bitmapSize[0]<=0||m_state->m_bitmapSize[0]>1024 ||
736
619
        m_state->m_bitmapSize[1]<=0||m_state->m_bitmapSize[1]>1024) {
737
0
      MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: argh can not find the bitmap size\n"));
738
0
      return false;
739
0
    }
740
619
    if (m_state->m_colorList.empty()) {
741
0
      MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: argh can not find the color list\n"));
742
0
      return false;
743
0
    }
744
619
    pict.reset(new MWAWPictBitmapIndexed(m_state->m_bitmapSize));
745
619
    numColors=static_cast<int>(m_state->m_colorList.size());
746
619
    pict->setColors(m_state->m_colorList);
747
619
  }
748
749
47.2k
  for (int row=0; row<m_state->m_bitmapSize[1]; ++row) {
750
46.7k
    pos=input->tell();
751
46.7k
    dataSz=static_cast<int>(input->readULong(2));
752
46.7k
    long endPos=pos+2+dataSz;
753
46.7k
    if (dataSz<2 || !input->checkPosition(endPos)) {
754
1.20k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
755
1.20k
      return false;
756
1.20k
    }
757
45.5k
    if (onlyCheck) {
758
28.1k
      input->seek(endPos, librevenge::RVNG_SEEK_SET);
759
28.1k
      continue;
760
28.1k
    }
761
17.4k
    f.str("");
762
17.4k
    f << "Bitmap[R" << row << "]:";
763
17.4k
    int col=0, nPixel=0;
764
2.39M
    while (input->tell()+2<=endPos) { // UnpackBits
765
2.38M
      auto n=static_cast<int>(input->readULong(1));
766
2.38M
      if (n>=0x81) {
767
474k
        auto color=static_cast<int>(input->readULong(1));
768
474k
        if (color>=numColors) {
769
0
          static bool first=true;
770
0
          if (first) {
771
0
            MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find some bad index\n"));
772
0
            first=false;
773
0
          }
774
0
          f << "###id=" << color << ",";
775
0
          color=0;
776
0
        }
777
4.95M
        for (int c=0; c<0x101-n; ++c) {
778
4.90M
          if (!pict || col >= m_state->m_bitmapSize[0])
779
424k
            break;
780
4.48M
          pict->set(col++, row, color);
781
4.48M
        }
782
474k
        nPixel+=0x101-n;
783
474k
      }
784
1.91M
      else { // checkme normally 0x80 is reserved and almost nobody used it (for ending the compression)
785
1.91M
        if (input->tell()+n+1>endPos) {
786
7.82k
          input->seek(-1, librevenge::RVNG_SEEK_CUR);
787
7.82k
          break;
788
7.82k
        }
789
1.90M
        nPixel+=n+1;
790
11.8M
        for (int c=0; c<=n; ++c) {
791
9.89M
          auto color=static_cast<int>(input->readULong(1));
792
9.89M
          if (color>=numColors) {
793
0
            static bool first=true;
794
0
            if (first) {
795
0
              MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find some bad index\n"));
796
0
              first=false;
797
0
            }
798
0
            f << "###id=" << color << ",";
799
0
            color=0;
800
0
          }
801
9.89M
          if (!pict || col >= m_state->m_bitmapSize[0])
802
7.92M
            continue;
803
1.97M
          pict->set(col++, row, color);
804
1.97M
        }
805
1.90M
      }
806
2.38M
    }
807
17.4k
    if (nPixel<m_state->m_bitmapSize[0] || nPixel>m_state->m_bitmapSize[0]+32) {
808
10.6k
      static bool first=true;
809
10.6k
      if (first) {
810
13
        MWAW_DEBUG_MSG(("PixelPaintParser::readBitmapV2: find row with odd number of pixel\n"));
811
13
        first=false;
812
13
      }
813
10.6k
      f << "###numPixel=" << nPixel << ",";
814
10.6k
    }
815
17.4k
    if (input->tell()!=endPos) {
816
9.03k
      ascii().addDelimiter(input->tell(),'|');
817
9.03k
      f << "###";
818
9.03k
    }
819
17.4k
    ascii().addPos(pos);
820
17.4k
    ascii().addNote(f.str().c_str());
821
17.4k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
822
17.4k
  }
823
454
  m_state->m_bitmap=pict;
824
454
  return true;
825
1.65k
}
826
827
////////////////////////////////////////////////////////////
828
// read the header
829
////////////////////////////////////////////////////////////
830
bool PixelPaintParser::checkHeader(MWAWHeader *header, bool strict)
831
15.5k
{
832
15.5k
  *m_state = PixelPaintParserInternal::State();
833
15.5k
  MWAWInputStreamPtr input = getInput();
834
15.5k
  if (!input || !input->hasDataFork() || !input->checkPosition(512))
835
5.89k
    return false;
836
9.64k
  input->seek(0, librevenge::RVNG_SEEK_SET);
837
9.64k
  if (input->readULong(2))
838
72
    return false;
839
9.57k
  int vers=1;
840
9.57k
  auto val=static_cast<int>(input->readULong(2));
841
9.57k
  if (val==0x7fff)
842
4.16k
    ;
843
5.40k
  else if (val==0x8000)
844
5.33k
    vers=2;
845
73
  else
846
73
    return false;
847
9.49k
  if ((vers==1&&!readFileHeaderV1(true)) || (vers==2&&!readFileHeaderV2(true)))
848
1.96k
    return false;
849
7.53k
  if (!readColorMap(true) || !readPatternMap(true))
850
572
    return false;
851
6.96k
  if (strict) {
852
2.59k
    if ((vers==1 && !readBitmapV1(true)) || (vers==2 && !readBitmapV2(true)))
853
2.30k
      return false;
854
2.59k
  }
855
4.66k
  setVersion(vers);
856
4.66k
  if (header)
857
2.27k
    header->reset(MWAWDocument::MWAW_T_PIXELPAINT, vers, MWAWDocument::MWAW_K_PAINT);
858
859
4.66k
  return true;
860
6.96k
}
861
862
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: