Coverage Report

Created: 2026-09-06 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcdr/src/lib/CMXParser.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libcdr project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "CMXParser.h"
11
12
#include <librevenge-stream/librevenge-stream.h>
13
14
#include <math.h>
15
#include <stdlib.h>
16
#include <utility>
17
#include <cinttypes>
18
19
#include "libcdr_utils.h"
20
#include "CDRPath.h"
21
#include "CDRCollector.h"
22
#include "CDRDocumentStructure.h"
23
#include "CMXDocumentStructure.h"
24
25
#ifndef DUMP_PREVIEW_IMAGE
26
#define DUMP_PREVIEW_IMAGE 0
27
#endif
28
29
#ifndef DUMP_IMAGE
30
#define DUMP_IMAGE 0
31
#endif
32
33
static const int MAX_RECORD_DEPTH = 1 << 10;
34
35
namespace
36
{
37
38
uint16_t readTagLength(librevenge::RVNGInputStream *const input, const bool bigEndian)
39
0
{
40
0
  uint16_t tagLength = libcdr::readU16(input, bigEndian);
41
0
  if (tagLength < 3)
42
0
  {
43
0
    CDR_DEBUG_MSG(("invalid tag length %" PRIu16 "\n", tagLength));
44
0
    tagLength = 3;
45
0
  }
46
0
  return tagLength;
47
0
}
48
49
void sanitizeNumRecords(
50
  unsigned long &numRecords,
51
  const libcdr::CoordinatePrecision precision, const unsigned size16, const unsigned size32,
52
  const unsigned long remainingLength)
53
0
{
54
0
  unsigned recordSize = 1;
55
0
  if (precision == libcdr::PRECISION_16BIT)
56
0
    recordSize = size16;
57
0
  else if (precision == libcdr::PRECISION_32BIT)
58
0
    recordSize = size32;
59
0
  if (numRecords > remainingLength / recordSize)
60
0
    numRecords = remainingLength / recordSize;
61
0
}
62
63
void sanitizeNumRecords(
64
  unsigned long &numRecords,
65
  const libcdr::CoordinatePrecision precision, const unsigned size16, const unsigned size32, const unsigned tags,
66
  const unsigned long remainingLength)
67
0
{
68
0
  sanitizeNumRecords(numRecords, precision, size16, size32 + 3 * tags + 1, remainingLength);
69
0
}
70
71
}
72
73
libcdr::CMXParser::CMXParser(libcdr::CDRCollector *collector, CMXParserState &parserState)
74
18.0k
  : CommonParser(collector),
75
18.0k
    m_bigEndian(false), m_unit(0),
76
18.0k
    m_scale(0.0), m_xmin(0.0), m_xmax(0.0), m_ymin(0.0), m_ymax(0.0),
77
18.0k
    m_fillIndex(0), m_nextInstructionOffset(0), m_parserState(parserState),
78
18.0k
    m_currentImageInfo(), m_currentPattern(), m_currentBitmap() {}
79
80
libcdr::CMXParser::~CMXParser()
81
18.0k
{
82
18.0k
}
83
84
bool libcdr::CMXParser::parseRecords(librevenge::RVNGInputStream *input, long size, unsigned level)
85
38.8k
{
86
38.8k
  if (!input || level > MAX_RECORD_DEPTH)
87
1
  {
88
1
    return false;
89
1
  }
90
38.8k
  m_collector->collectLevel(level);
91
38.8k
  long endPosition = -1;
92
38.8k
  if (size > 0)
93
18.3k
    endPosition = input->tell() + size;
94
86.7k
  while (!input->isEnd() && (endPosition < 0 || input->tell() < endPosition))
95
50.0k
  {
96
50.0k
    if (!parseRecord(input, level))
97
2.14k
      return false;
98
50.0k
  }
99
36.7k
  return true;
100
38.8k
}
101
102
bool libcdr::CMXParser::parseRecord(librevenge::RVNGInputStream *input, unsigned level)
103
50.0k
{
104
50.0k
  if (!input)
105
0
  {
106
0
    return false;
107
0
  }
108
50.0k
  try
109
50.0k
  {
110
50.0k
    m_collector->collectLevel(level);
111
166k
    while (!input->isEnd() && readU8(input, m_bigEndian) == 0)
112
116k
    {
113
116k
    }
114
50.0k
    if (!input->isEnd())
115
33.3k
      input->seek(-1, librevenge::RVNG_SEEK_CUR);
116
16.6k
    else
117
16.6k
      return true;
118
33.3k
    unsigned fourCC = readU32(input, m_bigEndian);
119
33.3k
    unsigned long length = readU32(input, m_bigEndian);
120
33.3k
    const unsigned long maxLength = getRemainingLength(input);
121
33.3k
    if (length > maxLength)
122
19.2k
      length = maxLength;
123
33.3k
    long endPosition = input->tell() + length;
124
125
33.3k
    CDR_DEBUG_MSG(("Record: level %u %s, length: 0x%.8lx (%lu)\n", level, toFourCC(fourCC), length, length));
126
127
33.3k
    if (fourCC == CDR_FOURCC_RIFF || fourCC == CDR_FOURCC_RIFX || fourCC == CDR_FOURCC_LIST)
128
20.8k
    {
129
20.8k
      if (length < 4)
130
17
        return false;
131
#ifdef DEBUG
132
      unsigned listType = readU32(input, m_bigEndian);
133
#else
134
20.7k
      input->seek(4, librevenge::RVNG_SEEK_CUR);
135
20.7k
#endif
136
20.7k
      CDR_DEBUG_MSG(("CMX listType: %s\n", toFourCC(listType)));
137
20.7k
      unsigned long dataSize = length-4;
138
20.7k
      if (!parseRecords(input, dataSize, level+1))
139
1.80k
        return false;
140
20.7k
    }
141
12.5k
    else
142
12.5k
      readRecord(fourCC, length, input);
143
144
31.4k
    if (input->tell() < endPosition)
145
27
      input->seek(endPosition, librevenge::RVNG_SEEK_SET);
146
31.4k
    return true;
147
33.3k
  }
148
50.0k
  catch (...)
149
50.0k
  {
150
328
    return false;
151
328
  }
152
50.0k
}
153
154
void libcdr::CMXParser::parseImage(librevenge::RVNGInputStream *input)
155
0
{
156
0
  if (!input)
157
0
  {
158
0
    return;
159
0
  }
160
0
  try
161
0
  {
162
0
    while (!input->isEnd() && readU8(input, m_bigEndian) == 0)
163
0
    {
164
0
    }
165
0
    if (!input->isEnd())
166
0
      input->seek(-1, librevenge::RVNG_SEEK_CUR);
167
0
    else
168
0
      return;
169
0
    unsigned fourCC = readU32(input, m_bigEndian);
170
0
    unsigned long length = readU32(input, m_bigEndian);
171
0
    const unsigned long maxLength = getRemainingLength(input);
172
0
    if (length > maxLength)
173
0
      length = maxLength;
174
0
    long endPosition = input->tell() + length;
175
176
0
    if (fourCC != CDR_FOURCC_LIST)
177
0
      return;
178
0
    unsigned listType = readU32(input, m_bigEndian);
179
0
    CDR_DEBUG_MSG(("CMX listType: %s\n", toFourCC(listType)));
180
0
    if (listType != CDR_FOURCC_imag)
181
0
      return;
182
0
    unsigned long dataSize = length-4;
183
0
    if (!parseRecords(input, dataSize, 0))
184
0
      return;
185
186
0
    if (input->tell() < endPosition)
187
0
      input->seek(endPosition, librevenge::RVNG_SEEK_SET);
188
0
  }
189
0
  catch (...)
190
0
  {
191
0
  }
192
0
}
193
194
void libcdr::CMXParser::readRecord(unsigned fourCC, unsigned long length, librevenge::RVNGInputStream *input)
195
12.4k
{
196
12.4k
  long recordEnd = input->tell() + length;
197
12.4k
  switch (fourCC)
198
12.4k
  {
199
689
  case CDR_FOURCC_cont:
200
689
    readCMXHeader(input);
201
689
    return;
202
11
  case CDR_FOURCC_info:
203
11
    readInfo(input);
204
11
    break;
205
2
  case CDR_FOURCC_data:
206
2
    readData(input);
207
2
    break;
208
11.7k
  default:
209
11.7k
    break;
210
12.4k
  }
211
11.7k
  if (input->tell() < recordEnd)
212
2.50k
    input->seek(recordEnd, librevenge::RVNG_SEEK_SET);
213
11.7k
}
214
215
void libcdr::CMXParser::readCMXHeader(librevenge::RVNGInputStream *input)
216
689
{
217
689
  librevenge::RVNGString tmpString;
218
689
  unsigned i = 0;
219
22.1k
  for (i = 0; i < 32; i++)
220
21.4k
    tmpString.append((char)readU8(input, m_bigEndian));
221
689
  CDR_DEBUG_MSG(("CMX File ID: %s\n", tmpString.cstr()));
222
689
  tmpString.clear();
223
10.4k
  for (i = 0; i < 16; i++)
224
9.71k
    tmpString.append((char)readU8(input, m_bigEndian));
225
689
  CDR_DEBUG_MSG(("CMX Platform: %s\n", tmpString.cstr()));
226
689
  tmpString.clear();
227
3.08k
  for (i = 0; i < 4; i++)
228
2.39k
    tmpString.append((char)readU8(input, m_bigEndian));
229
689
  CDR_DEBUG_MSG(("CMX Byte Order: %s\n", tmpString.cstr()));
230
689
  if (4 == atoi(tmpString.cstr()))
231
11
    m_bigEndian = true;
232
689
  tmpString.clear();
233
1.87k
  for (i = 0; i < 2; i++)
234
1.18k
    tmpString.append((char)readU8(input, m_bigEndian));
235
689
  CDR_DEBUG_MSG(("CMX Coordinate Size: %s\n", tmpString.cstr()));
236
689
  auto coordSize = (unsigned short)atoi(tmpString.cstr());
237
689
  switch (coordSize)
238
689
  {
239
1
  case 2:
240
1
    m_precision = libcdr::PRECISION_16BIT;
241
1
    break;
242
2
  case 4:
243
2
    m_precision = libcdr::PRECISION_32BIT;
244
2
    break;
245
587
  default:
246
587
    m_precision = libcdr::PRECISION_UNKNOWN;
247
587
    break;
248
689
  }
249
590
  tmpString.clear();
250
2.94k
  for (i = 0; i < 4; i++)
251
2.35k
    tmpString.append((char)readU8(input, m_bigEndian));
252
590
  CDR_DEBUG_MSG(("CMX Version Major: %s\n", tmpString.cstr()));
253
590
  tmpString.clear();
254
2.92k
  for (i = 0; i < 4; i++)
255
2.33k
    tmpString.append((char)readU8(input, m_bigEndian));
256
590
  CDR_DEBUG_MSG(("CMX Version Minor: %s\n", tmpString.cstr()));
257
590
  m_unit = readU16(input, m_bigEndian);
258
590
  CDR_DEBUG_MSG(("CMX Base Units: %u\n", m_unit));
259
590
  m_scale = readDouble(input, m_bigEndian);
260
590
  CDR_DEBUG_MSG(("CMX Units Scale: %.9f\n", m_scale));
261
590
  input->seek(12, librevenge::RVNG_SEEK_CUR);
262
590
  unsigned indexSectionOffset = readU32(input, m_bigEndian);
263
#ifdef DEBUG
264
  unsigned infoSectionOffset = readU32(input, m_bigEndian);
265
#else
266
590
  input->seek(4, librevenge::RVNG_SEEK_CUR);
267
590
#endif
268
590
  unsigned thumbnailOffset = readU32(input, m_bigEndian);
269
#ifdef DEBUG
270
  CDRBox box = readBBox(input);
271
#endif
272
590
  CDR_DEBUG_MSG(("CMX Offsets: index section 0x%.8x, info section: 0x%.8x, thumbnail: 0x%.8x\n",
273
590
                 indexSectionOffset, infoSectionOffset, thumbnailOffset));
274
590
  CDR_DEBUG_MSG(("CMX Bounding Box: x: %f, y: %f, w: %f, h: %f\n", box.m_x, box.m_y, box.m_w, box.m_h));
275
590
  if (thumbnailOffset != (unsigned)-1)
276
540
  {
277
540
    long oldOffset = input->tell();
278
540
    input->seek(thumbnailOffset, librevenge::RVNG_SEEK_SET);
279
540
    readDisp(input);
280
540
    input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
281
540
  }
282
590
  if (indexSectionOffset != (unsigned)-1)
283
456
  {
284
456
    long oldOffset = input->tell();
285
456
    input->seek(indexSectionOffset, librevenge::RVNG_SEEK_SET);
286
456
    readIxmr(input);
287
456
    input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
288
456
  }
289
590
}
290
291
void libcdr::CMXParser::readDisp(librevenge::RVNGInputStream *input)
292
540
{
293
540
  unsigned fourCC = readU32(input, m_bigEndian);
294
540
  if (CDR_FOURCC_DISP != fourCC)
295
494
    return;
296
46
  unsigned long length = readU32(input, m_bigEndian);
297
46
  const unsigned long maxLength = getRemainingLength(input);
298
46
  if (length > maxLength)
299
0
    length = maxLength;
300
301
46
  librevenge::RVNGBinaryData previewImage;
302
46
  previewImage.append((unsigned char)0x42);
303
46
  previewImage.append((unsigned char)0x4d);
304
305
46
  previewImage.append((unsigned char)((length+8) & 0x000000ff));
306
46
  previewImage.append((unsigned char)(((length+8) & 0x0000ff00) >> 8));
307
46
  previewImage.append((unsigned char)(((length+8) & 0x00ff0000) >> 16));
308
46
  previewImage.append((unsigned char)(((length+8) & 0xff000000) >> 24));
309
310
46
  previewImage.append((unsigned char)0x00);
311
46
  previewImage.append((unsigned char)0x00);
312
46
  previewImage.append((unsigned char)0x00);
313
46
  previewImage.append((unsigned char)0x00);
314
315
46
  long startPosition = input->tell();
316
46
  input->seek(0x18, librevenge::RVNG_SEEK_CUR);
317
46
  unsigned long lengthX = length + 10 - readU32(input, m_bigEndian);
318
46
  input->seek(startPosition, librevenge::RVNG_SEEK_SET);
319
320
46
  previewImage.append((unsigned char)((lengthX) & 0x000000ff));
321
46
  previewImage.append((unsigned char)(((lengthX) & 0x0000ff00) >> 8));
322
46
  previewImage.append((unsigned char)(((lengthX) & 0x00ff0000) >> 16));
323
46
  previewImage.append((unsigned char)(((lengthX) & 0xff000000) >> 24));
324
325
46
  input->seek(4, librevenge::RVNG_SEEK_CUR);
326
46
  for (unsigned long i = 4; i<length; i++)
327
0
    previewImage.append(readU8(input, m_bigEndian));
328
#if DUMP_PREVIEW_IMAGE
329
  FILE *f = fopen("previewImage.bmp", "wb");
330
  if (f)
331
  {
332
    const unsigned char *tmpBuffer = previewImage.getDataBuffer();
333
    for (unsigned long k = 0; k < previewImage.size(); k++)
334
      fprintf(f, "%c",tmpBuffer[k]);
335
    fclose(f);
336
  }
337
#endif
338
46
}
339
340
const unsigned *libcdr::CMXParser::_getOffsetByType(unsigned short type, const std::map<unsigned short, unsigned> &offsets)
341
0
{
342
0
  auto iter = offsets.find(type);
343
0
  if (iter != offsets.end())
344
0
    return &(iter->second);
345
0
  return nullptr;
346
0
}
347
348
void libcdr::CMXParser::readIxmr(librevenge::RVNGInputStream *input)
349
456
{
350
456
  unsigned fourCC = readU32(input, m_bigEndian);
351
456
  if (CDR_FOURCC_ixmr != fourCC)
352
397
    return;
353
59
  readU32(input, m_bigEndian); // Length
354
355
59
  readU16(input, m_bigEndian); // Master ID
356
59
  readU16(input, m_bigEndian); // Size
357
59
  unsigned long recordCount = readU16(input, m_bigEndian);
358
59
  if (recordCount > getRemainingLength(input) / 6)
359
0
    recordCount = getRemainingLength(input) / 6;
360
59
  std::map<unsigned short, unsigned> offsets;
361
59
  for (unsigned long i = 1; i <= recordCount; ++i)
362
0
  {
363
0
    unsigned short indexRecordId = readU16(input, m_bigEndian);
364
0
    unsigned offset = readU32(input, m_bigEndian);
365
0
    offsets[indexRecordId] = offset;
366
0
  }
367
59
  long oldOffset = input->tell();
368
59
  const unsigned *address = nullptr;
369
59
  if ((address = _getOffsetByType(CMX_COLOR_DESCRIPTION_SECTION, offsets)))
370
0
  {
371
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
372
0
    readRclr(input);
373
0
  }
374
59
  if ((address = _getOffsetByType(CMX_DOT_DASH_DESCRIPTION_SECTION, offsets)))
375
0
  {
376
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
377
0
    readRdot(input);
378
0
  }
379
59
  if ((address = _getOffsetByType(CMX_PEN_DESCRIPTION_SECTION, offsets)))
380
0
  {
381
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
382
0
    readRpen(input);
383
0
  }
384
59
  if ((address = _getOffsetByType(CMX_LINE_STYLE_DESCRIPTION_SECTION, offsets)))
385
0
  {
386
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
387
0
    readRott(input);
388
0
  }
389
59
  if ((address = _getOffsetByType(CMX_OUTLINE_DESCRIPTION_SECTION, offsets)))
390
0
  {
391
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
392
0
    readRotl(input);
393
0
  }
394
59
  if ((address = _getOffsetByType(CMX_BITMAP_INDEX_TABLE, offsets)))
395
0
  {
396
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
397
0
    readIxtl(input);
398
0
  }
399
59
  if ((address = _getOffsetByType(CMX_EMBEDDED_FILE_INDEX_TABLE, offsets)))
400
0
  {
401
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
402
0
    readIxef(input);
403
0
  }
404
59
  if ((address = _getOffsetByType(CMX_PROCEDURE_INDEX_TABLE, offsets)))
405
0
  {
406
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
407
0
    readIxpc(input);
408
0
  }
409
59
  if ((address = _getOffsetByType(CMX_PAGE_INDEX_TABLE, offsets)))
410
0
  {
411
0
    input->seek(*address, librevenge::RVNG_SEEK_SET);
412
0
    readIxpg(input);
413
0
  }
414
59
  input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
415
59
}
416
417
void libcdr::CMXParser::readCommands(librevenge::RVNGInputStream *input, unsigned length)
418
0
{
419
0
  long endPosition = length + input->tell();
420
0
  while (!input->isEnd() && endPosition > input->tell())
421
0
  {
422
0
    long startPosition = input->tell();
423
0
    int instructionSize = readS16(input, m_bigEndian);
424
0
    int minInstructionSize = 4;
425
0
    if (instructionSize < 0)
426
0
    {
427
0
      instructionSize = readS32(input, m_bigEndian);
428
0
      minInstructionSize += 4;
429
0
    }
430
0
    if (instructionSize < minInstructionSize)
431
0
    {
432
0
      CDR_DEBUG_MSG(("CMXParser::readCommands - invalid instructionSize %i\n", instructionSize));
433
0
      instructionSize = minInstructionSize;
434
0
    }
435
0
    m_nextInstructionOffset = startPosition+instructionSize;
436
0
    short instructionCode = abs(readS16(input, m_bigEndian));
437
0
    CDR_DEBUG_MSG(("CMXParser::readCommands - instructionSize %i, instructionCode %i\n", instructionSize, instructionCode));
438
0
    switch (instructionCode)
439
0
    {
440
0
    case CMX_Command_BeginPage:
441
0
      readBeginPage(input);
442
0
      break;
443
0
    case CMX_Command_BeginLayer:
444
0
      readBeginLayer(input);
445
0
      break;
446
0
    case CMX_Command_BeginGroup:
447
0
      readBeginGroup(input);
448
0
      break;
449
0
    case CMX_Command_PolyCurve:
450
0
      readPolyCurve(input);
451
0
      break;
452
0
    case CMX_Command_Ellipse:
453
0
      readEllipse(input);
454
0
      break;
455
0
    case CMX_Command_Rectangle:
456
0
      readRectangle(input);
457
0
      break;
458
0
    case CMX_Command_JumpAbsolute:
459
0
      readJumpAbsolute(input);
460
0
      break;
461
0
    case CMX_Command_DrawImage:
462
0
      readDrawImage(input);
463
0
      break;
464
0
    default:
465
0
      break;
466
0
    }
467
0
    input->seek(m_nextInstructionOffset, librevenge::RVNG_SEEK_SET);
468
0
  }
469
0
}
470
471
void libcdr::CMXParser::readPage(librevenge::RVNGInputStream *input)
472
0
{
473
0
  unsigned fourCC = readU32(input, m_bigEndian);
474
0
  if (CDR_FOURCC_page != fourCC)
475
0
    return;
476
0
  unsigned length = readU32(input, m_bigEndian);
477
0
  CDR_DEBUG_MSG(("CMXParser::readPage\n"));
478
0
  readCommands(input, length);
479
0
}
480
481
void libcdr::CMXParser::readProc(librevenge::RVNGInputStream *input)
482
0
{
483
0
  unsigned fourCC = readU32(input, m_bigEndian);
484
0
  if (CDR_FOURCC_proc != fourCC)
485
0
    return;
486
0
  unsigned length = readU32(input, m_bigEndian);
487
0
  CDR_DEBUG_MSG(("CMXParser::readProc\n"));
488
0
  readCommands(input, length);
489
0
}
490
491
void libcdr::CMXParser::readBeginPage(librevenge::RVNGInputStream *input)
492
0
{
493
0
  CDRBox box;
494
0
  CDRTransform matrix;
495
0
  unsigned flags = 0;
496
0
  if (m_precision == libcdr::PRECISION_32BIT)
497
0
  {
498
0
    unsigned char tagId = 0;
499
0
    unsigned short tagLength = 0;
500
0
    do
501
0
    {
502
0
      long startOffset = input->tell();
503
0
      tagId = readU8(input, m_bigEndian);
504
0
      if (tagId == CMX_Tag_EndTag)
505
0
      {
506
0
        CDR_DEBUG_MSG(("  CMXParser::readBeginPage - tagId %i\n", tagId));
507
0
        break;
508
0
      }
509
0
      tagLength = readTagLength(input, m_bigEndian);
510
0
      CDR_DEBUG_MSG(("  CMXParser::readBeginPage - tagId %i, tagLength %u\n", tagId, tagLength));
511
0
      switch (tagId)
512
0
      {
513
0
      case CMX_Tag_BeginPage_PageSpecification:
514
0
        input->seek(2, librevenge::RVNG_SEEK_CUR);
515
0
        flags = readU32(input, m_bigEndian);
516
0
        box = readBBox(input);
517
0
        break;
518
0
      case CMX_Tag_BeginPage_Matrix:
519
0
        matrix = readMatrix(input);
520
0
        break;
521
0
      default:
522
0
        break;
523
0
      }
524
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
525
0
    }
526
0
    while (tagId != CMX_Tag_EndTag);
527
0
  }
528
0
  else if (m_precision == libcdr::PRECISION_16BIT)
529
0
  {
530
0
    input->seek(2, librevenge::RVNG_SEEK_CUR);
531
0
    flags = readU32(input, m_bigEndian);
532
0
    box = readBBox(input);
533
0
  }
534
0
  else
535
0
    return;
536
0
  m_collector->collectPage(0);
537
0
  m_collector->collectFlags(flags, true);
538
0
  m_collector->collectPageSize(box.getWidth(), box.getHeight(), box.getMinX(), box.getMinY());
539
0
}
540
void libcdr::CMXParser::readBeginLayer(librevenge::RVNGInputStream * /* input */)
541
0
{
542
0
}
543
void libcdr::CMXParser::readBeginGroup(librevenge::RVNGInputStream *input)
544
0
{
545
0
  CDRBox box;
546
0
  if (m_precision == libcdr::PRECISION_32BIT)
547
0
  {
548
0
    unsigned char tagId = 0;
549
0
    unsigned short tagLength = 0;
550
0
    do
551
0
    {
552
0
      long startOffset = input->tell();
553
0
      tagId = readU8(input, m_bigEndian);
554
0
      if (tagId == CMX_Tag_EndTag)
555
0
      {
556
0
        CDR_DEBUG_MSG(("  CMXParser::readBeginGroup - tagId %i\n", tagId));
557
0
        break;
558
0
      }
559
0
      tagLength = readTagLength(input, m_bigEndian);
560
0
      CDR_DEBUG_MSG(("  CMXParser::readBeginGroup - tagId %i, tagLength %u\n", tagId, tagLength));
561
0
      switch (tagId)
562
0
      {
563
0
      case CMX_Tag_BeginGroup_GroupSpecification:
564
0
      {
565
0
        box = readBBox(input);
566
0
        /* unsigned short groupCount = */ readU16(input, m_bigEndian);
567
0
        /* unsigned commandCount = */ readU32(input, m_bigEndian);
568
0
        /* unsigned endAddress = */ readU32(input, m_bigEndian);
569
0
        break;
570
0
      }
571
0
      default:
572
0
        break;
573
0
      }
574
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
575
0
    }
576
0
    while (tagId != CMX_Tag_EndTag);
577
0
  }
578
0
  else if (m_precision == libcdr::PRECISION_16BIT)
579
0
  {
580
0
    box = readBBox(input);
581
0
    /* unsigned short groupCount = */ readU16(input, m_bigEndian);
582
0
    /* unsigned commandCount = */ readU32(input, m_bigEndian);
583
0
    /* unsigned endAddress = */ readU32(input, m_bigEndian);
584
0
  }
585
0
  else
586
0
    return;
587
0
  m_collector->collectBBox(box.getMinX(), box.getMinX() + box.getWidth(), box.getMinY(), box.getMinY() + box.getHeight());
588
0
}
589
590
void libcdr::CMXParser::readPolyCurve(librevenge::RVNGInputStream *input)
591
0
{
592
0
  m_collector->collectObject(1);
593
0
  unsigned long pointNum = 0;
594
0
  std::vector<std::pair<double, double> > points;
595
0
  std::vector<unsigned char> pointTypes;
596
0
  if (m_precision == libcdr::PRECISION_32BIT)
597
0
  {
598
0
    unsigned char tagId = 0;
599
0
    unsigned short tagLength = 0;
600
0
    do
601
0
    {
602
0
      long startOffset = input->tell();
603
0
      tagId = readU8(input, m_bigEndian);
604
0
      if (tagId == CMX_Tag_EndTag)
605
0
      {
606
0
        CDR_DEBUG_MSG(("  CMXParser::readPolyCurve - tagId %i\n", tagId));
607
0
        break;
608
0
      }
609
0
      tagLength = readTagLength(input, m_bigEndian);
610
0
      CDR_DEBUG_MSG(("  CMXParser::readPolyCurve - tagId %i, tagLength %u\n", tagId, tagLength));
611
0
      switch (tagId)
612
0
      {
613
0
      case CMX_Tag_PolyCurve_RenderingAttr:
614
0
        readRenderingAttributes(input);
615
0
        break;
616
0
      case CMX_Tag_PolyCurve_PointList:
617
0
        pointNum = readU16(input, m_bigEndian);
618
0
        if (pointNum > getRemainingLength(input) / (2 * 4 + 1))
619
0
          pointNum = getRemainingLength(input) / (2 * 4 + 1);
620
0
        points.reserve(pointNum);
621
0
        pointTypes.reserve(pointNum);
622
0
        for (unsigned long i = 0; i < pointNum; ++i)
623
0
        {
624
0
          std::pair<double, double> point;
625
0
          point.first = readCoordinate(input, m_bigEndian);
626
0
          point.second = readCoordinate(input, m_bigEndian);
627
0
          points.push_back(point);
628
0
        }
629
0
        for (unsigned long j = 0; j < pointNum; ++j)
630
0
          pointTypes.push_back(readU8(input, m_bigEndian));
631
0
        break;
632
0
      default:
633
0
        break;
634
0
      }
635
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
636
0
    }
637
0
    while (tagId != CMX_Tag_EndTag);
638
0
  }
639
0
  else if (m_precision == libcdr::PRECISION_16BIT)
640
0
  {
641
0
    CDR_DEBUG_MSG(("  CMXParser::readPolyCurve\n"));
642
0
    if (!readRenderingAttributes(input))
643
0
      return;
644
0
    pointNum = readU16(input, m_bigEndian);
645
0
    const unsigned long maxPoints = getRemainingLength(input) / (2 * 2 + 1);
646
0
    if (pointNum > maxPoints)
647
0
      pointNum = maxPoints;
648
0
    for (unsigned long i = 0; i < pointNum; ++i)
649
0
    {
650
0
      std::pair<double, double> point;
651
0
      point.first = readCoordinate(input, m_bigEndian);
652
0
      point.second = readCoordinate(input, m_bigEndian);
653
0
      points.push_back(point);
654
0
    }
655
0
    for (unsigned long j = 0; j < pointNum; ++j)
656
0
      pointTypes.push_back(readU8(input, m_bigEndian));
657
0
  }
658
0
  else
659
0
    return;
660
661
0
  outputPath(points, pointTypes);
662
0
  m_collector->collectLevel(1);
663
0
}
664
665
void libcdr::CMXParser::readEllipse(librevenge::RVNGInputStream *input)
666
0
{
667
0
  m_collector->collectObject(1);
668
0
  double angle1 = 0.0;
669
0
  double angle2 = 0.0;
670
0
  double rotation = 0.0;
671
0
  bool pie = false;
672
673
0
  double cx = 0.0;
674
0
  double cy = 0.0;
675
0
  double rx = 0.0;
676
0
  double ry = 0.0;
677
678
0
  if (m_precision == libcdr::PRECISION_32BIT)
679
0
  {
680
0
    unsigned char tagId = 0;
681
0
    unsigned short tagLength = 0;
682
0
    do
683
0
    {
684
0
      long startOffset = input->tell();
685
0
      tagId = readU8(input, m_bigEndian);
686
0
      if (tagId == CMX_Tag_EndTag)
687
0
      {
688
0
        CDR_DEBUG_MSG(("  CMXParser::readEllipse - tagId %i\n", tagId));
689
0
        break;
690
0
      }
691
0
      tagLength = readTagLength(input, m_bigEndian);
692
0
      CDR_DEBUG_MSG(("  CMXParser::readEllipse - tagId %i, tagLength %u\n", tagId, tagLength));
693
0
      switch (tagId)
694
0
      {
695
0
      case CMX_Tag_Ellips_RenderingAttr:
696
0
        readRenderingAttributes(input);
697
0
        break;
698
0
      case CMX_Tag_Ellips_EllipsSpecification:
699
0
        cx = readCoordinate(input, m_bigEndian);
700
0
        cy = readCoordinate(input, m_bigEndian);
701
0
        rx = readCoordinate(input, m_bigEndian) / 2.0;
702
0
        ry = readCoordinate(input, m_bigEndian) / 2.0;
703
0
        angle1 = readAngle(input, m_bigEndian);
704
0
        angle2 = readAngle(input, m_bigEndian);
705
0
        rotation = readAngle(input, m_bigEndian);
706
0
        pie = (0 != readU8(input, m_bigEndian));
707
0
      default:
708
0
        break;
709
0
      }
710
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
711
0
    }
712
0
    while (tagId != CMX_Tag_EndTag);
713
0
  }
714
0
  else if (m_precision == libcdr::PRECISION_16BIT)
715
0
  {
716
0
    CDR_DEBUG_MSG(("  CMXParser::readEllipse\n"));
717
0
    if (!readRenderingAttributes(input))
718
0
      return;
719
0
    cx = readCoordinate(input, m_bigEndian);
720
0
    cy = readCoordinate(input, m_bigEndian);
721
0
    rx = readCoordinate(input, m_bigEndian) / 2.0;
722
0
    ry = readCoordinate(input, m_bigEndian) / 2.0;
723
0
    angle1 = readAngle(input, m_bigEndian);
724
0
    angle2 = readAngle(input, m_bigEndian);
725
0
    rotation = readAngle(input, m_bigEndian);
726
0
    pie = (0 != readU8(input, m_bigEndian));
727
0
  }
728
0
  else
729
0
    return;
730
731
0
  CDRPath path;
732
0
  if (!CDR_ALMOST_EQUAL(angle1,angle2))
733
0
  {
734
0
    if (angle2 < angle1)
735
0
      angle2 += 2*M_PI;
736
0
    double x0 = cx + rx*cos(angle1);
737
0
    double y0 = cy - ry*sin(angle1);
738
739
0
    double x1 = cx + rx*cos(angle2);
740
0
    double y1 = cy - ry*sin(angle2);
741
742
0
    bool largeArc = (angle2 - angle1 > M_PI || angle2 - angle1 < -M_PI);
743
744
0
    path.appendMoveTo(x0, y0);
745
0
    path.appendArcTo(rx, ry, 0.0, largeArc, true, x1, y1);
746
0
    if (pie)
747
0
    {
748
0
      path.appendLineTo(cx, cy);
749
0
      path.appendLineTo(x0, y0);
750
0
      path.appendClosePath();
751
0
    }
752
0
  }
753
0
  else
754
0
  {
755
0
    double x0 = cx + rx;
756
0
    double y0 = cy;
757
758
0
    double x1 = cx;
759
0
    double y1 = cy - ry;
760
761
0
    path.appendMoveTo(x0, y0);
762
0
    path.appendArcTo(rx, ry, 0.0, false, true, x1, y1);
763
0
    path.appendArcTo(rx, ry, 0.0, true, true, x0, y0);
764
0
  }
765
0
  m_collector->collectPath(path);
766
0
  m_collector->collectRotate(rotation, cx, cy);
767
0
  m_collector->collectLevel(1);
768
0
}
769
770
void libcdr::CMXParser::readDrawImage(librevenge::RVNGInputStream *input)
771
0
{
772
0
  m_collector->collectObject(1);
773
0
  CDRBox bBox;
774
0
  CDRTransforms trafos;
775
0
  unsigned short imageRef = 0;
776
0
  if (m_precision == libcdr::PRECISION_32BIT)
777
0
  {
778
0
    unsigned char tagId = 0;
779
0
    unsigned short tagLength = 0;
780
0
    do
781
0
    {
782
0
      long startOffset = input->tell();
783
0
      tagId = readU8(input, m_bigEndian);
784
0
      if (tagId == CMX_Tag_EndTag)
785
0
      {
786
0
        CDR_DEBUG_MSG(("  CMXParser::readDrawImage - tagId %i\n", tagId));
787
0
        break;
788
0
      }
789
0
      tagLength = readTagLength(input, m_bigEndian);
790
0
      CDR_DEBUG_MSG(("  CMXParser::readDrawImage - tagId %i, tagLength %u\n", tagId, tagLength));
791
0
      switch (tagId)
792
0
      {
793
0
      case CMX_Tag_DrawImage_RenderingAttr:
794
0
        readRenderingAttributes(input);
795
0
        break;
796
0
      case CMX_Tag_DrawImage_DrawImageSpecification:
797
0
      {
798
0
        bBox = readBBox(input);
799
0
        readBBox(input);
800
0
        trafos.append(readMatrix(input));
801
0
        /* unsigned short imageType = */ readU16(input, m_bigEndian);
802
0
        imageRef = readU16(input, m_bigEndian);
803
0
        break;
804
0
      }
805
0
      default:
806
0
        break;
807
0
      }
808
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
809
0
    }
810
0
    while (tagId != CMX_Tag_EndTag);
811
0
  }
812
0
  else if (m_precision == libcdr::PRECISION_16BIT)
813
0
  {
814
0
    CDR_DEBUG_MSG(("  CMXParser::readDrawImage\n"));
815
0
    if (!readRenderingAttributes(input))
816
0
      return;
817
0
    bBox = readBBox(input);
818
0
    readBBox(input);
819
0
    trafos.append(readMatrix(input));
820
0
    /* unsigned short imageType = */ readU16(input, m_bigEndian);
821
0
    imageRef = readU16(input, m_bigEndian);
822
0
  }
823
0
  else
824
0
    return;
825
826
0
  m_collector->collectTransform(trafos, false);
827
0
  m_collector->collectBitmap(imageRef, bBox.m_x, bBox.m_x + bBox.m_w, bBox.m_y, bBox.m_y + bBox.m_h);
828
0
  m_collector->collectLevel(1);
829
0
}
830
831
void libcdr::CMXParser::readRectangle(librevenge::RVNGInputStream *input)
832
0
{
833
0
  m_collector->collectObject(1);
834
0
  double cx = 0.0;
835
0
  double cy = 0.0;
836
0
  double width = 0.0;
837
0
  double height = 0.0;
838
0
  double radius = 0.0;
839
0
  double angle = 0.0;
840
0
  if (m_precision == libcdr::PRECISION_32BIT)
841
0
  {
842
0
    unsigned char tagId = 0;
843
0
    unsigned short tagLength = 0;
844
0
    do
845
0
    {
846
0
      long startOffset = input->tell();
847
0
      tagId = readU8(input, m_bigEndian);
848
0
      if (tagId == CMX_Tag_EndTag)
849
0
      {
850
0
        CDR_DEBUG_MSG(("  CMXParser::readRectangle - tagId %i\n", tagId));
851
0
        break;
852
0
      }
853
0
      tagLength = readTagLength(input, m_bigEndian);
854
0
      CDR_DEBUG_MSG(("  CMXParser::readRectangle - tagId %i, tagLength %u\n", tagId, tagLength));
855
0
      switch (tagId)
856
0
      {
857
0
      case CMX_Tag_Rectangle_RenderingAttr:
858
0
        readRenderingAttributes(input);
859
0
        break;
860
0
      case CMX_Tag_Rectangle_RectangleSpecification:
861
0
        cx = readCoordinate(input, m_bigEndian);
862
0
        cy = readCoordinate(input, m_bigEndian);
863
0
        width = readCoordinate(input, m_bigEndian);
864
0
        height = readCoordinate(input, m_bigEndian);
865
0
        radius = readCoordinate(input, m_bigEndian);
866
0
        angle = readAngle(input, m_bigEndian);
867
0
        break;
868
0
      default:
869
0
        break;
870
0
      }
871
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
872
0
    }
873
0
    while (tagId != CMX_Tag_EndTag);
874
0
  }
875
0
  else if (m_precision == libcdr::PRECISION_16BIT)
876
0
  {
877
0
    CDR_DEBUG_MSG(("  CMXParser::readRectangle\n"));
878
0
    if (!readRenderingAttributes(input))
879
0
      return;
880
0
    cx = readCoordinate(input, m_bigEndian);
881
0
    cy = readCoordinate(input, m_bigEndian);
882
0
    width = readCoordinate(input, m_bigEndian);
883
0
    height = readCoordinate(input, m_bigEndian);
884
0
    radius = readCoordinate(input, m_bigEndian);
885
0
    angle = readAngle(input, m_bigEndian);
886
0
  }
887
0
  else
888
0
    return;
889
890
0
  double x0 = cx - width / 2.0;
891
0
  double y0 = cy - height / 2.0;
892
0
  double x1 = cx + width / 2.0;
893
0
  double y1 = cy + height / 2.0;
894
0
  CDRPath path;
895
0
  if (radius > 0.0)
896
0
  {
897
0
    path.appendMoveTo(x0, y0-radius);
898
0
    path.appendLineTo(x0, y1+radius);
899
0
    path.appendQuadraticBezierTo(x0, y1, x0+radius, y1);
900
0
    path.appendLineTo(x1-radius, y1);
901
0
    path.appendQuadraticBezierTo(x1, y1, x1, y1+radius);
902
0
    path.appendLineTo(x1, y0-radius);
903
0
    path.appendQuadraticBezierTo(x1, y0, x1-radius, y0);
904
0
    path.appendLineTo(x0+radius, y0);
905
0
    path.appendQuadraticBezierTo(x0, y0, x0, y0-radius);
906
0
  }
907
0
  else
908
0
  {
909
0
    path.appendMoveTo(x0, y0);
910
0
    path.appendLineTo(x0, y1);
911
0
    path.appendLineTo(x1, y1);
912
0
    path.appendLineTo(x1, y0);
913
0
    path.appendLineTo(x0, y0);
914
0
  }
915
0
  m_collector->collectPath(path);
916
0
  m_collector->collectRotate(angle, cx, cy);
917
0
  m_collector->collectLevel(1);
918
0
}
919
920
void libcdr::CMXParser::readBeginProcedure(librevenge::RVNGInputStream *input)
921
0
{
922
0
  if (m_precision == libcdr::PRECISION_32BIT)
923
0
  {
924
0
    unsigned char tagId = 0;
925
0
    unsigned short tagLength = 0;
926
0
    do
927
0
    {
928
0
      long startOffset = input->tell();
929
0
      tagId = readU8(input, m_bigEndian);
930
0
      if (tagId == CMX_Tag_EndTag)
931
0
      {
932
0
        CDR_DEBUG_MSG(("  CMXParser::readBeginProcedure - tagId %i\n", tagId));
933
0
        break;
934
0
      }
935
0
      tagLength = readTagLength(input, m_bigEndian);
936
0
      CDR_DEBUG_MSG(("  CMXParser::readBeginProcedure - tagId %i, tagLength %u\n", tagId, tagLength));
937
0
      switch (tagId)
938
0
      {
939
0
      case CMX_Tag_BeginProcedure_ProcedureSpecification:
940
        /* unsigned flags = */
941
0
        readU32(input, m_bigEndian);
942
0
        /* CDRBox bBox = */ readBBox(input);
943
0
        /* unsigned endOffset = */ readU32(input, m_bigEndian);
944
0
        /* unsigned short groupCount = */ readU16(input, m_bigEndian);
945
0
        /* unsigned tally = */ readU32(input, m_bigEndian);
946
0
        break;
947
0
      default:
948
0
        break;
949
0
      }
950
0
      input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
951
0
    }
952
0
    while (tagId != CMX_Tag_EndTag);
953
0
  }
954
0
  else if (m_precision == libcdr::PRECISION_16BIT)
955
0
  {
956
0
    CDR_DEBUG_MSG(("  CMXParser::readBeginProcedure\n"));
957
0
    /* unsigned flags = */ readU32(input, m_bigEndian);
958
0
    /* CDRBox bBox = */ readBBox(input);
959
0
    /* unsigned endOffset = */ readU32(input, m_bigEndian);
960
0
    /* unsigned short groupCount = */ readU16(input, m_bigEndian);
961
0
    /* unsigned tally = */ readU32(input, m_bigEndian);
962
0
  }
963
0
  else
964
0
    return;
965
0
}
966
967
libcdr::CDRTransform libcdr::CMXParser::readMatrix(librevenge::RVNGInputStream *input)
968
0
{
969
0
  CDRTransform matrix;
970
0
  unsigned short type = readU16(input, m_bigEndian);
971
0
  if (type > 1)
972
0
  {
973
0
    double v0 = readDouble(input, m_bigEndian);
974
0
    double v3 = readDouble(input, m_bigEndian);
975
0
    double v1 = readDouble(input, m_bigEndian);
976
0
    double v4 = readDouble(input, m_bigEndian);
977
0
    double x0 = readDouble(input, m_bigEndian) ;
978
0
    double y0 = readDouble(input, m_bigEndian);
979
0
    if (m_precision == PRECISION_32BIT)
980
0
    {
981
0
      x0 /= 254000.0;
982
0
      y0 /= 254000.0;
983
0
    }
984
0
    else if (m_precision == PRECISION_16BIT)
985
0
    {
986
0
      x0 /= 1000.0;
987
0
      y0 /= 1000.0;
988
0
    }
989
0
    else
990
0
      return CDRTransform();
991
0
    return libcdr::CDRTransform(v0, v1, x0, v3, v4, y0);
992
0
  }
993
0
  else
994
0
    return matrix;
995
0
}
996
997
libcdr::CDRBox libcdr::CMXParser::readBBox(librevenge::RVNGInputStream *input)
998
0
{
999
0
  double x0 = readCoordinate(input, m_bigEndian);
1000
0
  double y0 = readCoordinate(input, m_bigEndian);
1001
0
  double x1 = readCoordinate(input, m_bigEndian);
1002
0
  double y1 = readCoordinate(input, m_bigEndian);
1003
0
  CDRBox box(x0, y0, x1, y1);
1004
0
  return box;
1005
0
}
1006
1007
librevenge::RVNGString libcdr::CMXParser::readString(librevenge::RVNGInputStream *input)
1008
0
{
1009
0
  unsigned long count = readU16(input, m_bigEndian);
1010
0
  if (count > getRemainingLength(input))
1011
0
    count = getRemainingLength(input);
1012
0
  librevenge::RVNGString tmpString;
1013
0
  for (unsigned long i = 0; i < count; ++i)
1014
0
    tmpString.append((char)readU8(input, m_bigEndian));
1015
0
  return tmpString;
1016
0
}
1017
1018
bool libcdr::CMXParser::readLens(librevenge::RVNGInputStream *input)
1019
0
{
1020
0
  unsigned char lensType = readU8(input, m_bigEndian);
1021
0
  switch (lensType)
1022
0
  {
1023
0
  case 1: // Glass
1024
0
  {
1025
0
    unsigned char tintMethod = readU8(input, m_bigEndian);
1026
0
    unsigned short uniformRate = readU16(input, m_bigEndian);
1027
0
    /* unsigned short colorRef = */ readU16(input, m_bigEndian);
1028
0
    /* unsigned short rangeProcRef = */ readU16(input, m_bigEndian);
1029
0
    if (tintMethod == 0)
1030
0
      m_collector->collectFillOpacity((double)uniformRate / 1000.0);
1031
0
    break;
1032
0
  }
1033
0
  case 2: // Magnifying
1034
0
  {
1035
0
    /* unsigned short uniformRate = */ readU16(input, m_bigEndian);
1036
0
    /* unsigned short rangeProcRef = */ readU16(input, m_bigEndian);
1037
0
    break;
1038
0
  }
1039
0
  case 3: // Fisheye
1040
0
  {
1041
0
    /* unsigned short uniformRate = */ readU16(input, m_bigEndian);
1042
0
    /* unsigned short rangeProcRef = */ readU16(input, m_bigEndian);
1043
0
    break;
1044
0
  }
1045
0
  case 4: // Wireframe
1046
0
  {
1047
0
    /* unsigned char outlineMethod = */ readU8(input, m_bigEndian);
1048
0
    /* unsigned short outlineColorRef = */ readU16(input, m_bigEndian);
1049
0
    /* unsigned char fillMethod = */ readU8(input, m_bigEndian);
1050
0
    /* unsigned short fillColorRef = */ readU16(input, m_bigEndian);
1051
0
    /* unsigned short rangeProcRef = */ readU16(input, m_bigEndian);
1052
0
    break;
1053
0
  }
1054
0
  default:
1055
0
    if (m_precision == libcdr::PRECISION_16BIT)
1056
0
      return false;
1057
0
    break;
1058
0
  }
1059
0
  return true;
1060
0
}
1061
1062
bool libcdr::CMXParser::readFill(librevenge::RVNGInputStream *input)
1063
0
{
1064
0
  libcdr::CDRColor color1;
1065
0
  libcdr::CDRColor color2;
1066
0
  libcdr::CDRImageFill imageFill;
1067
0
  libcdr::CDRGradient gradient;
1068
0
  auto fillId = (unsigned)input->tell();
1069
0
  unsigned fillType = readU16(input, m_bigEndian);
1070
0
  switch (fillType)
1071
0
  {
1072
0
  case 1: // Uniform
1073
0
    if (m_precision == libcdr::PRECISION_32BIT)
1074
0
    {
1075
0
      unsigned char tagId = 0;
1076
0
      unsigned short tagLength = 0;
1077
0
      do
1078
0
      {
1079
0
        long startOffset = input->tell();
1080
0
        tagId = readU8(input, m_bigEndian);
1081
0
        if (tagId == CMX_Tag_EndTag)
1082
0
        {
1083
0
          CDR_DEBUG_MSG(("    Solid fill - tagId %i\n", tagId));
1084
0
          break;
1085
0
        }
1086
0
        tagLength = readTagLength(input, m_bigEndian);
1087
0
        CDR_DEBUG_MSG(("    Solid fill - tagId %i, tagLength %u\n", tagId, tagLength));
1088
0
        switch (tagId)
1089
0
        {
1090
0
        case CMX_Tag_RenderAttr_FillSpec_Uniform:
1091
0
        {
1092
0
          unsigned colorRef = readU16(input, m_bigEndian);
1093
0
          color1 = getPaletteColor(colorRef);
1094
0
          readU16(input, m_bigEndian);
1095
0
          break;
1096
0
        }
1097
0
        default:
1098
0
          break;
1099
0
        }
1100
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1101
0
      }
1102
0
      while (tagId != CMX_Tag_EndTag);
1103
0
    }
1104
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1105
0
    {
1106
0
      CDR_DEBUG_MSG(("    Solid fill\n"));
1107
0
      unsigned colorRef = readU16(input, m_bigEndian);
1108
0
      color1 = getPaletteColor(colorRef);
1109
0
      readU16(input, m_bigEndian);
1110
0
    }
1111
0
    break;
1112
0
  case 2:  // Fountain
1113
0
    if (m_precision == libcdr::PRECISION_32BIT)
1114
0
    {
1115
0
      unsigned char tagId = 0;
1116
0
      unsigned short tagLength = 0;
1117
0
      do
1118
0
      {
1119
0
        long startOffset = input->tell();
1120
0
        tagId = readU8(input, m_bigEndian);
1121
0
        if (tagId == CMX_Tag_EndTag)
1122
0
        {
1123
0
          CDR_DEBUG_MSG(("    Fountain fill - tagId %i\n", tagId));
1124
0
          break;
1125
0
        }
1126
0
        tagLength = readTagLength(input, m_bigEndian);
1127
0
        CDR_DEBUG_MSG(("    Fountain fill - tagId %i, tagLength %u\n", tagId, tagLength));
1128
0
        switch (tagId)
1129
0
        {
1130
0
        case CMX_Tag_RenderAttr_FillSpec_Fountain_Base:
1131
0
        {
1132
0
          gradient.m_type = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1133
0
          /* unsigned short screen = */ readU16(input, m_bigEndian);
1134
0
          gradient.m_edgeOffset = readU16(input, m_bigEndian);
1135
0
          gradient.m_angle = readAngle(input, m_bigEndian);
1136
0
          gradient.m_centerXOffset = readS32(input, m_bigEndian);
1137
0
          gradient.m_centerYOffset = readS32(input, m_bigEndian);
1138
0
          /* unsigned short steps = */ readU16(input, m_bigEndian);
1139
0
          gradient.m_mode = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1140
0
          /* unsigned short rateMethod = */ readU16(input, m_bigEndian);
1141
0
          /* unsigned short rateValue = */ readU16(input, m_bigEndian);
1142
0
          break;
1143
0
        }
1144
0
        case CMX_Tag_RenderAttr_FillSpec_Fountain_Color:
1145
0
        {
1146
0
          unsigned long colorCount = readU16(input, m_bigEndian);
1147
0
          if (colorCount > getRemainingLength(input) / 4)
1148
0
            colorCount = getRemainingLength(input) / 4;
1149
0
          for (unsigned long i = 0; i < colorCount; ++i)
1150
0
          {
1151
0
            unsigned short colorRef = readU16(input, m_bigEndian);
1152
0
            unsigned short offset = readU16(input, m_bigEndian);
1153
0
            libcdr::CDRGradientStop stop;
1154
0
            stop.m_color = getPaletteColor(colorRef);
1155
0
            stop.m_offset = (double)offset / 100.0;
1156
0
            gradient.m_stops.push_back(stop);
1157
0
          }
1158
0
          break;
1159
0
        }
1160
0
        default:
1161
0
          break;
1162
0
        }
1163
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1164
0
      }
1165
0
      while (tagId != CMX_Tag_EndTag);
1166
0
    }
1167
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1168
0
    {
1169
0
      CDR_DEBUG_MSG(("    Fountain fill\n"));
1170
0
      gradient.m_type = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1171
0
      /* unsigned short screen = */ readU16(input, m_bigEndian);
1172
0
      gradient.m_edgeOffset = readU16(input, m_bigEndian);
1173
0
      gradient.m_angle = readAngle(input, m_bigEndian);
1174
0
      input->seek(2, librevenge::RVNG_SEEK_CUR);
1175
0
      gradient.m_centerXOffset = readS16(input, m_bigEndian);
1176
0
      gradient.m_centerYOffset = readS16(input, m_bigEndian);
1177
0
      /* unsigned short steps = */ readU16(input, m_bigEndian);
1178
0
      gradient.m_mode = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1179
0
      unsigned long colorCount = readU16(input, m_bigEndian);
1180
0
      if (colorCount > getRemainingLength(input) / 4)
1181
0
        colorCount = getRemainingLength(input) / 4;
1182
0
      for (unsigned long i = 0; i < colorCount; ++i)
1183
0
      {
1184
0
        unsigned short colorRef = readU16(input, m_bigEndian);
1185
0
        unsigned short offset = readU16(input, m_bigEndian);
1186
0
        libcdr::CDRGradientStop stop;
1187
0
        stop.m_color = getPaletteColor(colorRef);
1188
0
        stop.m_offset = (double)offset / 100.0;
1189
0
        gradient.m_stops.push_back(stop);
1190
0
      }
1191
0
    }
1192
0
    break;
1193
0
  case 6: // Postscript
1194
0
    CDR_DEBUG_MSG(("    Postscript fill\n"));
1195
0
    if (m_precision == libcdr::PRECISION_32BIT)
1196
0
    {
1197
0
    }
1198
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1199
0
    {
1200
0
      /* unsigned atom = */ readU32(input, m_bigEndian);
1201
0
      unsigned long count = readU16(input, m_bigEndian);
1202
0
      if (count > getRemainingLength(input) / 2)
1203
0
        count = getRemainingLength(input) / 2;
1204
0
      for (unsigned long i = 0; i < count; ++i)
1205
0
        readU16(input, m_bigEndian);
1206
0
      readString(input);
1207
0
    }
1208
0
    break;
1209
0
  case 7: // Two-Color Pattern
1210
0
  case 8: // Monochrome with transparent bitmap
1211
0
    if (m_precision == libcdr::PRECISION_32BIT)
1212
0
    {
1213
0
      unsigned char tagId = 0;
1214
0
      unsigned short tagLength = 0;
1215
0
      do
1216
0
      {
1217
0
        long startOffset = input->tell();
1218
0
        tagId = readU8(input, m_bigEndian);
1219
0
        if (tagId == CMX_Tag_EndTag)
1220
0
        {
1221
0
          CDR_DEBUG_MSG(("    %s fill - tagId %i\n", fillType == 7 ? "Two-Color Pattern" : "Monochrome with transparent bitmap", tagId));
1222
0
          break;
1223
0
        }
1224
0
        tagLength = readTagLength(input, m_bigEndian);
1225
0
        CDR_DEBUG_MSG(("    %s fill - tagId %i, tagLength %u\n", fillType == 7 ? "Two-Color Pattern" : "Monochrome with transparent bitmap", tagId, tagLength));
1226
0
        switch (tagId)
1227
0
        {
1228
0
        case CMX_Tag_RenderAttr_FillSpec_MonoBM:
1229
0
        {
1230
0
          unsigned short patternId = readU16(input, m_bigEndian);
1231
0
          input->seek(3, librevenge::RVNG_SEEK_CUR); // CMX_Tag_Tiling
1232
0
          int tmpWidth = readS32(input, m_bigEndian);
1233
0
          int tmpHeight = readS32(input, m_bigEndian);
1234
0
          double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1235
0
          double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1236
0
          double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1237
0
          unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1238
0
          input->seek(1, librevenge::RVNG_SEEK_CUR); // CMX_Tag_EndTag
1239
0
          double patternWidth = (double)tmpWidth / 254000.0;
1240
0
          double patternHeight = (double)tmpHeight / 254000.0;
1241
0
          bool isRelative = false;
1242
0
          if (flags & 0x04)
1243
0
          {
1244
0
            isRelative = true;
1245
0
            patternWidth = (double)tmpWidth / 100.0;
1246
0
            patternHeight = (double)tmpHeight / 100.0;
1247
0
          }
1248
0
          color1 = getPaletteColor(readU16(input, m_bigEndian));
1249
0
          color2 = getPaletteColor(readU16(input, m_bigEndian));
1250
0
          /* unsigned short screen = */ readU16(input, m_bigEndian);
1251
0
          imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1252
0
          break;
1253
0
        }
1254
0
        default:
1255
0
          break;
1256
0
        }
1257
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1258
0
      }
1259
0
      while (tagId != CMX_Tag_EndTag);
1260
0
    }
1261
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1262
0
    {
1263
0
      CDR_DEBUG_MSG(("    %s fill\n", fillType == 7 ? "Two-Color Pattern" : "Monochrome with transparent bitmap"));
1264
0
      unsigned short patternId = readU16(input, m_bigEndian);
1265
0
      int tmpWidth = readU16(input, m_bigEndian);
1266
0
      int tmpHeight = readU16(input, m_bigEndian);
1267
0
      double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1268
0
      double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1269
0
      double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1270
0
      unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1271
0
      double patternWidth = (double)tmpWidth / 1000.0;
1272
0
      double patternHeight = (double)tmpHeight / 1000.0;
1273
0
      bool isRelative = false;
1274
0
      if (flags & 0x04)
1275
0
      {
1276
0
        isRelative = true;
1277
0
        patternWidth = (double)tmpWidth / 100.0;
1278
0
        patternHeight = (double)tmpHeight / 100.0;
1279
0
      }
1280
0
      color1 = getPaletteColor(readU16(input, m_bigEndian));
1281
0
      color2 = getPaletteColor(readU16(input, m_bigEndian));
1282
0
      /* unsigned short screen = */ readU16(input, m_bigEndian);
1283
0
      imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1284
0
    }
1285
0
    break;
1286
0
  case 9: // Imported Bitmap
1287
0
  case 10: // Full Color Pattern
1288
0
    if (m_precision == libcdr::PRECISION_32BIT)
1289
0
    {
1290
0
      unsigned char tagId = 0;
1291
0
      unsigned short tagLength = 0;
1292
0
      do
1293
0
      {
1294
0
        long startOffset = input->tell();
1295
0
        tagId = readU8(input, m_bigEndian);
1296
0
        if (tagId == CMX_Tag_EndTag)
1297
0
        {
1298
0
          CDR_DEBUG_MSG(("    %s fill - tagId %i\n", fillType == 9 ? "Imported Bitmap" : "Full Color Pattern", tagId));
1299
0
          break;
1300
0
        }
1301
0
        tagLength = readTagLength(input, m_bigEndian);
1302
0
        CDR_DEBUG_MSG(("    %s fill - tagId %i, tagLength %u\n", fillType == 9 ? "Imported Bitmap" : "Full Color Pattern", tagId, tagLength));
1303
0
        switch (tagId)
1304
0
        {
1305
0
        case CMX_Tag_RenderAttr_FillSpec_ColorBM:
1306
0
        {
1307
0
          unsigned short patternId = readU16(input, m_bigEndian);
1308
0
          input->seek(3, librevenge::RVNG_SEEK_CUR); // CMX_Tag_Tiling
1309
0
          int tmpWidth = readS32(input, m_bigEndian);
1310
0
          int tmpHeight = readS32(input, m_bigEndian);
1311
0
          double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1312
0
          double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1313
0
          double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1314
0
          unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1315
0
          input->seek(1, librevenge::RVNG_SEEK_CUR); // CMX_Tag_EndTag
1316
0
          double patternWidth = (double)tmpWidth / 254000.0;
1317
0
          double patternHeight = (double)tmpHeight / 254000.0;
1318
0
          bool isRelative = false;
1319
0
          if (flags & 0x04)
1320
0
          {
1321
0
            isRelative = true;
1322
0
            patternWidth = (double)tmpWidth / 100.0;
1323
0
            patternHeight = (double)tmpHeight / 100.0;
1324
0
          }
1325
0
          /* libcdr::CDRBox box = */ readBBox(input);
1326
0
          imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1327
0
          break;
1328
0
        }
1329
0
        default:
1330
0
          break;
1331
0
        }
1332
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1333
0
      }
1334
0
      while (tagId != CMX_Tag_EndTag);
1335
0
    }
1336
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1337
0
    {
1338
0
      CDR_DEBUG_MSG(("    %s fill\n", fillType == 9 ? "Imported Bitmap" : "Full Color Pattern"));
1339
0
      unsigned short patternId = readU16(input, m_bigEndian);
1340
0
      int tmpWidth = readU16(input, m_bigEndian);
1341
0
      int tmpHeight = readU16(input, m_bigEndian);
1342
0
      double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1343
0
      double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1344
0
      double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1345
0
      unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1346
0
      double patternWidth = (double)tmpWidth / 1000.0;
1347
0
      double patternHeight = (double)tmpHeight / 1000.0;
1348
0
      bool isRelative = false;
1349
0
      if (flags & 0x04)
1350
0
      {
1351
0
        isRelative = true;
1352
0
        patternWidth = (double)tmpWidth / 100.0;
1353
0
        patternHeight = (double)tmpHeight / 100.0;
1354
0
      }
1355
0
      /* libcdr::CDRBox box = */ readBBox(input);
1356
0
      imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1357
0
    }
1358
0
    break;
1359
0
  case 11:
1360
0
    if (m_precision == libcdr::PRECISION_32BIT)
1361
0
    {
1362
0
      unsigned char tagId = 0;
1363
0
      unsigned short tagLength = 0;
1364
0
      do
1365
0
      {
1366
0
        long startOffset = input->tell();
1367
0
        tagId = readU8(input, m_bigEndian);
1368
0
        if (tagId == CMX_Tag_EndTag)
1369
0
        {
1370
0
          CDR_DEBUG_MSG(("    Texture fill - tagId %i\n", tagId));
1371
0
          break;
1372
0
        }
1373
0
        tagLength = readTagLength(input, m_bigEndian);
1374
0
        CDR_DEBUG_MSG(("    Texture fill - tagId %i, tagLength %u\n", tagId, tagLength));
1375
0
        switch (tagId)
1376
0
        {
1377
0
        case CMX_Tag_RenderAttr_FillSpec_Texture:
1378
0
        {
1379
0
          unsigned char subTagId = 0;
1380
0
          unsigned short subTagLength = 0;
1381
0
          do
1382
0
          {
1383
0
            long subStartOffset = input->tell();
1384
0
            subTagId = readU8(input, m_bigEndian);
1385
0
            if (subTagId == CMX_Tag_EndTag)
1386
0
              break;
1387
0
            subTagLength = readTagLength(input, m_bigEndian);
1388
0
            switch (subTagId)
1389
0
            {
1390
0
            case CMX_Tag_RenderAttr_FillSpec_ColorBM:
1391
0
            {
1392
0
              unsigned short patternId = readU16(input, m_bigEndian);
1393
0
              input->seek(3, librevenge::RVNG_SEEK_CUR); // CMX_Tag_Tiling
1394
0
              int tmpWidth = readS32(input, m_bigEndian);
1395
0
              int tmpHeight = readS32(input, m_bigEndian);
1396
0
              double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1397
0
              double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1398
0
              double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1399
0
              unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1400
0
              input->seek(1, librevenge::RVNG_SEEK_CUR); // CMX_Tag_EndTag
1401
0
              double patternWidth = (double)tmpWidth / 254000.0;
1402
0
              double patternHeight = (double)tmpHeight / 254000.0;
1403
0
              bool isRelative = false;
1404
0
              if (flags & 0x04)
1405
0
              {
1406
0
                isRelative = true;
1407
0
                patternWidth = (double)tmpWidth / 100.0;
1408
0
                patternHeight = (double)tmpHeight / 100.0;
1409
0
              }
1410
0
              /* libcdr::CDRBox box = */ readBBox(input);
1411
0
              imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1412
0
              break;
1413
0
            }
1414
0
            default:
1415
0
              break;
1416
0
            }
1417
0
            input->seek(subStartOffset + subTagLength, librevenge::RVNG_SEEK_SET);
1418
0
          }
1419
0
          while (subTagId != CMX_Tag_EndTag);
1420
0
        }
1421
0
        default:
1422
0
          break;
1423
0
        }
1424
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1425
0
      }
1426
0
      while (tagId != CMX_Tag_EndTag);
1427
0
    }
1428
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1429
0
    {
1430
0
      CDR_DEBUG_MSG(("    Texture fill\n"));
1431
0
      unsigned short patternId = readU16(input, m_bigEndian);
1432
0
      int tmpWidth = readU16(input, m_bigEndian);
1433
0
      int tmpHeight = readU16(input, m_bigEndian);
1434
0
      double tileOffsetX = (double)readU16(input, m_bigEndian) / 100.0;
1435
0
      double tileOffsetY = (double)readU16(input, m_bigEndian) / 100.0;
1436
0
      double rcpOffset = (double)readU16(input, m_bigEndian) / 100.0;
1437
0
      unsigned char flags = (unsigned char)(readU16(input, m_bigEndian) & 0xff);
1438
0
      double patternWidth = (double)tmpWidth / 1000.0;
1439
0
      double patternHeight = (double)tmpHeight / 1000.0;
1440
0
      bool isRelative = false;
1441
0
      if (flags & 0x04)
1442
0
      {
1443
0
        isRelative = true;
1444
0
        patternWidth = (double)tmpWidth / 100.0;
1445
0
        patternHeight = (double)tmpHeight / 100.0;
1446
0
      }
1447
0
      /* libcdr::CDRBox box = */ readBBox(input);
1448
0
      /* unsigned char reserved = */ readU8(input, m_bigEndian);
1449
0
      /* unsigned res = */ readU32(input, m_bigEndian);
1450
0
      /* unsigned short maxEdge = */ readU16(input, m_bigEndian);
1451
0
      /* librevenge::RVNGString lib = */ readString(input);
1452
0
      /* librevenge::RVNGString name = */ readString(input);
1453
0
      /* librevenge::RVNGString stl = */ readString(input);
1454
0
      unsigned long count = readU16(input, m_bigEndian);
1455
0
      if (count > getRemainingLength(input) / 8)
1456
0
        count = getRemainingLength(input) / 8;
1457
0
      for (unsigned long i = 0; i < count; ++i)
1458
0
      {
1459
0
        readU16(input, m_bigEndian);
1460
0
        readU16(input, m_bigEndian);
1461
0
        readU16(input, m_bigEndian);
1462
0
        readU16(input, m_bigEndian);
1463
0
      }
1464
0
      imageFill = libcdr::CDRImageFill(patternId, patternWidth, patternHeight, isRelative, tileOffsetX, tileOffsetY, rcpOffset, flags);
1465
0
    }
1466
0
    break;
1467
0
  default:
1468
0
    if (m_precision == libcdr::PRECISION_16BIT)
1469
0
      return false;
1470
0
    break;
1471
0
  }
1472
0
  m_collector->collectFillStyle(fillId, CDRFillStyle((unsigned short)fillType, color1, color2, gradient, imageFill));
1473
0
  m_collector->collectFillStyleId(fillId);
1474
0
  return true;
1475
0
}
1476
1477
bool libcdr::CMXParser::readRenderingAttributes(librevenge::RVNGInputStream *input)
1478
0
{
1479
0
  unsigned char tagId = 0;
1480
0
  unsigned short tagLength = 0;
1481
0
  unsigned char bitMask = readU8(input, m_bigEndian);
1482
0
  if (bitMask & 0x01) // fill
1483
0
  {
1484
0
    if (m_precision == libcdr::PRECISION_32BIT)
1485
0
    {
1486
0
      do
1487
0
      {
1488
0
        long startOffset = input->tell();
1489
0
        tagId = readU8(input, m_bigEndian);
1490
0
        if (tagId == CMX_Tag_EndTag)
1491
0
        {
1492
0
          CDR_DEBUG_MSG(("  Fill specification - tagId %i\n", tagId));
1493
0
          break;
1494
0
        }
1495
0
        tagLength = readTagLength(input, m_bigEndian);
1496
0
        CDR_DEBUG_MSG(("  Fill specification - tagId %i, tagLength %u\n", tagId, tagLength));
1497
0
        switch (tagId)
1498
0
        {
1499
0
        case CMX_Tag_RenderAttr_FillSpec:
1500
0
          readFill(input);
1501
0
          break;
1502
0
        default:
1503
0
          break;
1504
0
        }
1505
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1506
0
      }
1507
0
      while (tagId != CMX_Tag_EndTag);
1508
0
    }
1509
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1510
0
    {
1511
0
      CDR_DEBUG_MSG(("  Fill specification\n"));
1512
0
      if (!readFill(input))
1513
0
        return false;
1514
0
    }
1515
0
  }
1516
0
  if (bitMask & 0x02) // outline
1517
0
  {
1518
0
    CDRLineStyle lineStyle;
1519
0
    auto lineStyleId = (unsigned)input->tell();
1520
0
    if (m_precision == libcdr::PRECISION_32BIT)
1521
0
    {
1522
0
      do
1523
0
      {
1524
0
        long startOffset = input->tell();
1525
0
        tagId = readU8(input, m_bigEndian);
1526
0
        if (tagId == CMX_Tag_EndTag)
1527
0
        {
1528
0
          CDR_DEBUG_MSG(("  Outline specification - tagId %i\n", tagId));
1529
0
          break;
1530
0
        }
1531
0
        tagLength = readTagLength(input, m_bigEndian);
1532
0
        CDR_DEBUG_MSG(("  Outline specification - tagId %i, tagLength %u\n", tagId, tagLength));
1533
0
        switch (tagId)
1534
0
        {
1535
0
        case CMX_Tag_RenderAttr_OutlineSpec:
1536
0
          lineStyle = getLineStyle(readU16(input, m_bigEndian));
1537
0
          break;
1538
0
        default:
1539
0
          break;
1540
0
        }
1541
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1542
0
      }
1543
0
      while (tagId != CMX_Tag_EndTag);
1544
0
    }
1545
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1546
0
    {
1547
0
      CDR_DEBUG_MSG(("  Outline specification\n"));
1548
0
      lineStyle = getLineStyle(readU16(input, m_bigEndian));
1549
0
    }
1550
0
    m_collector->collectLineStyle(lineStyleId, lineStyle);
1551
0
    m_collector->collectLineStyleId(lineStyleId);
1552
0
  }
1553
0
  if (bitMask & 0x04) // lens
1554
0
  {
1555
0
    if (m_precision == libcdr::PRECISION_32BIT)
1556
0
    {
1557
0
      do
1558
0
      {
1559
0
        long startOffset = input->tell();
1560
0
        tagId = readU8(input, m_bigEndian);
1561
0
        if (tagId == CMX_Tag_EndTag)
1562
0
        {
1563
0
          CDR_DEBUG_MSG(("  Lens specification - tagId %i\n", tagId));
1564
0
          break;
1565
0
        }
1566
0
        tagLength = readTagLength(input, m_bigEndian);
1567
0
        CDR_DEBUG_MSG(("  Lens specification - tagId %i, tagLength %u\n", tagId, tagLength));
1568
0
        switch (tagId)
1569
0
        {
1570
0
        case CMX_Tag_RenderAttr_LensSpec_Base:
1571
0
          readLens(input);
1572
0
          break;
1573
0
        default:
1574
0
          break;
1575
0
        }
1576
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1577
0
      }
1578
0
      while (tagId != CMX_Tag_EndTag);
1579
0
    }
1580
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1581
0
    {
1582
0
      CDR_DEBUG_MSG(("  Lens specification\n"));
1583
0
      if (!readLens(input))
1584
0
        return false;
1585
0
    }
1586
0
  }
1587
0
  if (bitMask & 0x08) // canvas
1588
0
  {
1589
0
    if (m_precision == libcdr::PRECISION_32BIT)
1590
0
    {
1591
0
      do
1592
0
      {
1593
0
        long startOffset = input->tell();
1594
0
        tagId = readU8(input, m_bigEndian);
1595
0
        if (tagId == CMX_Tag_EndTag)
1596
0
        {
1597
0
          CDR_DEBUG_MSG(("  Canvas specification - tagId %i\n", tagId));
1598
0
          break;
1599
0
        }
1600
0
        tagLength = readTagLength(input, m_bigEndian);
1601
0
        CDR_DEBUG_MSG(("  Canvas specification - tagId %i, tagLength %u\n", tagId, tagLength));
1602
0
        switch (tagId)
1603
0
        {
1604
0
        default:
1605
0
          break;
1606
0
        }
1607
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1608
0
      }
1609
0
      while (tagId != CMX_Tag_EndTag);
1610
0
    }
1611
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1612
0
    {
1613
0
      CDR_DEBUG_MSG(("  Canvas specification\n"));
1614
0
      return false;
1615
0
    }
1616
0
  }
1617
0
  if (bitMask & 0x10) // container
1618
0
  {
1619
0
    if (m_precision == libcdr::PRECISION_32BIT)
1620
0
    {
1621
0
      do
1622
0
      {
1623
0
        long startOffset = input->tell();
1624
0
        tagId = readU8(input, m_bigEndian);
1625
0
        if (tagId == CMX_Tag_EndTag)
1626
0
        {
1627
0
          CDR_DEBUG_MSG(("  Container specification - tagId %i\n", tagId));
1628
0
          break;
1629
0
        }
1630
0
        tagLength = readTagLength(input, m_bigEndian);
1631
0
        CDR_DEBUG_MSG(("  Container specification - tagId %i, tagLength %u\n", tagId, tagLength));
1632
0
        switch (tagId)
1633
0
        {
1634
0
        default:
1635
0
          break;
1636
0
        }
1637
0
        input->seek(startOffset + tagLength, librevenge::RVNG_SEEK_SET);
1638
0
      }
1639
0
      while (tagId != CMX_Tag_EndTag);
1640
0
    }
1641
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1642
0
    {
1643
0
      CDR_DEBUG_MSG(("  Container specification\n"));
1644
0
      return false;
1645
0
    }
1646
0
  }
1647
0
  return true;
1648
0
}
1649
1650
void libcdr::CMXParser::readJumpAbsolute(librevenge::RVNGInputStream *input)
1651
0
{
1652
0
  if (m_precision == libcdr::PRECISION_32BIT)
1653
0
  {
1654
0
    unsigned char tagId = 0;
1655
0
    unsigned short tagLength = 0;
1656
0
    do
1657
0
    {
1658
0
      long offset = input->tell();
1659
0
      tagId = readU8(input, m_bigEndian);
1660
0
      if (tagId == CMX_Tag_EndTag)
1661
0
      {
1662
0
        CDR_DEBUG_MSG(("  CMXParser::readJumpAbsolute - tagId %i\n", tagId));
1663
0
        break;
1664
0
      }
1665
0
      tagLength = readTagLength(input, m_bigEndian);
1666
0
      CDR_DEBUG_MSG(("  CMXParser::readJumpAbsolute - tagId %i, tagLength %u\n", tagId, tagLength));
1667
0
      switch (tagId)
1668
0
      {
1669
0
      case CMX_Tag_JumpAbsolute_Offset:
1670
0
        m_nextInstructionOffset = readU32(input, m_bigEndian);
1671
0
      default:
1672
0
        break;
1673
0
      }
1674
0
      input->seek(offset + tagLength, librevenge::RVNG_SEEK_SET);
1675
0
    }
1676
0
    while (tagId != CMX_Tag_EndTag);
1677
0
  }
1678
0
  else if (m_precision == libcdr::PRECISION_16BIT)
1679
0
    m_nextInstructionOffset = readU32(input, m_bigEndian);
1680
0
  else
1681
0
    return;
1682
0
}
1683
1684
void libcdr::CMXParser::readRclr(librevenge::RVNGInputStream *input)
1685
0
{
1686
0
  unsigned fourCC = readU32(input, m_bigEndian);
1687
0
  if (CDR_FOURCC_rclr != fourCC)
1688
0
    return;
1689
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1690
1691
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1692
0
  CDR_DEBUG_MSG(("CMXParser::readRclr - numRecords %li\n", numRecords));
1693
0
  sanitizeNumRecords(numRecords, m_precision, 2, 2 + 0, 2, getRemainingLength(input));
1694
0
  for (unsigned j = 1; j <= numRecords; ++j)
1695
0
  {
1696
0
    CDR_DEBUG_MSG(("Color index %i\n", j));
1697
0
    unsigned char colorModel = 0;
1698
0
    if (m_precision == libcdr::PRECISION_32BIT)
1699
0
    {
1700
0
      unsigned char tagId = 0;
1701
0
      do
1702
0
      {
1703
0
        long offset = input->tell();
1704
0
        tagId = readU8(input, m_bigEndian);
1705
0
        if (tagId == CMX_Tag_EndTag)
1706
0
          break;
1707
0
        unsigned short tagLength = readTagLength(input, m_bigEndian);
1708
0
        switch (tagId)
1709
0
        {
1710
0
        case CMX_Tag_DescrSection_Color_Base:
1711
0
          colorModel = readU8(input, m_bigEndian);
1712
0
          readU8(input, m_bigEndian);
1713
0
          break;
1714
0
        case CMX_Tag_DescrSection_Color_ColorDescr:
1715
0
          m_parserState.m_colorPalette[j] = readColor(input, colorModel);
1716
0
          break;
1717
0
        default:
1718
0
          break;
1719
0
        }
1720
0
        input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
1721
0
      }
1722
0
      while (tagId != CMX_Tag_EndTag);
1723
0
    }
1724
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1725
0
    {
1726
0
      colorModel = readU8(input, m_bigEndian);
1727
0
      readU8(input, m_bigEndian);
1728
0
      m_parserState.m_colorPalette[j] = readColor(input, colorModel);
1729
0
    }
1730
0
    else
1731
0
      return;
1732
0
  }
1733
0
}
1734
1735
void libcdr::CMXParser::readRdot(librevenge::RVNGInputStream *input)
1736
0
{
1737
0
  unsigned fourCC = readU32(input, m_bigEndian);
1738
0
  if (CDR_FOURCC_rdot != fourCC)
1739
0
    return;
1740
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1741
1742
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1743
0
  CDR_DEBUG_MSG(("CMXParser::readRdot - numRecords %li\n", numRecords));
1744
0
  sanitizeNumRecords(numRecords, m_precision, 2, 2, 1, getRemainingLength(input));
1745
0
  for (unsigned j = 1; j <= numRecords; ++j)
1746
0
  {
1747
0
    std::vector<unsigned> dots;
1748
0
    if (m_precision == libcdr::PRECISION_32BIT)
1749
0
    {
1750
0
      unsigned char tagId = 0;
1751
0
      do
1752
0
      {
1753
0
        long offset = input->tell();
1754
0
        tagId = readU8(input, m_bigEndian);
1755
0
        if (tagId == CMX_Tag_EndTag)
1756
0
          break;
1757
0
        unsigned short tagLength = readTagLength(input, m_bigEndian);
1758
0
        switch (tagId)
1759
0
        {
1760
0
        case CMX_Tag_DescrSection_Dash:
1761
0
        {
1762
0
          unsigned long dotCount = readU16(input, m_bigEndian);
1763
0
          if (dotCount > getRemainingLength(input) / 2)
1764
0
            dotCount = getRemainingLength(input) / 2;
1765
0
          for (unsigned long i = 0; i < dotCount; ++i)
1766
0
            dots.push_back(readU16(input, m_bigEndian));
1767
0
          break;
1768
0
        }
1769
0
        default:
1770
0
          break;
1771
0
        }
1772
0
        input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
1773
0
      }
1774
0
      while (tagId != CMX_Tag_EndTag);
1775
0
    }
1776
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1777
0
    {
1778
0
      unsigned long dotCount = readU16(input, m_bigEndian);
1779
0
      if (dotCount > getRemainingLength(input) / 2)
1780
0
        dotCount = getRemainingLength(input) / 2;
1781
0
      for (unsigned long i = 0; i < dotCount; ++i)
1782
0
        dots.push_back(readU16(input, m_bigEndian));
1783
0
    }
1784
0
    else
1785
0
      return;
1786
0
    m_parserState.m_dashArrays[j] = dots;
1787
0
  }
1788
0
}
1789
1790
void libcdr::CMXParser::readRott(librevenge::RVNGInputStream *input)
1791
0
{
1792
0
  unsigned fourCC = readU32(input, m_bigEndian);
1793
0
  if (CDR_FOURCC_rott != fourCC)
1794
0
    return;
1795
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1796
1797
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1798
0
  CDR_DEBUG_MSG(("CMXParser::readRott - numRecords %li\n", numRecords));
1799
0
  sanitizeNumRecords(numRecords, m_precision, 2, 2, 1, getRemainingLength(input));
1800
0
  for (unsigned j = 1; j <= numRecords; ++j)
1801
0
  {
1802
0
    CMXLineStyle lineStyle;
1803
0
    if (m_precision == libcdr::PRECISION_32BIT)
1804
0
    {
1805
0
      unsigned char tagId = 0;
1806
0
      do
1807
0
      {
1808
0
        long offset = input->tell();
1809
0
        tagId = readU8(input, m_bigEndian);
1810
0
        if (tagId == CMX_Tag_EndTag)
1811
0
          break;
1812
0
        unsigned short tagLength = readTagLength(input, m_bigEndian);
1813
0
        switch (tagId)
1814
0
        {
1815
0
        case CMX_Tag_DescrSection_LineStyle:
1816
0
        {
1817
0
          lineStyle.m_spec = readU8(input, m_bigEndian);
1818
0
          lineStyle.m_capAndJoin = readU8(input, m_bigEndian);
1819
0
          break;
1820
0
        }
1821
0
        default:
1822
0
          break;
1823
0
        }
1824
0
        input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
1825
0
      }
1826
0
      while (tagId != CMX_Tag_EndTag);
1827
0
    }
1828
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1829
0
    {
1830
0
      lineStyle.m_spec = readU8(input, m_bigEndian);
1831
0
      lineStyle.m_capAndJoin = readU8(input, m_bigEndian);
1832
0
    }
1833
0
    else
1834
0
      return;
1835
0
    m_parserState.m_lineStyles[j] = lineStyle;
1836
0
  }
1837
0
}
1838
1839
void libcdr::CMXParser::readRotl(librevenge::RVNGInputStream *input)
1840
0
{
1841
0
  unsigned fourCC = readU32(input, m_bigEndian);
1842
0
  if (CDR_FOURCC_rotl != fourCC)
1843
0
    return;
1844
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1845
1846
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1847
0
  CDR_DEBUG_MSG(("CMXParser::readRotl - numRecords %li\n", numRecords));
1848
0
  sanitizeNumRecords(numRecords, m_precision, 12, 12, 1, getRemainingLength(input));
1849
0
  for (unsigned j = 1; j <= numRecords; ++j)
1850
0
  {
1851
0
    CMXOutline outline;
1852
0
    if (m_precision == libcdr::PRECISION_32BIT)
1853
0
    {
1854
0
      unsigned char tagId = 0;
1855
0
      do
1856
0
      {
1857
0
        long offset = input->tell();
1858
0
        tagId = readU8(input, m_bigEndian);
1859
0
        if (tagId == CMX_Tag_EndTag)
1860
0
          break;
1861
0
        unsigned short tagLength = readTagLength(input, m_bigEndian);
1862
0
        switch (tagId)
1863
0
        {
1864
0
        case CMX_Tag_DescrSection_Outline:
1865
0
        {
1866
0
          outline.m_lineStyle = readU16(input, m_bigEndian);
1867
0
          outline.m_screen = readU16(input, m_bigEndian);
1868
0
          outline.m_color = readU16(input, m_bigEndian);
1869
0
          outline.m_arrowHeads = readU16(input, m_bigEndian);
1870
0
          outline.m_pen = readU16(input, m_bigEndian);
1871
0
          outline.m_dashArray = readU16(input, m_bigEndian);
1872
0
          break;
1873
0
        }
1874
0
        default:
1875
0
          break;
1876
0
        }
1877
0
        input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
1878
0
      }
1879
0
      while (tagId != CMX_Tag_EndTag);
1880
0
    }
1881
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1882
0
    {
1883
0
      outline.m_lineStyle = readU16(input, m_bigEndian);
1884
0
      outline.m_screen = readU16(input, m_bigEndian);
1885
0
      outline.m_color = readU16(input, m_bigEndian);
1886
0
      outline.m_arrowHeads = readU16(input, m_bigEndian);
1887
0
      outline.m_pen = readU16(input, m_bigEndian);
1888
0
      outline.m_dashArray = readU16(input, m_bigEndian);
1889
0
    }
1890
0
    else
1891
0
      return;
1892
0
    m_parserState.m_outlines[j] = outline;
1893
0
  }
1894
0
}
1895
1896
void libcdr::CMXParser::readRpen(librevenge::RVNGInputStream *input)
1897
0
{
1898
0
  unsigned fourCC = readU32(input, m_bigEndian);
1899
0
  if (CDR_FOURCC_rpen != fourCC)
1900
0
    return;
1901
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1902
1903
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1904
0
  CDR_DEBUG_MSG(("CMXParser::readRpen - numRecords %li\n", numRecords));
1905
0
  sanitizeNumRecords(numRecords, m_precision, 10, 12, 1, getRemainingLength(input));
1906
0
  for (unsigned j = 1; j <= numRecords; ++j)
1907
0
  {
1908
0
    CMXPen pen;
1909
0
    if (m_precision == libcdr::PRECISION_32BIT)
1910
0
    {
1911
0
      unsigned char tagId = 0;
1912
0
      do
1913
0
      {
1914
0
        long offset = input->tell();
1915
0
        tagId = readU8(input, m_bigEndian);
1916
0
        if (tagId == CMX_Tag_EndTag)
1917
0
          break;
1918
0
        unsigned short tagLength = readTagLength(input, m_bigEndian);
1919
0
        switch (tagId)
1920
0
        {
1921
0
        case CMX_Tag_DescrSection_Pen:
1922
0
        {
1923
0
          pen.m_width = readCoordinate(input);
1924
0
          pen.m_aspect = (double)readU16(input, m_bigEndian) / 100.0;
1925
0
          pen.m_angle = readAngle(input);
1926
0
          pen.m_matrix = readMatrix(input);
1927
0
          break;
1928
0
        }
1929
0
        default:
1930
0
          break;
1931
0
        }
1932
0
        input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
1933
0
      }
1934
0
      while (tagId != CMX_Tag_EndTag);
1935
0
    }
1936
0
    else if (m_precision == libcdr::PRECISION_16BIT)
1937
0
    {
1938
0
      pen.m_width = readCoordinate(input);
1939
0
      pen.m_aspect = (double)readU16(input, m_bigEndian) / 100.0;
1940
0
      pen.m_angle = readAngle(input);
1941
0
      input->seek(2, librevenge::RVNG_SEEK_CUR);
1942
0
      pen.m_matrix = readMatrix(input);
1943
0
    }
1944
0
    else
1945
0
      return;
1946
0
    m_parserState.m_pens[j] = pen;
1947
0
  }
1948
0
}
1949
1950
void libcdr::CMXParser::readIxtl(librevenge::RVNGInputStream *input)
1951
0
{
1952
0
  unsigned fourCC = readU32(input, m_bigEndian);
1953
0
  if (CDR_FOURCC_ixtl != fourCC)
1954
0
    return;
1955
0
  /* unsigned length = */ readU32(input, m_bigEndian);
1956
1957
0
  unsigned long numRecords = readU16(input, m_bigEndian);
1958
0
  CDR_DEBUG_MSG(("CMXParser::readIxtl - numRecords %li\n", numRecords));
1959
0
  int sizeInFile(0);
1960
0
  if (m_precision == libcdr::PRECISION_32BIT)
1961
0
  {
1962
0
    sizeInFile = readU16(input, m_bigEndian);
1963
0
    if (sizeInFile < 4)
1964
0
      return;
1965
0
  }
1966
0
  unsigned type = readU16(input, m_bigEndian);
1967
0
  sanitizeNumRecords(numRecords, m_precision, 4, 4, getRemainingLength(input));
1968
0
  for (unsigned j = 1; j <= numRecords; ++j)
1969
0
  {
1970
0
    switch (type)
1971
0
    {
1972
0
    case 5: // BMP
1973
0
    {
1974
0
      unsigned offset = readU32(input, m_bigEndian);
1975
0
      long oldOffset = input->tell();
1976
0
      input->seek(offset, librevenge::RVNG_SEEK_SET);
1977
0
      parseImage(input);
1978
0
      input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
1979
0
      if (m_currentPattern && !m_currentPattern->pattern.empty())
1980
0
        m_collector->collectBmpf(j, m_currentPattern->width, m_currentPattern->height, m_currentPattern->pattern);
1981
0
      m_currentPattern = nullptr;
1982
0
      break;
1983
0
    }
1984
0
    case 6:
1985
0
      m_parserState.m_arrowOffsets[j] = readU32(input, m_bigEndian);
1986
0
      break;
1987
0
    default:
1988
0
      break;
1989
0
    }
1990
0
    if (sizeInFile)
1991
0
      input->seek(sizeInFile-4, librevenge::RVNG_SEEK_CUR);
1992
0
  }
1993
0
}
1994
1995
void libcdr::CMXParser::readIxef(librevenge::RVNGInputStream *input)
1996
0
{
1997
0
  unsigned fourCC = readU32(input, m_bigEndian);
1998
0
  if (CDR_FOURCC_ixef != fourCC)
1999
0
    return;
2000
0
  /* unsigned length = */ readU32(input, m_bigEndian);
2001
2002
0
  unsigned long numRecords = readU16(input, m_bigEndian);
2003
0
  CDR_DEBUG_MSG(("CMXParser::readIxef - numRecords %li\n", numRecords));
2004
0
  sanitizeNumRecords(numRecords, m_precision, 6, 8, getRemainingLength(input));
2005
0
  for (unsigned j = 1; j <= numRecords; ++j)
2006
0
  {
2007
0
    int sizeInFile(0);
2008
0
    if (m_precision == libcdr::PRECISION_32BIT)
2009
0
    {
2010
0
      sizeInFile = readU16(input, m_bigEndian);
2011
0
      if (sizeInFile < 6)
2012
0
        return;
2013
0
    }
2014
0
    unsigned offset = readU32(input, m_bigEndian);
2015
0
    unsigned type = readU16(input, m_bigEndian);
2016
0
    long oldOffset = input->tell();
2017
0
    if (type == 0x11)
2018
0
    {
2019
0
      input->seek(offset, librevenge::RVNG_SEEK_SET);
2020
0
      parseImage(input);
2021
0
      input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
2022
0
      if (m_currentBitmap && !(m_currentBitmap->bitmap.empty()))
2023
0
        m_collector->collectBmp(j, m_currentBitmap->colorModel, m_currentBitmap->width, m_currentBitmap->height,
2024
0
                                m_currentBitmap->bpp, m_currentBitmap->palette, m_currentBitmap->bitmap);
2025
0
      m_currentBitmap = nullptr;
2026
0
    }
2027
0
    if (sizeInFile)
2028
0
      input->seek(sizeInFile-6, librevenge::RVNG_SEEK_CUR);
2029
0
  }
2030
0
}
2031
2032
void libcdr::CMXParser::readIxpg(librevenge::RVNGInputStream *input)
2033
0
{
2034
0
  unsigned fourCC = readU32(input, m_bigEndian);
2035
0
  if (CDR_FOURCC_ixpg != fourCC)
2036
0
    return;
2037
0
  /* unsigned length = */ readU32(input, m_bigEndian);
2038
2039
0
  unsigned long numRecords = readU16(input, m_bigEndian);
2040
0
  CDR_DEBUG_MSG(("CMXParser::readIxpg - numRecords %li\n", numRecords));
2041
0
  sanitizeNumRecords(numRecords, m_precision, 16, 18, getRemainingLength(input));
2042
0
  for (unsigned j = 1; j <= numRecords; ++j)
2043
0
  {
2044
0
    int sizeInFile(0);
2045
0
    if (m_precision == libcdr::PRECISION_32BIT)
2046
0
    {
2047
0
      sizeInFile = readU16(input, m_bigEndian);
2048
0
      if (sizeInFile < 16)
2049
0
        return;
2050
0
    }
2051
0
    unsigned pageOffset = readU32(input, m_bigEndian);
2052
0
    /* unsigned layerTableOffset = */ readU32(input, m_bigEndian);
2053
0
    /* unsigned thumbnailOffset = */ readU32(input, m_bigEndian);
2054
0
    /* unsigned refListOffset = */ readU32(input, m_bigEndian);
2055
0
    if (pageOffset && pageOffset != (unsigned)-1)
2056
0
    {
2057
0
      long oldOffset = input->tell();
2058
0
      input->seek(pageOffset, librevenge::RVNG_SEEK_SET);
2059
0
      readPage(input);
2060
0
      input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
2061
0
    }
2062
0
    if (sizeInFile)
2063
0
      input->seek(sizeInFile-16, librevenge::RVNG_SEEK_CUR);
2064
0
  }
2065
0
}
2066
2067
void libcdr::CMXParser::readIxpc(librevenge::RVNGInputStream *input)
2068
0
{
2069
0
  unsigned fourCC = readU32(input, m_bigEndian);
2070
0
  if (CDR_FOURCC_ixpc != fourCC)
2071
0
    return;
2072
0
  /* unsigned length = */ readU32(input, m_bigEndian);
2073
2074
0
  unsigned numRecords = readU16(input, m_bigEndian);
2075
0
  CDR_DEBUG_MSG(("CMXParser::readIxpc - numRecords %i\n", numRecords));
2076
2077
  /* Don't really parse it for the while */
2078
0
  return;
2079
0
  for (unsigned j = 1; j <= numRecords; ++j)
2080
0
  {
2081
0
    int sizeInFile(0);
2082
0
    if (m_precision == libcdr::PRECISION_32BIT)
2083
0
    {
2084
0
      sizeInFile = readU16(input, m_bigEndian);
2085
0
      if (sizeInFile < 8)
2086
0
        return;
2087
0
    }
2088
0
    /* unsigned refListOffset = */ readU32(input, m_bigEndian);
2089
0
    unsigned procOffset = readU32(input, m_bigEndian);
2090
0
    if (procOffset && procOffset != (unsigned)-1)
2091
0
    {
2092
0
      long oldOffset = input->tell();
2093
0
      input->seek(procOffset, librevenge::RVNG_SEEK_SET);
2094
0
      m_collector->collectVect(0);
2095
0
      m_collector->collectSpnd(j);
2096
0
      readProc(input);
2097
0
      input->seek(oldOffset, librevenge::RVNG_SEEK_SET);
2098
0
    }
2099
0
    if (sizeInFile)
2100
0
      input->seek(sizeInFile-8, librevenge::RVNG_SEEK_CUR);
2101
0
  }
2102
0
}
2103
2104
void libcdr::CMXParser::readInfo(librevenge::RVNGInputStream *input)
2105
11
{
2106
11
  m_currentImageInfo = libcdr::CMXImageInfo();
2107
11
  CDR_DEBUG_MSG(("CMXParser::readInfo\n"));
2108
11
  if (m_precision == libcdr::PRECISION_32BIT)
2109
0
  {
2110
0
    unsigned char tagId = 0;
2111
0
    do
2112
0
    {
2113
0
      long offset = input->tell();
2114
0
      tagId = readU8(input, m_bigEndian);
2115
0
      if (tagId == CMX_Tag_EndTag)
2116
0
        break;
2117
0
      unsigned short tagLength = readTagLength(input, m_bigEndian);
2118
0
      switch (tagId)
2119
0
      {
2120
0
      case CMX_Tag_DescrSection_Image_ImageInfo:
2121
0
      {
2122
0
        m_currentImageInfo.m_type = readU16(input, m_bigEndian);
2123
0
        m_currentImageInfo.m_compression = readU16(input, m_bigEndian);
2124
0
        m_currentImageInfo.m_size = readU32(input, m_bigEndian);
2125
0
        m_currentImageInfo.m_compressedSize = readU32(input, m_bigEndian);
2126
0
      }
2127
0
      default:
2128
0
        break;
2129
0
      }
2130
0
      input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
2131
0
    }
2132
0
    while (tagId != CMX_Tag_EndTag);
2133
0
  }
2134
11
  else if (m_precision == libcdr::PRECISION_16BIT)
2135
0
  {
2136
0
    m_currentImageInfo.m_type = readU16(input, m_bigEndian);
2137
0
    m_currentImageInfo.m_compression = readU16(input, m_bigEndian);
2138
0
    m_currentImageInfo.m_size = readU32(input, m_bigEndian);
2139
0
    m_currentImageInfo.m_compressedSize = readU32(input, m_bigEndian);
2140
0
  }
2141
11
  else
2142
11
    return;
2143
11
}
2144
2145
void libcdr::CMXParser::readData(librevenge::RVNGInputStream *input)
2146
2
{
2147
2
  CDR_DEBUG_MSG(("CMXParser::readData\n"));
2148
2
  if (m_precision == libcdr::PRECISION_32BIT && m_currentImageInfo.m_type == 0x10)
2149
0
  {
2150
0
    unsigned char tagId = 0;
2151
0
    do
2152
0
    {
2153
0
      long offset = input->tell();
2154
0
      tagId = readU8(input, m_bigEndian);
2155
0
      if (tagId == CMX_Tag_EndTag)
2156
0
        break;
2157
0
      unsigned tagLength = readU32(input, m_bigEndian);
2158
0
      switch (tagId)
2159
0
      {
2160
0
      case CMX_Tag_DescrSection_Image_ImageData:
2161
0
      {
2162
0
        unsigned char first = readU8(input, m_bigEndian);
2163
0
        unsigned char second = readU8(input, m_bigEndian);
2164
0
        if (0x42 == first && 0x4d == second) // BM
2165
0
        {
2166
0
          unsigned fileSize = readU32(input, m_bigEndian);
2167
0
          input->seek(8, librevenge::RVNG_SEEK_CUR);
2168
0
          m_currentPattern.reset(new libcdr::CDRPattern());
2169
0
          readBmpPattern(m_currentPattern->width, m_currentPattern->height, m_currentPattern->pattern,
2170
0
                         fileSize - 14, input, m_bigEndian);
2171
0
        }
2172
0
        else if (0x52 == first && 0x49 == second) // RI
2173
0
        {
2174
0
          input->seek(12, librevenge::RVNG_SEEK_CUR);
2175
0
          m_currentBitmap.reset(new libcdr::CDRBitmap());
2176
0
          readRImage(m_currentBitmap->colorModel, m_currentBitmap->width, m_currentBitmap->height,
2177
0
                     m_currentBitmap->bpp, m_currentBitmap->palette, m_currentBitmap->bitmap,
2178
0
                     input, m_bigEndian);
2179
0
        }
2180
0
        break;
2181
0
      }
2182
0
      default:
2183
0
        break;
2184
0
      }
2185
0
      input->seek(offset+tagLength, librevenge::RVNG_SEEK_SET);
2186
0
    }
2187
0
    while (tagId != CMX_Tag_EndTag);
2188
0
  }
2189
2
  else if (m_precision == libcdr::PRECISION_16BIT || m_currentImageInfo.m_type != 0x10)
2190
2
  {
2191
2
    unsigned char first = readU8(input, m_bigEndian);
2192
2
    unsigned char second = readU8(input, m_bigEndian);
2193
2
    if (0x42 == first && 0x4d == second) // RI
2194
0
    {
2195
0
      unsigned fileSize = readU32(input, m_bigEndian);
2196
0
      input->seek(8, librevenge::RVNG_SEEK_CUR);
2197
0
      m_currentPattern.reset(new libcdr::CDRPattern());
2198
0
      readBmpPattern(m_currentPattern->width, m_currentPattern->height, m_currentPattern->pattern, fileSize - 14, input);
2199
0
    }
2200
2
    else if (0x52 == first && 0x49 == second)
2201
0
    {
2202
0
      input->seek(12, librevenge::RVNG_SEEK_CUR); // RI
2203
0
      m_currentBitmap.reset(new libcdr::CDRBitmap());
2204
0
      readRImage(m_currentBitmap->colorModel, m_currentBitmap->width, m_currentBitmap->height,
2205
0
                 m_currentBitmap->bpp, m_currentBitmap->palette, m_currentBitmap->bitmap,
2206
0
                 input, m_bigEndian);
2207
0
    }
2208
2
  }
2209
0
  else
2210
0
    return;
2211
2
}
2212
2213
libcdr::CDRColor libcdr::CMXParser::getPaletteColor(unsigned id)
2214
0
{
2215
0
  const std::map<unsigned, libcdr::CDRColor>::const_iterator iter = m_parserState.m_colorPalette.find(id);
2216
0
  if (iter != m_parserState.m_colorPalette.end())
2217
0
    return iter->second;
2218
0
  return libcdr::CDRColor();
2219
0
}
2220
2221
libcdr::CDRColor libcdr::CMXParser::readColor(librevenge::RVNGInputStream *input, unsigned char colorModel)
2222
0
{
2223
0
  libcdr::CDRColor color;
2224
0
  switch (colorModel)
2225
0
  {
2226
0
  case 0: // Invalid
2227
0
    CDR_DEBUG_MSG(("Invalid color model\n"));
2228
0
    break;
2229
0
  case 1: // Pantone
2230
0
  {
2231
0
    unsigned short pantoneId = readU16(input, m_bigEndian);
2232
0
    unsigned short pantoneDensity = readU16(input, m_bigEndian);
2233
0
    CDR_DEBUG_MSG(("Pantone color: id 0x%x, density 0x%x\n", pantoneId, pantoneDensity));
2234
0
    color.m_colorValue = ((unsigned)pantoneId & 0xff) | ((unsigned)pantoneId & 0xff00) | ((unsigned)pantoneDensity & 0xff) << 16 | ((unsigned)pantoneDensity & 0xff00) << 16;
2235
0
    color.m_colorModel = 0;
2236
0
    break;
2237
0
  }
2238
0
  case 2: // CMYK
2239
0
  {
2240
0
    unsigned char c = readU8(input, m_bigEndian);
2241
0
    unsigned char m = readU8(input, m_bigEndian);
2242
0
    unsigned char y = readU8(input, m_bigEndian);
2243
0
    unsigned char k = readU8(input, m_bigEndian);
2244
0
    CDR_DEBUG_MSG(("CMYK color: c 0x%x, m 0x%x, y 0x%x, k 0x%x\n", c, m, y, k));
2245
0
    color.m_colorValue = c | (unsigned)m << 8 | (unsigned)y << 16 | (unsigned)k << 24;
2246
0
    color.m_colorModel = colorModel;
2247
0
    break;
2248
0
  }
2249
0
  case 3: // CMYK255
2250
0
  {
2251
0
    unsigned char c = readU8(input, m_bigEndian);
2252
0
    unsigned char m = readU8(input, m_bigEndian);
2253
0
    unsigned char y = readU8(input, m_bigEndian);
2254
0
    unsigned char k = readU8(input, m_bigEndian);
2255
0
    CDR_DEBUG_MSG(("CMYK255 color: c 0x%x, m 0x%x, y 0x%x, k 0x%x\n", c, m, y, k));
2256
0
    color.m_colorValue = c | (unsigned)m << 8 | (unsigned)y << 16 | (unsigned)k << 24;
2257
0
    color.m_colorModel = colorModel;
2258
0
    break;
2259
0
  }
2260
0
  case 4: // CMY
2261
0
  {
2262
0
    unsigned char c = readU8(input, m_bigEndian);
2263
0
    unsigned char m = readU8(input, m_bigEndian);
2264
0
    unsigned char y = readU8(input, m_bigEndian);
2265
0
    CDR_DEBUG_MSG(("CMY color: c 0x%x, m 0x%x, y 0x%x\n", c, m, y));
2266
0
    color.m_colorValue = c | (unsigned)m << 8 | (unsigned)y << 16;
2267
0
    color.m_colorModel = colorModel;
2268
0
    break;
2269
0
  }
2270
0
  case 5: // RGB
2271
0
  {
2272
0
    unsigned char r = readU8(input, m_bigEndian);
2273
0
    unsigned char g = readU8(input, m_bigEndian);
2274
0
    unsigned char b = readU8(input, m_bigEndian);
2275
0
    CDR_DEBUG_MSG(("RGB color: r 0x%x, g 0x%x, b 0x%x\n", r, g, b));
2276
0
    color.m_colorValue = b | (unsigned)g << 8 | (unsigned)r << 16;
2277
0
    color.m_colorModel = colorModel;
2278
0
    break;
2279
0
  }
2280
0
  case 6: // HSB
2281
0
  {
2282
0
    unsigned short h = readU16(input, m_bigEndian);
2283
0
    unsigned char s = readU8(input, m_bigEndian);
2284
0
    unsigned char b = readU8(input, m_bigEndian);
2285
0
    CDR_DEBUG_MSG(("HSB color: h 0x%x, s 0x%x, b 0x%x\n", h, s, b));
2286
0
    color.m_colorValue = (h & 0xff) | ((unsigned)(h & 0xff00) >> 8) << 8 | (unsigned)s << 16 | (unsigned)b << 24;
2287
0
    color.m_colorModel = colorModel;
2288
0
    break;
2289
0
  }
2290
0
  case 7: // HLS
2291
0
  {
2292
0
    unsigned short h = readU16(input, m_bigEndian);
2293
0
    unsigned char l = readU8(input, m_bigEndian);
2294
0
    unsigned char s = readU8(input, m_bigEndian);
2295
0
    CDR_DEBUG_MSG(("HLS color: h 0x%x, l 0x%x, s 0x%x\n", h, l, s));
2296
0
    color.m_colorValue = (h & 0xff) | ((unsigned)(h & 0xff00) >> 8) << 8 | (unsigned)l << 16 | (unsigned)s << 24;
2297
0
    color.m_colorModel = colorModel;
2298
0
    break;
2299
0
  }
2300
0
  case 8: // BW
2301
0
  case 9: // Gray
2302
0
  {
2303
0
    unsigned value = readU8(input, m_bigEndian);
2304
0
    CDR_DEBUG_MSG(("%s color: %s 0x%x\n", colorModel == 8 ? "BW" : "Gray", colorModel == 8 ? "black" : "gray", value));
2305
0
    color.m_colorValue = value;
2306
0
    color.m_colorModel = colorModel;
2307
0
    break;
2308
0
  }
2309
0
  case 10: // YIQ255
2310
0
  {
2311
0
    unsigned char y = readU8(input, m_bigEndian);
2312
0
    unsigned char i = readU8(input, m_bigEndian);
2313
0
    unsigned char q = readU8(input, m_bigEndian);
2314
0
    CDR_DEBUG_MSG(("YIQ255 color: y 0x%x, i 0x%x, q 0x%x\n", y, i, q));
2315
0
    color.m_colorValue = (unsigned)y << 8 | (unsigned)i << 16 | (unsigned)q << 24 ;
2316
0
    color.m_colorModel = 11;
2317
0
    break;
2318
0
  }
2319
0
  case 11: // LAB
2320
0
  case 12: // LAB ???
2321
0
  {
2322
0
    unsigned char l = readU8(input, m_bigEndian);
2323
0
    unsigned char a = readU8(input, m_bigEndian);
2324
0
    unsigned char b = readU8(input, m_bigEndian);
2325
0
    CDR_DEBUG_MSG(("LAB color: L 0x%x, green2magenta 0x%x, blue2yellow 0x%x\n", l, a, b));
2326
0
    color.m_colorValue =l | (unsigned)a << 8 | (unsigned)b << 16;
2327
0
    color.m_colorModel = 12;
2328
0
    break;
2329
0
  }
2330
0
  case 0xff: // something funny here
2331
0
    input->seek(4, librevenge::RVNG_SEEK_CUR);
2332
0
    CDR_FALLTHROUGH;
2333
0
  default:
2334
0
    CDR_DEBUG_MSG(("Unknown color model %i\n", colorModel));
2335
0
    break;
2336
0
  }
2337
0
  return color;
2338
0
}
2339
2340
libcdr::CDRLineStyle libcdr::CMXParser::getLineStyle(unsigned id)
2341
0
{
2342
0
  libcdr::CDRLineStyle tmpLineStyle;
2343
0
  std::map<unsigned, CMXOutline>::const_iterator iterOutline = m_parserState.m_outlines.find(id);
2344
0
  if (iterOutline == m_parserState.m_outlines.end())
2345
0
    return tmpLineStyle;
2346
0
  unsigned lineStyleId = iterOutline->second.m_lineStyle;
2347
0
  unsigned colorId = iterOutline->second.m_color;
2348
0
  unsigned penId = iterOutline->second.m_pen;
2349
0
  unsigned dashArrayId = iterOutline->second.m_dashArray;
2350
0
  tmpLineStyle.color = getPaletteColor(colorId);
2351
0
  std::map<unsigned, CMXLineStyle>::const_iterator iterLineStyle = m_parserState.m_lineStyles.find(lineStyleId);
2352
0
  if (iterLineStyle != m_parserState.m_lineStyles.end())
2353
0
  {
2354
0
    tmpLineStyle.lineType = iterLineStyle->second.m_spec;
2355
0
    tmpLineStyle.capsType = (unsigned short)((iterLineStyle->second.m_capAndJoin) & 0xf);
2356
0
    tmpLineStyle.joinType = (unsigned short)(((iterLineStyle->second.m_capAndJoin) & 0xf0) >> 4);
2357
0
  }
2358
0
  std::map<unsigned, CMXPen>::const_iterator iterPen = m_parserState.m_pens.find(penId);
2359
0
  if (iterPen != m_parserState.m_pens.end())
2360
0
  {
2361
0
    tmpLineStyle.lineWidth = iterPen->second.m_width * (iterPen->second.m_matrix.getScaleX()+iterPen->second.m_matrix.getScaleY())/ 2.0;
2362
0
    if (!CDR_ALMOST_ZERO(iterPen->second.m_matrix.getScaleY()))
2363
0
      tmpLineStyle.stretch = iterPen->second.m_matrix.getScaleX()/iterPen->second.m_matrix.getScaleY();
2364
0
    else
2365
0
      tmpLineStyle.stretch = 1.0;
2366
0
    tmpLineStyle.stretch *= iterPen->second.m_aspect;
2367
0
    tmpLineStyle.angle = iterPen->second.m_angle;
2368
0
  }
2369
0
  std::map<unsigned, std::vector<unsigned> >::const_iterator iterDash = m_parserState.m_dashArrays.find(dashArrayId);
2370
0
  if (iterDash != m_parserState.m_dashArrays.end())
2371
0
  {
2372
0
    tmpLineStyle.dashArray = iterDash->second;
2373
0
  }
2374
0
  return tmpLineStyle;
2375
0
}
2376
2377
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */