Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/CanvasParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cmath>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <set>
39
#include <sstream>
40
#include <stack>
41
#include <utility>
42
43
#include <librevenge/librevenge.h>
44
45
#include "MWAWFontConverter.hxx"
46
#include "MWAWGraphicListener.hxx"
47
#include "MWAWGraphicStyle.hxx"
48
#include "MWAWHeader.hxx"
49
#include "MWAWPosition.hxx"
50
#include "MWAWPrinter.hxx"
51
#include "MWAWRSRCParser.hxx"
52
#include "MWAWStringStream.hxx"
53
54
#include "CanvasGraph.hxx"
55
#include "CanvasStyleManager.hxx"
56
57
#include "CanvasParser.hxx"
58
59
/** Internal: the structures of a CanvasParser */
60
namespace CanvasParserInternal
61
{
62
//! Internal: the layer of a CanvasParser
63
struct Layer {
64
  //! constructor
65
  Layer()
66
0
    : m_name()
67
    , m_numShapes()
68
0
    , m_shapesId()
69
0
  {
70
0
  }
71
  //! the layer name
72
  librevenge::RVNGString m_name;
73
  //! the number of shape
74
  int m_numShapes;
75
  //! the shape id
76
  std::vector<int> m_shapesId;
77
};
78
79
////////////////////////////////////////
80
//! Internal and low level: the decoder of a canvas file
81
struct Decoder {
82
  //! constructor
83
  Decoder()
84
21.7k
    : m_version(2)
85
21.7k
    , m_isWindows(false)
86
21.7k
    , m_input()
87
21.7k
    , m_inputPos(0)
88
21.7k
    , m_stream()
89
21.7k
  {
90
21.7k
  }
91
  //! first function to init the output (and copy the first headerSize characters)
92
  bool initOutput(MWAWInputStreamPtr &input, unsigned long const headerSize=0x89c);
93
  //! returns true if the input is completly decoded
94
  bool isEnd() const
95
0
  {
96
0
    return m_inputPos>=m_input->size();
97
0
  }
98
  //! try to read the following sz bytes and append them to the output
99
  bool append(long length);
100
  //! try to decode a part of the input
101
  bool decode(long length=-1);
102
  //! try to decode a part of the input: v3
103
  bool decode3(long length);
104
  //! try to unpack some bits from buffer into buffer2, assuming buffer and buffer2 differs
105
  bool unpackBits(unsigned char const(&buffer)[256], int n,
106
                  unsigned char (&buffer2)[256], int &n2) const;
107
108
  //! the file version
109
  int m_version;
110
  //! a flag to know if the file is a windows file
111
  bool m_isWindows;
112
  //! the initial input
113
  MWAWInputStreamPtr m_input;
114
  //! the input current position
115
  long m_inputPos;
116
  //! the current stream
117
  std::shared_ptr<MWAWStringStream> m_stream;
118
};
119
120
bool Decoder::unpackBits(unsigned char const(&buffer)[256], int n,
121
                         unsigned char (&buffer2)[256], int &n2) const
122
11.6k
{
123
11.6k
  if (n<=0 || n>256 || &buffer == &buffer2) {
124
213
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::unpackBits: bad arguments\n"));
125
213
    return false;
126
213
  }
127
11.4k
  int r=0;
128
11.4k
  n2=0;
129
  // canvas only packs zone with less than 127 characters
130
  // => we must not found <M> M+1 bits <N> N+1 bits
131
11.4k
  bool lastCopy=false;
132
49.4k
  while (r+1<n) {
133
39.9k
    int c=buffer[r++];
134
39.9k
    if (c>=0x81) {
135
13.9k
      unsigned char val=buffer[r++];
136
13.9k
      int num=0x101-c;
137
13.9k
      if (n2+num>256)
138
245
        return false;
139
155k
      for (int i=0; i<num; ++i)
140
141k
        buffer2[n2++]=val;
141
13.7k
      lastCopy=false;
142
13.7k
    }
143
25.9k
    else {
144
      // normally c==0x80 is reserved, but must not be used
145
25.9k
      if (lastCopy && !m_isWindows)
146
844
        return false;
147
25.0k
      int num=c+1;
148
25.0k
      if (r+num>n || n2+num>256)
149
831
        return false;
150
89.0k
      for (int i=0; i<num; ++i)
151
64.7k
        buffer2[n2++]=buffer[r++];
152
24.2k
      lastCopy=true;
153
24.2k
    }
154
39.9k
  }
155
9.52k
  return r==n;
156
11.4k
}
157
158
bool Decoder::initOutput(MWAWInputStreamPtr &input, unsigned long const headerSize)
159
8.90k
{
160
8.90k
  m_input=input;
161
8.90k
  if (!m_input || !m_input->checkPosition(long(headerSize)+20)) {
162
203
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::initOutput: can not find the input\n"));
163
203
    return false;
164
203
  }
165
166
8.69k
  m_input->seek(0, librevenge::RVNG_SEEK_SET);
167
8.69k
  unsigned long read;
168
8.69k
  const unsigned char *dt = m_input->read(headerSize, read);
169
8.69k
  if (!dt || read != headerSize) {
170
0
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::initOutput: can not read some data\n"));
171
0
    return false;
172
0
  }
173
8.69k
  m_stream.reset(new MWAWStringStream(dt, unsigned(headerSize)));
174
8.69k
  m_inputPos=long(headerSize);
175
8.69k
  return true;
176
8.69k
}
177
178
bool Decoder::append(long length)
179
0
{
180
0
  if (length==0)
181
0
    return true;
182
0
  if (!m_input || !m_stream || length<0 || !m_input->checkPosition(m_input->tell()+length)) {
183
0
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::append: the zone seems too short\n"));
184
0
    return false;
185
0
  }
186
0
  auto actIPos=m_input->tell();
187
0
  auto actOPos=m_stream->tell();
188
0
  m_input->seek(m_inputPos, librevenge::RVNG_SEEK_SET);
189
0
  m_stream->seek(0, librevenge::RVNG_SEEK_END);
190
191
0
  unsigned long read;
192
0
  const unsigned char *dt = m_input->read((unsigned long)length, read);
193
0
  bool ok=true;
194
0
  if (!dt || read != (unsigned long)length) {
195
0
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::append: can not read some data\n"));
196
0
    ok=false;
197
0
  }
198
0
  if (ok) {
199
0
    m_stream->append(dt, unsigned(length));
200
0
    m_inputPos=m_input->tell();
201
0
  }
202
203
0
  m_input->seek(actIPos, librevenge::RVNG_SEEK_SET);
204
0
  m_stream->seek(actOPos, librevenge::RVNG_SEEK_SET);
205
0
  return ok;
206
0
}
207
208
bool Decoder::decode(long length)
209
8.34k
{
210
8.34k
  if (!m_input || !m_stream) {
211
0
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not find the input/output\n"));
212
0
    return false;
213
0
  }
214
8.34k
  auto actIPos=m_input->tell();
215
8.34k
  auto actOPos=m_stream->tell();
216
8.34k
  m_input->seek(m_inputPos, librevenge::RVNG_SEEK_SET);
217
8.34k
  m_stream->seek(0, librevenge::RVNG_SEEK_END);
218
219
8.34k
  long lastPos=m_input->size();
220
8.34k
  bool ok=true;
221
8.34k
  if (m_inputPos>=lastPos)
222
0
    ok=false;
223
8.34k
  if (m_version<=2) {
224
2.66k
    long nWrite=0;
225
2.66k
    unsigned char data[256], data2[256];
226
3.47k
    while (ok && !m_input->isEnd()) {
227
3.46k
      if (length>=0 && nWrite>=length)
228
3
        break;
229
3.46k
      long pos=m_input->tell();
230
3.46k
      int zSz=int(m_input->readULong(1));
231
3.46k
      long endPos=pos+zSz;
232
3.46k
      if (zSz==0 || endPos>lastPos) {
233
1.13k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not read some data zSz=%d, pos=%lx\n", zSz, (unsigned long) pos));
234
1.13k
        ok=false;
235
1.13k
        break;
236
1.13k
      }
237
165k
      for (int i=0; i<zSz; ++i) data[i]=(unsigned char)(m_input->readULong(1));
238
2.32k
      int n;
239
2.32k
      if (!unpackBits(data, zSz, data2, n)) {
240
1.51k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not read some data at %lx\n", (unsigned long) pos));
241
1.51k
        ok=false;
242
1.51k
        break;
243
1.51k
      }
244
811
      m_stream->append(data2, static_cast<unsigned int>(n));
245
811
      nWrite+=n;
246
811
    }
247
2.66k
    if (ok && length>=0 && nWrite!=length) {
248
12
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not decode some data\n"));
249
12
      ok=false;
250
12
    }
251
2.66k
  }
252
5.68k
  else if (ok)
253
5.68k
    ok=decode3(length);
254
255
8.34k
  if (ok)
256
62
    m_inputPos=m_input->tell();
257
258
8.34k
  m_input->seek(actIPos, librevenge::RVNG_SEEK_SET);
259
8.34k
  m_stream->seek(actOPos, librevenge::RVNG_SEEK_SET);
260
8.34k
  return ok;
261
8.34k
}
262
263
#ifdef DEBUG_WITH_FILES
264
// flag to debug/or not the uncompress function
265
static bool s_showData=false;
266
#endif
267
bool Decoder::decode3(long length)
268
5.68k
{
269
5.68k
  if (!m_input || !m_stream) {
270
0
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: can not find the input/output\n"));
271
0
    return false;
272
0
  }
273
5.68k
  long lastPos=m_input->size();
274
5.68k
  long numWrite=0;
275
276
5.68k
  int const maxFinalSize=120;
277
5.68k
  unsigned char data[256], data2[256];
278
5.68k
  bool forceDict=false;
279
280
5.68k
  unsigned char m_dict[30];
281
5.68k
  std::set<unsigned char> m_dictKeys;
282
5.68k
  bool m_isDictInitialized=false;
283
5.68k
  long lastDictPos=0;
284
  // a zone is stored:
285
  // - either as a list of [length] packbits [checksum]
286
  // - or as a dictionary (30 keys) and a list of [length] bytes where bytes can be:
287
  //    . packbits [checksum] as before
288
  //    . or compressed with dictionary of (packbits [checksum])
289
  // I supposed that the dictionary is only created if the zone's length is greated than a constant (to be verified).
290
  // There remains also the problem to know if (packbits [checksum]) has been compressed with the dictionary or not ;
291
  //   currently, I test if I can decode these sub zones with the dictionary, ...
292
27.1k
  while (m_input->tell()<lastPos) {
293
27.0k
    if (length>=0 && numWrite>=length)
294
61
      return numWrite==length;
295
296
27.0k
    long pos=m_input->tell();
297
27.0k
    int zSz=int(m_input->readULong(1));
298
299
    // FIXME: find a method to detect if the zone begins with a dictionary, maybe length>some constant
300
27.0k
    if ((length<0 || numWrite==0) && lastDictPos+30!=pos && (zSz<2 || zSz>maxFinalSize+3 || forceDict)) {
301
5.43k
      if (pos+30>lastPos) {
302
204
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: can not read a dictionary at pos=%lx\n", (unsigned long) pos));
303
204
        return false;
304
204
      }
305
      // create the dictionary
306
5.23k
      lastDictPos=pos;
307
5.23k
      m_dict[0]=(unsigned char)(zSz);
308
156k
      for (int i=1; i<30; ++i)
309
151k
        m_dict[i]=(unsigned char)m_input->readULong(1);
310
5.23k
      m_dictKeys.clear();
311
156k
      for (auto &c : m_dict) m_dictKeys.insert(c);
312
5.23k
      m_isDictInitialized=true;
313
5.23k
      forceDict=false;
314
5.23k
      continue;
315
5.43k
    }
316
21.5k
    else if (forceDict) {
317
5.34k
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: can not place a dictionary at pos=%lx\n", (unsigned long) pos));
318
5.34k
      return false;
319
5.34k
    }
320
321
16.2k
    long endPos=pos+1+zSz;
322
16.2k
    if (endPos>lastPos) {
323
811
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: force a dictionary in pos=%lx\n", (unsigned long) pos));
324
811
      forceDict=true;
325
811
      m_input->seek(pos, librevenge::RVNG_SEEK_SET);
326
811
      continue;
327
811
    }
328
    // FIXME: find a method if the data are compressed or not
329
15.4k
    int const lastChecksumSz=m_isWindows ? 1 : 0;
330
33.9k
    for (int step=0; step<3; ++step) {
331
33.9k
      if (step==2) {
332
7.50k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: force a dictionary in pos=%lx\n", (unsigned long) pos));
333
7.50k
        forceDict=true;
334
7.50k
        m_input->seek(pos, librevenge::RVNG_SEEK_SET);
335
7.50k
        break;
336
7.50k
      }
337
26.4k
      m_input->seek(pos+1, librevenge::RVNG_SEEK_SET);
338
26.4k
      int numChar=int(m_input->readULong(1));
339
#ifdef DEBUG_WITH_FILES
340
      int nChar=numChar;
341
#endif
342
26.4k
      if (step==0) {
343
15.4k
        if (!m_isDictInitialized || zSz>numChar || numChar>2*zSz || numChar>maxFinalSize+2+lastChecksumSz) continue;
344
        // try to decode with the dictionary has been used to pack the data
345
7.08k
        bool ok=true;
346
7.08k
        int w=0;
347
7.08k
        unsigned char c;
348
7.08k
        bool readC=false;
349
94.0k
        while (m_input->tell()<=endPos && w<numChar) {
350
87.7k
          int newC=0;
351
171k
          for (int st=0; st<4; ++st) {
352
160k
            int val;
353
160k
            if (!readC) {
354
80.3k
              if (m_input->tell()>endPos) {
355
194
                ok=false;
356
194
                break;
357
194
              }
358
80.1k
              c=(unsigned char) m_input->readULong(1);
359
80.1k
              val=int(c>>4);
360
80.1k
            }
361
79.6k
            else
362
79.6k
              val=int(c&0xf);
363
159k
            readC=!readC;
364
365
159k
            if (val && st<2) {
366
75.8k
              data[w++]=m_dict[15*st+val-1];
367
75.8k
              break;
368
75.8k
            }
369
84.0k
            newC=(newC<<4)|val;
370
84.0k
            if (st==3) {
371
11.7k
              if (m_dictKeys.find((unsigned char) newC)!=m_dictKeys.end()) {
372
558
                ok=false;
373
558
                break;
374
558
              }
375
11.1k
              data[w++]=(unsigned char) newC;
376
11.1k
            }
377
84.0k
          }
378
87.7k
          if (ok==false)
379
752
            break;
380
87.7k
        }
381
7.08k
        if (ok==false || w!=numChar || m_input->tell()<endPos)
382
1.41k
          continue;
383
7.08k
      }
384
11.0k
      else {
385
        // basic copy
386
        // checkme: on mac, the first bytes is always ignored when numChar+1==zSz ;
387
        //          but only sometimes on windows :-~
388
11.0k
        if (numChar+1!=zSz) {
389
10.4k
          m_input->seek(-1, librevenge::RVNG_SEEK_CUR);
390
10.4k
          numChar=zSz;
391
10.4k
        }
392
344k
        for (int i=0; i<numChar; ++i)
393
333k
          data[i]=(unsigned char) m_input->readULong(1);
394
11.0k
      }
395
396
      // first check the checksum
397
16.7k
      int checkSum;
398
16.7k
      bool ok=false;
399
24.5k
      for (int step2=0; step2<2; ++step2) {
400
24.2k
        if (step2==1) {
401
7.48k
          if (!m_isWindows || step!=1 || numChar+1!=zSz)
402
7.05k
            break;
403
429
          m_input->seek(-zSz, librevenge::RVNG_SEEK_CUR);
404
429
          numChar=zSz;
405
13.6k
          for (int i=0; i<numChar; ++i)
406
13.2k
            data[i]=(unsigned char) m_input->readULong(1);
407
429
        }
408
17.1k
        checkSum=0;
409
379k
        for (int i=0; i<numChar-1; ++i)
410
361k
          checkSum+=int(data[i]);
411
17.1k
        if (numChar==0 || (checkSum&0xff)!=int(data[numChar-1]))
412
7.83k
          continue;
413
9.34k
        ok=true;
414
9.34k
        break;
415
17.1k
      }
416
16.7k
      if (!ok) continue;
417
418
9.34k
      --numChar;
419
#ifdef DEBUG_WITH_FILES
420
      if (s_showData) {
421
        std::cout << zSz << "[" << nChar << "," << numChar << "]:";
422
        auto prev=std::cout.fill('0');
423
        for (int i=0; i < numChar; ++i)
424
          std::cout << std::hex << std::setw(2) << int(data[i]) << std::dec;
425
        std::cout.fill(prev);
426
        std::cout << "\n";
427
      }
428
#endif
429
      // then check if we can unpack the data
430
9.34k
      int finalN;
431
9.34k
      if (!unpackBits(data, numChar, data2, finalN) || finalN>maxFinalSize+lastChecksumSz || (m_isWindows && finalN<=numChar) ||
432
7.72k
          (length>=0 && numWrite+finalN>length+lastChecksumSz) || finalN<1+lastChecksumSz) {
433
7.72k
        if (m_isWindows && (length<0 || numWrite+numChar<=length+lastChecksumSz) &&
434
6.93k
            numChar<=maxFinalSize+lastChecksumSz && numChar>=1+lastChecksumSz) {
435
49.4k
          for (int i=0; i < numChar; ++i)
436
42.9k
            data2[i]=data[i];
437
6.45k
          finalN=numChar;
438
6.45k
        }
439
1.26k
        else
440
1.26k
          continue;
441
7.72k
      }
442
#ifdef DEBUG_WITH_FILES
443
      if (s_showData) {
444
        std::cout << "\t" << finalN << ":";
445
        auto prev=std::cout.fill('0');
446
        for (int i=0; i < finalN; ++i)
447
          std::cout << std::hex << std::setw(2) << int(data2[i]) << std::dec;
448
        std::cout.fill(prev);
449
        std::cout << "\n";
450
      }
451
#endif
452
8.07k
      if (lastChecksumSz==1) {
453
6.45k
        checkSum=0;
454
43.1k
        for (int i=0; i<finalN-1; ++i)
455
36.6k
          checkSum+=int(data2[i]);
456
6.45k
        if ((checkSum&0xff)!=int(data2[finalN-1]))
457
167
          continue;
458
6.29k
        --finalN;
459
6.29k
      }
460
7.90k
      m_stream->append(data2, static_cast<unsigned int>(finalN));
461
7.90k
      numWrite+=finalN;
462
7.90k
      break;
463
8.07k
    }
464
15.4k
  }
465
71
  return length<0 || numWrite==length;
466
5.68k
}
467
////////////////////////////////////////
468
//! Internal: the state of a CanvasParser
469
struct State {
470
  //! constructor
471
  State()
472
14.5k
    : m_isWindowsFile(false)
473
14.5k
    , m_lengths()
474
14.5k
    , m_brushLengths()
475
14.5k
    , m_bitmapSize(0)
476
14.5k
    , m_input()
477
14.5k
    , m_decoder()
478
14.5k
    , m_numLayers(1)
479
14.5k
    , m_numShapes(0)
480
14.5k
    , m_numViews(0)
481
14.5k
    , m_numColors(256) // FIXME: check if this number is stored in the file or not
482
14.5k
    , m_numPatterns(120)
483
14.5k
    , m_sprayLengths()
484
485
14.5k
    , m_numPages(1,1)
486
14.5k
    , m_pageDimension(425, 624)
487
14.5k
    , m_layers()
488
489
14.5k
    , m_metaData()
490
14.5k
  {
491
14.5k
  }
492
493
  //! true if this is a windows file
494
  bool m_isWindowsFile;
495
  //! the file header first 4+1 lengths
496
  std::vector<unsigned long> m_lengths;
497
  //! the brush lengths
498
  std::vector<unsigned long> m_brushLengths;
499
  //! the file bitmap size (Windows v3)
500
  long m_bitmapSize;
501
  //! the uncompressed input
502
  MWAWInputStreamPtr m_input;
503
  //! the main decoder
504
  Decoder m_decoder;
505
  //! the number of layer
506
  int m_numLayers;
507
  //! the number of shapes
508
  int m_numShapes;
509
  //! the number of views
510
  int m_numViews;
511
  //! the number of colors
512
  int m_numColors;
513
  //! the number of patterns
514
  int m_numPatterns;
515
  //! the list of spray size
516
  std::vector<unsigned long> m_sprayLengths;
517
518
  //! the number of pages
519
  MWAWVec2i m_numPages;
520
  //! the page dimension
521
  MWAWVec2i m_pageDimension;
522
  //! the layer
523
  std::vector<Layer> m_layers;
524
525
  //! the meta data
526
  librevenge::RVNGPropertyList m_metaData;
527
};
528
529
}
530
531
////////////////////////////////////////////////////////////
532
// constructor/destructor, ...
533
////////////////////////////////////////////////////////////
534
CanvasParser::CanvasParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
535
14.5k
  : MWAWGraphicParser(input, rsrcParser, header)
536
14.5k
  , m_state()
537
14.5k
  , m_graphParser()
538
14.5k
  , m_styleManager()
539
14.5k
{
540
14.5k
  resetGraphicListener();
541
14.5k
  setAsciiName("main-1");
542
543
14.5k
  m_state.reset(new CanvasParserInternal::State);
544
545
14.5k
  m_styleManager.reset(new CanvasStyleManager(*this));
546
14.5k
  m_graphParser.reset(new CanvasGraph(*this));
547
548
14.5k
  getPageSpan().setMargins(0.1);
549
14.5k
}
550
551
CanvasParser::~CanvasParser()
552
14.5k
{
553
14.5k
}
554
555
MWAWInputStreamPtr &CanvasParser::getInput()
556
111k
{
557
111k
  if (m_state->m_input)
558
86.8k
    return m_state->m_input;
559
24.2k
  return MWAWGraphicParser::getInput();
560
111k
}
561
562
bool CanvasParser::decode(long length)
563
1.39k
{
564
1.39k
  long prevSize=m_state->m_input ? m_state->m_input->size() : 0;
565
1.39k
  if (!m_state->m_input || !m_state->m_decoder.decode(length)) {
566
1.38k
    if (m_state->m_decoder.m_stream)
567
1.38k
      m_state->m_decoder.m_stream->resize((unsigned long)(prevSize));
568
1.38k
    return false;
569
1.38k
  }
570
10
  m_state->m_input->recomputeStreamSize();
571
10
  return true;
572
1.39k
}
573
574
bool CanvasParser::isWindowsFile() const
575
79.2k
{
576
79.2k
  return m_state->m_isWindowsFile;
577
79.2k
}
578
579
////////////////////////////////////////////////////////////
580
// the parser
581
////////////////////////////////////////////////////////////
582
void CanvasParser::parse(librevenge::RVNGDrawingInterface *docInterface)
583
1.94k
{
584
1.94k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
585
1.94k
  bool ok = false;
586
1.94k
  try {
587
1.94k
    checkHeader(nullptr);
588
1.94k
    ascii().setStream(getInput());
589
1.94k
    ascii().open(asciiName());
590
1.94k
    if (!readFileHeader())
591
0
      throw libmwaw::ParseException();
592
593
1.94k
    bool const isWindows=isWindowsFile();
594
1.94k
    m_state->m_decoder.m_isWindows=isWindows;
595
1.94k
    m_state->m_decoder.m_version=version();
596
1.94k
    if (!m_state->m_decoder.initOutput(getInput(), isWindows ? (unsigned long)(0x920+m_state->m_bitmapSize) : 0x89c) || !m_state->m_decoder.m_stream)
597
138
      throw libmwaw::ParseException();
598
1.80k
    m_state->m_input.reset(new MWAWInputStream(m_state->m_decoder.m_stream, isWindows));
599
600
    // update the style manager and the graph parser and the asciiFile input
601
1.80k
    m_styleManager->setInput(m_state->m_input);
602
1.80k
    m_graphParser->setInput(m_state->m_input);
603
1.80k
    ascii().setStream(m_state->m_input);
604
605
1.80k
    ok = createZones();
606
1.80k
    if (ok) {
607
0
      createDocument(docInterface);
608
0
      for (auto const &layer : m_state->m_layers)
609
0
        send(layer);
610
0
      m_graphParser->checkUnsent();
611
0
    }
612
1.80k
  }
613
1.94k
  catch (...) {
614
138
    MWAW_DEBUG_MSG(("CanvasParser::parse: exception catched when parsing\n"));
615
138
    ok = false;
616
138
  }
617
618
1.94k
  ascii().reset();
619
1.94k
  resetGraphicListener();
620
1.94k
  if (!ok) throw(libmwaw::ParseException());
621
1.94k
}
622
623
////////////////////////////////////////////////////////////
624
// create the document
625
////////////////////////////////////////////////////////////
626
void CanvasParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
627
0
{
628
0
  if (!documentInterface) return;
629
0
  if (getGraphicListener()) {
630
0
    MWAW_DEBUG_MSG(("CanvasParser::createDocument: listener already exist\n"));
631
0
    return;
632
0
  }
633
634
  // create the page list
635
0
  MWAWPageSpan ps(getPageSpan());
636
0
  if (m_state->m_numPages!=MWAWVec2i(1,1)) {
637
0
    ps.setFormWidth(double(m_state->m_numPages[0])*ps.getFormWidth());
638
0
    ps.setFormLength(double(m_state->m_numPages[1])*ps.getFormLength());
639
0
  }
640
0
  ps.setPageSpan(1);
641
0
  std::vector<MWAWPageSpan> pageList(1,ps);
642
0
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
643
0
  setGraphicListener(listen);
644
645
0
  if (!m_state->m_metaData.empty())
646
0
    listen->setDocumentMetaData(m_state->m_metaData);
647
0
  listen->startDocument();
648
0
}
649
650
////////////////////////////////////////////////////////////
651
//
652
// Intermediate level
653
//
654
////////////////////////////////////////////////////////////
655
bool CanvasParser::createZones()
656
1.80k
{
657
1.80k
  auto input=getInput();
658
1.80k
  if (!input) return false;
659
660
1.80k
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
661
1.80k
  if (rsrcParser) {
662
0
    auto rsrcInput=rsrcParser->getInput();
663
0
    auto &rsrcAscii=rsrcParser->ascii();
664
0
    auto const &entryMap = rsrcParser->getEntriesMap();
665
666
0
    for (int w=0; w<5; ++w) {
667
0
      static char const* const wh[]= {"HeAd" /*11164*/, "Jinf" /* 10568 */, "WIND" /* 10568 */, "LPol" /* 2,4,... */, "USER" /*0*/};
668
0
      auto it = entryMap.lower_bound(wh[w]);
669
0
      while (it != entryMap.end() && it->first==wh[w]) {
670
0
        auto const &entry=it++->second;
671
0
        if (!entry.valid()) continue;
672
0
        switch (w) {
673
0
        case 0:
674
0
          readRSRCFileHeader(rsrcInput, entry, rsrcAscii);
675
0
          break;
676
0
        case 1:
677
0
          readPrintInfo(rsrcInput, entry, rsrcAscii);
678
0
          break;
679
0
        case 2:
680
0
          readWindows(rsrcInput, entry, rsrcAscii);
681
0
          break;
682
0
        case 3:
683
0
          readLPOL(rsrcInput, entry, rsrcAscii);
684
0
          break;
685
0
        case 4:
686
0
        default:
687
0
          readUsers(rsrcInput, entry, rsrcAscii);
688
0
          break;
689
0
        }
690
0
      }
691
0
    }
692
0
  }
693
694
1.80k
  bool const isWindows=m_state->m_isWindowsFile;
695
1.80k
  input->seek(0x3c, librevenge::RVNG_SEEK_SET);
696
1.80k
  if (isWindows) {
697
831
    if (!m_graphParser->readFileBitmap(m_state->m_bitmapSize) || !input->checkPosition(input->tell()+132))
698
418
      return false;
699
413
    long pos=input->tell();
700
413
    libmwaw::DebugStream f;
701
413
    f << "Entries(Brush):lengths=[";
702
13.6k
    for (int i=0; i<32; ++i) {
703
13.2k
      auto length=input->readULong(4);
704
13.2k
      m_state->m_brushLengths.push_back(length);
705
13.2k
      f << length << ",";
706
13.2k
    }
707
413
    f << "],";
708
413
    f << "f0=" << input->readULong(4) << ","; // small number
709
413
    ascii().addPos(pos);
710
413
    ascii().addNote(f.str().c_str());
711
413
  }
712
1.38k
  if (!readUnknownZoneHeader() || !m_styleManager->readPenSize() || !readDocumentHeader() || !readMacroNames() ||
713
1.38k
      !readUnknownZone0() || !m_styleManager->readArrows() || !readFormats() || !readGrids() || !readUnknownZone1())
714
0
    return false;
715
716
1.38k
  if (!m_graphParser->readShapes(m_state->m_numShapes, m_state->m_lengths[0], m_state->m_lengths[1]))
717
1.38k
    return false;
718
719
0
  if (!readLayers() || !readViews() || !m_styleManager->readPatterns(m_state->m_numPatterns))
720
0
    return false;
721
722
0
  if (!m_styleManager->readColors(m_state->m_numColors))
723
0
    return true;
724
0
  if (!readUnknownZone2() || !readBrushes() || !readUnknownZone3())
725
0
    return true;
726
0
  if (!readSprays() || !readUnknownZone4())
727
0
    return true;
728
729
  // end of v2
730
0
  if (m_state->m_decoder.isEnd())
731
0
    return true;
732
733
0
  if (!m_styleManager->readDashes(6) || !readEndV3())
734
0
    return true;
735
736
0
  if (isWindows && !readRSRCWindowsFile())
737
0
    return true;
738
739
0
  if (m_state->m_decoder.isEnd())
740
0
    return true;
741
742
0
  decode(-1);
743
0
  MWAW_DEBUG_MSG(("CanvasParser::createZones: unexpected last zone size\n"));
744
0
  ascii().addPos(input->tell());
745
0
  ascii().addNote("Entries(Last):###");
746
747
0
  return true;
748
0
}
749
750
bool CanvasParser::readLayers()
751
0
{
752
0
  if (long(m_state->m_lengths[2])<0 || !decode(long(m_state->m_lengths[2]))) {
753
0
    MWAW_DEBUG_MSG(("CanvasParser::readLayers: can not decode the input\n"));
754
0
    return false;
755
0
  }
756
0
  MWAWInputStreamPtr input = getInput();
757
0
  long pos=input->tell();
758
0
  long endPos=pos+long(m_state->m_lengths[2]);
759
0
  if (!input->checkPosition(endPos) || m_state->m_numLayers < 0 ||
760
0
      long(m_state->m_lengths[2])/42 < m_state->m_numLayers) {
761
0
    MWAW_DEBUG_MSG(("CanvasParser::readLayers: zone seems too short\n"));
762
0
    return false;
763
0
  }
764
0
  libmwaw::DebugStream f;
765
0
  f << "Entries(Layer):";
766
0
  ascii().addPos(pos);
767
0
  ascii().addNote(f.str().c_str());
768
769
0
  std::vector<unsigned long> dataSize;
770
0
  m_state->m_layers.resize(size_t(m_state->m_numLayers));
771
0
  for (size_t i=0; i<size_t(m_state->m_numLayers); ++i) {
772
0
    pos=input->tell();
773
0
    f.str("");
774
0
    f << "Layer-" << i << ":";
775
0
    CanvasParserInternal::Layer &layer=m_state->m_layers[i];
776
0
    dataSize.push_back(input->readULong(4));
777
0
    f << "dSz=" << dataSize.back() << ",";
778
0
    layer.m_numShapes=int(input->readULong(2));
779
0
    f << "n[shapes]=" << layer.m_numShapes << ",";
780
0
    ascii().addDelimiter(input->tell(),'|');
781
0
    input->seek(pos+22, librevenge::RVNG_SEEK_SET);
782
0
    ascii().addDelimiter(input->tell(),'|');
783
0
    if (readString(layer.m_name, 20))
784
0
      f << layer.m_name.cstr() << ",";
785
0
    else {
786
0
      f << "###name,";
787
0
      MWAW_DEBUG_MSG(("CanvasParser::readLayers: bad name\n"));
788
0
    }
789
0
    input->seek(pos+42, librevenge::RVNG_SEEK_SET);
790
0
    ascii().addPos(pos);
791
0
    ascii().addNote(f.str().c_str());
792
0
  }
793
0
  if (input->tell()!=endPos) {
794
0
    ascii().addPos(input->tell());
795
0
    ascii().addNote("Layer-End:");
796
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
797
0
  }
798
799
0
  for (size_t i=0; i<size_t(m_state->m_numLayers); ++i) {
800
0
    if (!dataSize[i]) continue;
801
0
    if (long(dataSize[i])<0 || !decode(long(dataSize[i]))) {
802
0
      MWAW_DEBUG_MSG(("CanvasParser::readLayers: can not decode the data %d input\n", int(i)));
803
0
      return false;
804
0
    }
805
0
    pos=input->tell();
806
0
    f.str("");
807
0
    f << "Layer-data" << i << ":";
808
0
    auto &layer=m_state->m_layers[i];
809
0
    if (!input->checkPosition(pos+long(dataSize[size_t(i)]))) {
810
0
      MWAW_DEBUG_MSG(("CanvasParser::readLayers: can not find data %d\n", int(i)));
811
0
      f << "###";
812
0
      ascii().addPos(pos);
813
0
      ascii().addNote(f.str().c_str());
814
0
      return false;
815
0
    }
816
0
    if (long(dataSize[size_t(i)])<2*layer.m_numShapes) {
817
0
      MWAW_DEBUG_MSG(("CanvasParser::readLayers: the size seems too short\n"));
818
0
      f << "###";
819
0
    }
820
0
    else {
821
0
      if (layer.m_numShapes)
822
0
        f << "f0=" << std::hex << input->readULong(2) << std::dec << ",";
823
0
      f << "ids=[";
824
0
      for (int j=1; j<layer.m_numShapes; ++j) {
825
0
        layer.m_shapesId.push_back(int(input->readULong(2)));
826
0
        f << layer.m_shapesId.back() << ",";
827
0
      }
828
0
      f << "],";
829
0
      if (long(dataSize[size_t(i)])!=2*layer.m_numShapes)
830
0
        ascii().addDelimiter(input->tell(),'|');
831
0
    }
832
0
    input->seek(pos+long(dataSize[size_t(i)]), librevenge::RVNG_SEEK_SET);
833
0
    ascii().addPos(pos);
834
0
    ascii().addNote(f.str().c_str());
835
0
  }
836
837
0
  return true;
838
0
}
839
840
////////////////////////////////////////////////////////////
841
// read the header
842
////////////////////////////////////////////////////////////
843
bool CanvasParser::checkHeader(MWAWHeader *header, bool strict)
844
16.4k
{
845
16.4k
  MWAWInputStreamPtr input = getInput();
846
16.4k
  if (!input || !input->hasDataFork() || !input->checkPosition(0x89e))
847
0
    return false;
848
849
16.4k
  input->setReadInverted(false);
850
16.4k
  input->seek(0x36, librevenge::RVNG_SEEK_SET);
851
16.4k
  int val=int(input->readULong(2));
852
16.4k
  int vers=0;
853
16.4k
  switch (val) {
854
4.28k
  case 1:
855
4.28k
    vers=2;
856
4.28k
    break;
857
5.55k
  case 2:
858
5.55k
    vers=3;
859
5.55k
    break;
860
6.52k
  case 0x100:
861
6.52k
    input->setReadInverted(true);
862
6.52k
    m_state->m_isWindowsFile=true;
863
6.52k
    vers=3;
864
6.52k
    break;
865
89
  default:
866
89
    MWAW_DEBUG_MSG(("CanvasParser::checkHeader: unknown version=%d\n", val));
867
89
    return false;
868
16.4k
  }
869
870
16.3k
  input->seek(0, librevenge::RVNG_SEEK_SET);
871
16.3k
  unsigned long lengths[3];
872
48.6k
  for (auto &l : lengths) {
873
    // check that no shape/shape data/layer lengths is empty
874
48.6k
    l=input->readULong(4);
875
48.6k
    if (l==0)
876
554
      return false;
877
48.6k
  }
878
15.8k
  if (strict) {
879
    // try to decode the shape and the shape data zone
880
7.22k
    CanvasParserInternal::Decoder decoder;
881
7.22k
    decoder.m_isWindows=m_state->m_isWindowsFile;
882
7.22k
    decoder.m_version=vers;
883
7.22k
    input->seek(0x38, librevenge::RVNG_SEEK_SET);
884
7.22k
    unsigned long bitmapSize=m_state->m_isWindowsFile ? input->readULong(4) : 0;
885
7.22k
    if (long(bitmapSize)<0 || (m_state->m_isWindowsFile && !input->checkPosition(long(0x920+bitmapSize))) ||
886
6.95k
        !decoder.initOutput(input, m_state->m_isWindowsFile ? 0x920+bitmapSize : 0x89c) ||
887
6.89k
        !decoder.decode(long(lengths[0])) || !decoder.decode(long(lengths[1])))
888
7.22k
      return false;
889
7.22k
  }
890
8.58k
  setVersion(vers);
891
8.58k
  if (header)
892
4.70k
    header->reset(MWAWDocument::MWAW_T_CANVAS, vers, MWAWDocument::MWAW_K_DRAW);
893
894
8.58k
  return true;
895
15.8k
}
896
897
bool CanvasParser::readFileHeader()
898
1.94k
{
899
1.94k
  auto input=getInput();
900
1.94k
  long const endPos=0x3c;
901
1.94k
  if (!input || !input->checkPosition(endPos)) {
902
0
    MWAW_DEBUG_MSG(("CanvasParser::readFileHeader: file is too short\n"));
903
0
    return false;
904
0
  }
905
906
1.94k
  m_state->m_lengths.clear();
907
908
1.94k
  libmwaw::DebugStream f;
909
1.94k
  f << "FileHeader:";
910
1.94k
  input->seek(0, librevenge::RVNG_SEEK_SET);
911
1.94k
  f << "length=[";
912
27.2k
  for (int i=0; i<13; ++i) {
913
25.2k
    auto length=input->readULong(4);
914
25.2k
    if (i>=4 && i<12)
915
15.5k
      m_state->m_brushLengths.push_back(length);
916
9.72k
    else
917
9.72k
      m_state->m_lengths.push_back(length);
918
25.2k
    f << length << ",";
919
25.2k
  }
920
1.94k
  f << "],";
921
1.94k
  ascii().addPos(0);
922
1.94k
  ascii().addNote(f.str().c_str());
923
924
1.94k
  long pos=input->tell();
925
1.94k
  f.str("");
926
1.94k
  f << "FileHeader-end:";
927
1.94k
  int val;
928
1.94k
  val=int(input->readLong(1));
929
1.94k
  if (val==1)
930
969
    f << "little[endian],";
931
975
  else if (val)
932
0
    f << "##endian=" << val << ",";
933
1.94k
  val=int(input->readULong(1)); // v2: 100, v3: 104
934
1.94k
  switch (val) {
935
5
  case 100:
936
5
    f << "v2.0,";
937
5
    break;
938
0
  case 102:
939
0
    f << "v2.1,";
940
0
    break;
941
0
  case 104:
942
0
    f << "v3.0,";
943
0
    break;
944
0
  case 105:
945
0
    f << "v3.5,";
946
0
    break;
947
0
  case 107: // or windows 3.5
948
0
    f << "v3.5.2,";
949
0
    break;
950
1.93k
  default:
951
1.93k
    f << "version=" << val << ",";
952
1.93k
    break;
953
1.94k
  }
954
1.94k
  val=int(input->readULong(2));
955
1.94k
  if (val!=1) f << "vers=" << val+1 << ",";
956
1.94k
  if (isWindowsFile()) {
957
969
    m_state->m_bitmapSize=long(input->readULong(4));
958
969
    f << "bitmap[size]=" << m_state->m_bitmapSize << ",";
959
969
  }
960
1.94k
  if (input->tell()!=endPos)
961
975
    ascii().addDelimiter(input->tell(),'|');
962
1.94k
  ascii().addPos(pos);
963
1.94k
  ascii().addNote(f.str().c_str());
964
1.94k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
965
1.94k
  return true;
966
1.94k
}
967
968
bool CanvasParser::readDocumentHeader()
969
1.38k
{
970
1.38k
  auto input=getInput();
971
1.38k
  long pos=input ? input->tell() : 0;
972
1.38k
  if (!input || !input->checkPosition(pos+230)) {
973
0
    MWAW_DEBUG_MSG(("CanvasParser::readDocumentHeader: file is too short\n"));
974
0
    return false;
975
0
  }
976
977
1.38k
  libmwaw::DebugStream f;
978
1.38k
  f << "Entries(Document):";
979
1.38k
  input->seek(pos+46, librevenge::RVNG_SEEK_SET);
980
1.38k
  ascii().addDelimiter(input->tell(),'|');
981
1.38k
  int dim[2];
982
2.77k
  for (auto &d : dim) d=int(input->readULong(2));
983
1.38k
  if (dim[0]!=1 || dim[1]!=1) {
984
1.37k
    m_state->m_numPages=MWAWVec2i(dim[0], dim[1]);
985
1.37k
    f << "pages=" << m_state->m_numPages << ",";
986
1.37k
    if (dim[0]<=0 || dim[0]>15 || dim[1]<=0 || dim[1]>15) {
987
1.36k
      MWAW_DEBUG_MSG(("CanvasParser::readDocumentHeader: the number of pages seems bad\n"));
988
1.36k
      f << "###";
989
1.36k
      m_state->m_numPages=MWAWVec2i(1,1);
990
1.36k
    }
991
1.37k
  }
992
1.38k
  ascii().addDelimiter(input->tell(),'|');
993
1.38k
  input->seek(pos+60, librevenge::RVNG_SEEK_SET);
994
1.38k
  ascii().addPos(pos);
995
1.38k
  ascii().addNote(f.str().c_str());
996
997
1.38k
  pos=input->tell();
998
1.38k
  f.str("");
999
1.38k
  f << "Document-0:";
1000
1.38k
  m_state->m_numPatterns=int(input->readULong(2));
1001
1.38k
  if (m_state->m_numPatterns!=120)
1002
1.38k
    f << "num[patterns]=" << m_state->m_numPatterns << ",";
1003
1.38k
  ascii().addDelimiter(input->tell(),'|');
1004
1.38k
  input->seek(pos+58, librevenge::RVNG_SEEK_SET);
1005
1.38k
  ascii().addPos(pos);
1006
1.38k
  ascii().addNote(f.str().c_str());
1007
1008
1.38k
  pos=input->tell();
1009
1.38k
  f.str("");
1010
1.38k
  f << "Document-1:";
1011
1.38k
  int val=int(input->readULong(2));
1012
1.38k
  m_state->m_numShapes=int(input->readULong(2));
1013
1.38k
  f << "num[shapes]=" << m_state->m_numShapes << ",";
1014
1.38k
  if (val!=m_state->m_numShapes)
1015
892
    f << "max[shapes]=" << val << ",";
1016
1.38k
  val=int(input->readULong(2));
1017
1.38k
  f << "f0=" << val << ","; // small number
1018
1.38k
  ascii().addDelimiter(input->tell(),'|');
1019
1.38k
  input->seek(pos+30, librevenge::RVNG_SEEK_SET);
1020
1.38k
  ascii().addPos(pos);
1021
1.38k
  ascii().addNote(f.str().c_str());
1022
1023
1.38k
  pos=input->tell();
1024
1.38k
  f.str("");
1025
1.38k
  f << "Document-2:";
1026
13.8k
  for (int i=0; i<9; ++i) { // f0=-1|1, f1=1|5, f2=0|1,f3=0|2, f7=-1000|-2000
1027
12.4k
    val=int(input->readLong(2));
1028
12.4k
    int const expected[]= {-1,1,0,0,1,0,0, -1000, -1000};
1029
12.4k
    if (val==expected[i])
1030
1.45k
      continue;
1031
11.0k
    if (i==4) {
1032
1.36k
      m_state->m_numLayers=val;
1033
1.36k
      f << "N[layer]=" << val << ",";
1034
1.36k
    }
1035
9.67k
    else if (i==6) {
1036
1.09k
      m_state->m_numViews=val;
1037
1.09k
      f << "N[view]=" << val << ",";
1038
1.09k
    }
1039
8.58k
    else
1040
8.58k
      f << "f" << i << "=" << val << ",";
1041
11.0k
  }
1042
1.38k
  if (version()==2) {
1043
375
    librevenge::RVNGString text;
1044
375
    if (readString(text, 64)) // find "1page Grp B&W"
1045
256
      f << text.cstr() << ",";
1046
119
    else
1047
119
      f << "###string,";
1048
375
  }
1049
1.01k
  else // something like 0a40800...0
1050
1.01k
    ascii().addDelimiter(input->tell(),'|');
1051
1.38k
  input->seek(pos+18+64, librevenge::RVNG_SEEK_SET);
1052
1.38k
  ascii().addPos(pos);
1053
1.38k
  ascii().addNote(f.str().c_str());
1054
1.38k
  return true;
1055
1.38k
}
1056
1057
bool CanvasParser::readMacroNames()
1058
1.38k
{
1059
1.38k
  auto input=getInput();
1060
1.38k
  long pos=input ? input->tell() : 0;
1061
1.38k
  if (!input || !input->checkPosition(pos+32*20)) {
1062
0
    MWAW_DEBUG_MSG(("CanvasParser::readMacroNames: file is too short\n"));
1063
0
    return false;
1064
0
  }
1065
1066
1.38k
  libmwaw::DebugStream f;
1067
45.8k
  for (int i=0; i<32; ++i) {
1068
44.4k
    pos=input->tell();
1069
44.4k
    f.str("");
1070
44.4k
    f << "Entries(Macro)[" << i << "]:";
1071
44.4k
    librevenge::RVNGString text;
1072
44.4k
    if (readString(text, 20, true)) {
1073
30.0k
      if (text.empty()) {
1074
21.1k
        ascii().addPos(pos);
1075
21.1k
        ascii().addNote("_");
1076
21.1k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1077
21.1k
        continue;
1078
21.1k
      }
1079
8.90k
      f << "name=" << text.cstr() << ",";
1080
8.90k
    }
1081
14.3k
    else
1082
14.3k
      f << "##name,";
1083
23.2k
    ascii().addPos(pos);
1084
23.2k
    ascii().addNote(f.str().c_str());
1085
23.2k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1086
23.2k
  }
1087
1.38k
  return true;
1088
1.38k
}
1089
1090
bool CanvasParser::readUnknownZoneHeader()
1091
1.38k
{
1092
1.38k
  auto input=getInput();
1093
1.38k
  long pos=input ? input->tell() : 0;
1094
1.38k
  if (!input || !input->checkPosition(pos+28)) {
1095
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZoneHeader: file is too short\n"));
1096
0
    return false;
1097
0
  }
1098
1099
1.38k
  libmwaw::DebugStream f;
1100
1.38k
  f << "Entries(ZoneH):";
1101
1.38k
  ascii().addPos(pos);
1102
1.38k
  ascii().addNote(f.str().c_str());
1103
1.38k
  input->seek(pos+28, librevenge::RVNG_SEEK_SET);
1104
1.38k
  return true;
1105
1.38k
}
1106
1107
bool CanvasParser::readUnknownZone0()
1108
1.38k
{
1109
1.38k
  auto input=getInput();
1110
1.38k
  long pos=input ? input->tell() : 0;
1111
1.38k
  if (!input || !input->checkPosition(pos+252)) {
1112
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone0: file is too short\n"));
1113
0
    return false;
1114
0
  }
1115
1116
1.38k
  libmwaw::DebugStream f;
1117
1.38k
  f << "Entries(Zone0):";
1118
1.38k
  int val=int(input->readLong(2));
1119
1.38k
  if (val!=-1) // or 5
1120
1.30k
    f << "f0=" << val << ",";
1121
29.1k
  for (int i=0; i<20; ++i) { // f1=0|30, f7=f9=0|8000, f12=0|1, f14=f19=0|5, f16=f17=0|20, f20=0|29
1122
27.7k
    val=int(input->readULong(2));
1123
27.7k
    if (!val) continue;
1124
20.8k
    if (val<0x1000)
1125
7.49k
      f << "f" << i+1 << "=" << val << ",";
1126
13.3k
    else
1127
13.3k
      f << "f" << i+1 << "=" << std::hex << val << std::dec << ",";
1128
20.8k
  }
1129
4.16k
  for (int st=0; st<2; ++st) {
1130
2.77k
    unsigned char col[3];
1131
8.32k
    for (auto &c : col) c=(unsigned char)(input->readULong(2)>>8);
1132
2.77k
    MWAWColor color(col[0],col[1],col[2]);
1133
2.77k
    if (color!=MWAWColor::black())
1134
2.30k
      f << "col" << st << "=" << color << ",";
1135
2.77k
  }
1136
1.38k
  f << "id=" << std::hex << input->readULong(4) << std::dec << ",";
1137
1.38k
  ascii().addPos(pos);
1138
1.38k
  ascii().addNote(f.str().c_str());
1139
1140
1.38k
  pos=input->tell();
1141
1.38k
  f.str("");
1142
1.38k
  f << "Zone0-1:";
1143
13.8k
  for (int i=0; i<9; ++i) { // f0=3|5|4e, f1=1
1144
12.4k
    val=int(input->readULong(2));
1145
12.4k
    if (!val) continue;
1146
9.31k
    if (val<0x1000)
1147
3.47k
      f << "f" << i+1 << "=" << val << ",";
1148
5.84k
    else
1149
5.84k
      f << "f" << i+1 << "=" << std::hex << val << std::dec << ",";
1150
9.31k
  }
1151
1.38k
  librevenge::RVNGString text;
1152
1.38k
  if (readString(text, 20))
1153
763
    f << "name=" << text.cstr() << ","; // Layer
1154
625
  else
1155
625
    f << "###name,";
1156
1.38k
  input->seek(pos+18+20, librevenge::RVNG_SEEK_SET);
1157
1.38k
  ascii().addPos(pos);
1158
1.38k
  ascii().addNote(f.str().c_str());
1159
1160
1.38k
  pos=input->tell();
1161
1.38k
  f.str("");
1162
1.38k
  f << "Zone0-2:";
1163
1.38k
  f << "font=[";
1164
1.38k
  f << "id=" << input->readULong(2) << ",";
1165
1.38k
  val=int(input->readULong(2));
1166
1.38k
  if (val) f << "fl=" << std::hex << val << std::dec << ",";
1167
1.38k
  f << "sz=" << input->readULong(2) << ",";
1168
1.38k
  f << "],";
1169
51.3k
  for (int i=0; i<36; ++i) { // f3=-2, f7=0|1, f11=0|28, f13=0|18, f15=0|8, f35=0|-16
1170
49.9k
    val=int(input->readLong(2));
1171
49.9k
    if (!val) continue;
1172
36.7k
    f << "f" << i << "=" << val << ",";
1173
36.7k
  }
1174
1.38k
  ascii().addPos(pos);
1175
1.38k
  ascii().addNote(f.str().c_str());
1176
1177
1.38k
  pos=input->tell();
1178
1.38k
  f.str("");
1179
1.38k
  f << "Zone0-3:";
1180
11.1k
  for (int i=0; i<7; ++i) {
1181
9.71k
    val=int(input->readLong(2));
1182
9.71k
    int const expected[]= {-50,16, -26,0,0,0,0};
1183
9.71k
    if (val==expected[i]) continue;
1184
8.27k
    f << "f" << i << "=" << val << ",";
1185
8.27k
  }
1186
4.16k
  for (int st=0; st<2; ++st) {
1187
2.77k
    int dim[4];
1188
11.1k
    for (auto &d : dim) d=int(input->readLong(2));
1189
2.77k
    if (dim[0]!=dim[2])
1190
1.67k
      f << "box" << st << "=" << MWAWBox2i(MWAWVec2i(dim[0],dim[1]),MWAWVec2i(dim[2],dim[3])) << ",";
1191
2.77k
  }
1192
18.0k
  for (int i=0; i<12; ++i) {
1193
16.6k
    val=int(input->readLong(2));
1194
16.6k
    int const expected[]= {1,16,0,3,1,0,0x48 /* or 4b*/, 0, 1, 0, 1, 0};
1195
16.6k
    if (val==expected[i]) continue;
1196
14.7k
    f << "g" << i << "=" << val << ",";
1197
14.7k
  }
1198
1.38k
  if (readString(text, 20)) // checkme: in v3.5 windows, probably junk
1199
799
    f << "name=" << text.cstr() << ",";
1200
589
  else
1201
589
    f << "###name,";
1202
1.38k
  input->seek(pos+14+16+24+20, librevenge::RVNG_SEEK_SET);
1203
4.16k
  for (int i=0; i<2; ++i) {
1204
2.77k
    val=int(input->readLong(2));
1205
2.77k
    if (!val) continue;
1206
2.05k
    f << "overlap[" << (i==0 ? "H" : "V") << "]=" << val << ",";
1207
2.05k
  }
1208
1.38k
  ascii().addPos(pos);
1209
1.38k
  ascii().addNote(f.str().c_str());
1210
1.38k
  return true;
1211
1.38k
}
1212
1213
bool CanvasParser::readBrushes()
1214
0
{
1215
0
  auto input=getInput();
1216
0
  if (!input) {
1217
0
    MWAW_DEBUG_MSG(("CanvasParser::readBrushes: file is too short\n"));
1218
0
    return false;
1219
0
  }
1220
1221
0
  long pos=input->tell();
1222
0
  libmwaw::DebugStream f;
1223
0
  f << "Entries(Brush):";
1224
0
  ascii().addPos(pos);
1225
0
  ascii().addNote(f.str().c_str());
1226
1227
0
  bool const isWindows=isWindowsFile();
1228
0
  if (!isWindows) {
1229
0
    for (size_t i=0 ; i<m_state->m_brushLengths.size() ; ++i) {
1230
0
      auto len=m_state->m_brushLengths[i];
1231
0
      if (!len) continue;
1232
0
      if (long(len)<0 || !decode(long(len))) {
1233
0
        MWAW_DEBUG_MSG(("CanvasParser::readBrushes: can not decode the input %d\n", int(i)));
1234
0
        return false;
1235
0
      }
1236
0
      pos=input->tell();
1237
0
      f.str("");
1238
0
      f << "Brush-" << i << ":";
1239
0
      int N=int(input->readULong(2));
1240
0
      if (!input->checkPosition(pos+2+4*N) || 2+4*N>long(len)) {
1241
0
        MWAW_DEBUG_MSG(("CanvasParser::readBrushes: can not read a brush\n"));
1242
0
        return false;
1243
0
      }
1244
0
      input->seek(pos+long(len), librevenge::RVNG_SEEK_SET);
1245
0
      ascii().addPos(pos);
1246
0
      ascii().addNote(f.str().c_str());
1247
0
    }
1248
0
    return true;
1249
0
  }
1250
1251
  // windows file have more brushes, the first 36 are generally stored by pair, the last one are stored one by one ?
1252
0
  for (size_t i=0 ; i<m_state->m_brushLengths.size() ; ++i) {
1253
0
    auto len=m_state->m_brushLengths[i];
1254
0
    if (i+1<m_state->m_brushLengths.size())
1255
0
      len+=m_state->m_brushLengths[i+1];
1256
0
    if (!len) {
1257
0
      ++i;
1258
0
      continue;
1259
0
    }
1260
0
    if (i>=36 || len>256 || long(len)<0 || !decode(long(len))) { // check me: nbig blocks are stored one by one, what is the limit ?
1261
0
      len=m_state->m_brushLengths[i];
1262
0
      if (long(len)<0 || !decode(long(len))) {
1263
0
        MWAW_DEBUG_MSG(("CanvasParser::readBrushes: can not decode the input %d\n", int(i)));
1264
0
        return false;
1265
0
      }
1266
0
      pos=input->tell();
1267
0
      f.str("");
1268
0
      f << "Brush-" << i << ":";
1269
0
      ascii().addPos(pos);
1270
0
      ascii().addNote(f.str().c_str());
1271
1272
0
      input->seek(pos+long(len), librevenge::RVNG_SEEK_SET);
1273
0
      continue;
1274
0
    }
1275
0
    pos=input->tell();
1276
0
    f.str("");
1277
0
    f << "Brush-" << i << ":";
1278
0
    ascii().addPos(pos);
1279
0
    ascii().addNote(f.str().c_str());
1280
1281
0
    f.str("");
1282
0
    f << "Brush-" << ++i << ":";
1283
0
    ascii().addPos(pos+long(m_state->m_brushLengths[i-1]));
1284
0
    ascii().addNote(f.str().c_str());
1285
1286
0
    input->seek(pos+long(len), librevenge::RVNG_SEEK_SET);
1287
0
  }
1288
0
  return true;
1289
0
}
1290
1291
bool CanvasParser::readSprays()
1292
0
{
1293
0
  auto input=getInput();
1294
0
  for (auto const &l : m_state->m_sprayLengths) {
1295
0
    if (!l) continue;
1296
0
    if (long(l)<0 || !decode(long(l))) {
1297
0
      MWAW_DEBUG_MSG(("CanvasParser::readSprays: can not decode the input\n"));
1298
0
      return false;
1299
0
    }
1300
0
    long pos=input->tell();
1301
0
    if (long(l)<=0 || !input->checkPosition(pos+long(l))) {
1302
0
      MWAW_DEBUG_MSG(("CanvasParser::readSprays: can not read a spray\n"));
1303
0
      return false;
1304
0
    }
1305
    /* spray:
1306
       ID dSz=0006 bdBox=ffefffef00100010 ymin,xmin ymax,xmax
1307
       then dY*dSz
1308
       ID dSz=0004 bdBox=fff7fff30007000b
1309
    */
1310
0
    ascii().addPos(pos);
1311
0
    ascii().addNote("Spray:");
1312
0
    input->seek(pos+long(l), librevenge::RVNG_SEEK_SET);
1313
0
  }
1314
0
  return true;
1315
0
}
1316
1317
bool CanvasParser::readFormats()
1318
1.38k
{
1319
1.38k
  auto input=getInput();
1320
1.38k
  long pos=input ? input->tell() : 0;
1321
1.38k
  if (!input || !input->checkPosition(pos+8+6*44)) {
1322
0
    MWAW_DEBUG_MSG(("CanvasParser::readFormats: file is too short\n"));
1323
0
    return false;
1324
0
  }
1325
1326
1.38k
  libmwaw::DebugStream f;
1327
1.38k
  f << "Entries(Format):";
1328
1.38k
  input->seek(pos+8, librevenge::RVNG_SEEK_SET);
1329
1.38k
  ascii().addPos(pos);
1330
1.38k
  ascii().addNote(f.str().c_str());
1331
9.71k
  for (int u=0; u<6; ++u) {
1332
8.32k
    pos=input->tell();
1333
8.32k
    f.str("");
1334
8.32k
    f << "Format-" << u << ":";
1335
8.32k
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
1336
8.32k
    ascii().addDelimiter(input->tell(),'|');
1337
41.6k
    for (int i=0; i<4; ++i) {
1338
33.3k
      int val=int(input->readULong(4));
1339
33.3k
      if (val!=0x10000)
1340
33.1k
        f << "dim" << i << "=" << double(val)/double(0x10000) << ",";
1341
33.3k
    }
1342
8.32k
    librevenge::RVNGString text;
1343
8.32k
    if (readString(text, 20))
1344
4.68k
      f << "name=" << text.cstr() << ",";
1345
3.64k
    else
1346
3.64k
      f << "###name,";
1347
8.32k
    input->seek(pos+44, librevenge::RVNG_SEEK_SET);
1348
8.32k
    ascii().addPos(pos);
1349
8.32k
    ascii().addNote(f.str().c_str());
1350
8.32k
  }
1351
1.38k
  return true;
1352
1.38k
}
1353
1354
bool CanvasParser::readGrids()
1355
1.38k
{
1356
1.38k
  auto input=getInput();
1357
1.38k
  long pos=input ? input->tell() : 0;
1358
1.38k
  if (!input || !input->checkPosition(pos+18*20)) {
1359
0
    MWAW_DEBUG_MSG(("CanvasParser::readGrids: file is too short\n"));
1360
0
    return false;
1361
0
  }
1362
1363
1.38k
  libmwaw::DebugStream f;
1364
5.55k
  for (int i=0; i<3; ++i) {
1365
4.16k
    pos=input->tell();
1366
4.16k
    f.str("");
1367
4.16k
    f << "Entries(Grid)[" << i << "]:";
1368
4.16k
    librevenge::RVNGString text;
1369
4.16k
    if (readString(text, 20)) {
1370
2.37k
      if (text.empty()) {
1371
2.09k
        ascii().addPos(pos);
1372
2.09k
        ascii().addNote("_");
1373
2.09k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1374
2.09k
        continue;
1375
2.09k
      }
1376
273
      f << "name=" << text.cstr() << ",";
1377
273
    }
1378
1.79k
    else
1379
1.79k
      f << "###name,";
1380
2.06k
    ascii().addPos(pos);
1381
2.06k
    ascii().addNote(f.str().c_str());
1382
2.06k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1383
2.06k
  }
1384
1.38k
  pos=input->tell();
1385
1.38k
  f.str("");
1386
1.38k
  f << "Entries(Spray):lengths=[";
1387
29.1k
  for (int i=0; i<20; ++i) {
1388
27.7k
    m_state->m_sprayLengths.push_back(input->readULong(4));
1389
27.7k
    if (m_state->m_sprayLengths.back())
1390
22.8k
      f << m_state->m_sprayLengths.back() << ",";
1391
4.94k
    else
1392
4.94k
      f << "_,";
1393
27.7k
  }
1394
1.38k
  f << "],";
1395
1.38k
  ascii().addPos(pos);
1396
1.38k
  ascii().addNote(f.str().c_str());
1397
16.6k
  for (int i=0; i<11; ++i) {
1398
    // checkme: make no sense
1399
15.2k
    pos=input->tell();
1400
15.2k
    f.str("");
1401
15.2k
    f << "Entries(Grid)[" << i+3 << "]:";
1402
15.2k
    librevenge::RVNGString text;
1403
15.2k
    if (readString(text, 20)) {
1404
8.72k
      if (text.empty()) {
1405
7.72k
        ascii().addPos(pos);
1406
7.72k
        ascii().addNote("_");
1407
7.72k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1408
7.72k
        continue;
1409
7.72k
      }
1410
1.00k
      f << "name=" << text.cstr() << ",";
1411
1.00k
    }
1412
6.54k
    else
1413
6.54k
      f << "###name,";
1414
7.54k
    ascii().addPos(pos);
1415
7.54k
    ascii().addNote(f.str().c_str());
1416
7.54k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1417
7.54k
  }
1418
1.38k
  return true;
1419
1.38k
}
1420
1421
bool CanvasParser::readUnknownZone1()
1422
1.38k
{
1423
1.38k
  auto input=getInput();
1424
1.38k
  long pos=input ? input->tell() : 0;
1425
1.38k
  if (!input || !input->checkPosition(pos+162)) {
1426
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone1: file is too short\n"));
1427
0
    return false;
1428
0
  }
1429
1430
1.38k
  libmwaw::DebugStream f;
1431
1.38k
  f << "Entries(Zone1):";
1432
1.38k
  int val;
1433
26.3k
  for (int i=0; i<18; ++i) {
1434
24.9k
    val=int(input->readULong(2));
1435
24.9k
    if (!val) continue;
1436
18.9k
    f << "f" << i << "=" << val << ",";
1437
18.9k
  }
1438
23.5k
  for (int i=0; i<16; ++i) {
1439
22.2k
    val=int(input->readLong(2));
1440
22.2k
    int const expected[]= { 1, 0, 1, 1, 10, 0, 10, 0, 100 /* or 10000 */, 1,
1441
22.2k
                            2, 1/* or 4*/, 0/*or 1*/, 0, 1, 1
1442
22.2k
                          };
1443
22.2k
    if (val==expected[i]) continue;
1444
20.3k
    f << "g" << i << "=" << val << ",";
1445
20.3k
  }
1446
13.8k
  for (int i=0; i<9; ++i) {
1447
12.4k
    val=int(input->readLong(4));
1448
12.4k
    int const expected[]= { 100 /* or 120*/, 100, 100, 1 /* or 4*/, 1, 1, 1, 1, 1 };
1449
12.4k
    if (val==65536*expected[i]) continue;
1450
12.4k
    f << "h" << i << "=" << double(val)/65536. << ",";
1451
12.4k
  }
1452
1.38k
  ascii().addPos(pos);
1453
1.38k
  ascii().addNote(f.str().c_str());
1454
1.38k
  pos=input->tell();
1455
1.38k
  f.str("");
1456
1.38k
  f << "Zone1-1:";
1457
15.2k
  for (int i=0; i<10; ++i) { // f5=small number, f6/f7: related to spray(a list of bit?) f14: related to brush?
1458
13.8k
    val=int(input->readLong(2));
1459
13.8k
    int const expected[]= { 50, 10, 0 /* or 1*/, 0, 0, 0, 2, 0, 0, 0};
1460
13.8k
    if (val==expected[i]) continue;
1461
11.5k
    f << "f" << i << "=" << val << ",";
1462
11.5k
  }
1463
27.7k
  for (int i=0; i<19; ++i) { // f27= almost always 1, f28=almost always 3
1464
26.3k
    val=int(input->readLong(2));
1465
26.3k
    if (!val) continue;
1466
20.1k
    f << "f" << i+10 << "=" << val << ",";
1467
20.1k
  }
1468
1.38k
  ascii().addPos(pos);
1469
1.38k
  ascii().addNote(f.str().c_str());
1470
1.38k
  return true;
1471
1.38k
}
1472
1473
bool CanvasParser::readUnknownZone2()
1474
0
{
1475
0
  if (!decode(96)) {
1476
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone2: can not decode the input\n"));
1477
0
    return false;
1478
0
  }
1479
0
  auto input=getInput();
1480
0
  long pos=input ? input->tell() : 0;
1481
0
  if (!input || !input->checkPosition(pos+96)) {
1482
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone2: file is too short\n"));
1483
0
    return false;
1484
0
  }
1485
1486
0
  libmwaw::DebugStream f;
1487
0
  f << "Entries(Zone2):";
1488
0
  ascii().addPos(pos);
1489
0
  ascii().addNote(f.str().c_str());
1490
0
  input->seek(pos+96, librevenge::RVNG_SEEK_SET);
1491
0
  return true;
1492
0
}
1493
1494
bool CanvasParser::readUnknownZone3()
1495
0
{
1496
0
  if (long(m_state->m_lengths[4])==0)
1497
0
    return true;
1498
0
  if (long(m_state->m_lengths[4])<0 || !decode(long(m_state->m_lengths[4]))) {
1499
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone3: can not decode the input\n"));
1500
0
    return false;
1501
0
  }
1502
1503
  // 003a07000b010202080205030a040e0400050605030609060c0607070f0705080908000903090c09060a0a0a0e0a040b010c070c0a0c0d0d040e080f
1504
0
  auto input=getInput();
1505
0
  long pos=input ? input->tell() : 0;
1506
0
  int sz=input ? int(input->readULong(2)) : 0;
1507
0
  if (!input || !input->checkPosition(pos+2+sz) || 2+sz>long(m_state->m_lengths[4])) {
1508
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone3: file is too short\n"));
1509
0
    return false;
1510
0
  }
1511
1512
0
  libmwaw::DebugStream f;
1513
0
  f << "Entries(Zone3):";
1514
0
  ascii().addPos(pos);
1515
0
  ascii().addNote(f.str().c_str());
1516
0
  input->seek(pos+long(m_state->m_lengths[4]), librevenge::RVNG_SEEK_SET);
1517
0
  return true;
1518
0
}
1519
1520
bool CanvasParser::readUnknownZone4()
1521
0
{
1522
0
  if (!decode(486)) {
1523
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone4: can not decode data\n"));
1524
0
    return false;
1525
0
  }
1526
0
  MWAWInputStreamPtr input = getInput();
1527
0
  long pos=input->tell();
1528
0
  long endPos=pos+486;
1529
0
  if (!input->checkPosition(endPos)) {
1530
0
    MWAW_DEBUG_MSG(("CanvasParser::readUnknownZone4: zone seems too short\n"));
1531
0
    return false;
1532
0
  }
1533
0
  libmwaw::DebugStream f;
1534
0
  f << "Entries(Zone4):";
1535
0
  ascii().addPos(pos);
1536
0
  ascii().addNote(f.str().c_str());
1537
1538
0
  int val=int(input->readLong(2)); // small number
1539
0
  if (val) f << "f0=" << val << ",";
1540
0
  for (int i=0; i<2; ++i) { // f1=-1|25, f2=0|8
1541
0
    val=int(input->readLong(1));
1542
0
    if (val) f << "f" << i+1 << "=" << val << ",";
1543
0
  }
1544
0
  int dim[2];
1545
0
  for (auto &d : dim) d=int(input->readLong(2));
1546
0
  m_state->m_pageDimension=MWAWVec2i(dim[0], dim[1]);
1547
0
  f << "dim=" << m_state->m_pageDimension << ",";
1548
0
  ascii().addDelimiter(input->tell(),'|');
1549
0
  ascii().addPos(pos);
1550
0
  ascii().addNote(f.str().c_str());
1551
0
  ascii().addPos(pos+200);
1552
0
  ascii().addNote("Zone4-0");
1553
0
  ascii().addPos(pos+350);
1554
0
  ascii().addNote("Zone4-1");
1555
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1556
0
  return true;
1557
0
}
1558
1559
bool CanvasParser::readViews()
1560
0
{
1561
0
  if (long(m_state->m_lengths[3])<0 || (m_state->m_lengths[3] && !decode(long(m_state->m_lengths[3])))) {
1562
0
    MWAW_DEBUG_MSG(("CanvasParser::readViews: can not decode the input\n"));
1563
0
    return false;
1564
0
  }
1565
0
  MWAWInputStreamPtr input = getInput();
1566
0
  long pos=input->tell();
1567
0
  long endPos=pos+long(m_state->m_lengths[3]);
1568
0
  if (!input->checkPosition(endPos) ||
1569
0
      long(m_state->m_lengths[3])/26 < m_state->m_numViews) {
1570
0
    MWAW_DEBUG_MSG(("CanvasParser::readViews: zone seems too short\n"));
1571
0
    return false;
1572
0
  }
1573
0
  libmwaw::DebugStream f;
1574
0
  f << "Entries(View):";
1575
0
  ascii().addPos(pos);
1576
0
  ascii().addNote(f.str().c_str());
1577
1578
0
  for (int i=0; i<m_state->m_numViews; ++i) {
1579
0
    pos=input->tell();
1580
0
    f.str("");
1581
0
    f << "View-" << i << ":";
1582
    // 3 int:  a position + ?
1583
0
    input->seek(pos+6, librevenge::RVNG_SEEK_SET);
1584
0
    ascii().addDelimiter(input->tell(),'|');
1585
0
    librevenge::RVNGString text;
1586
0
    if (readString(text, 20))
1587
0
      f << text.cstr() << ",";
1588
0
    else {
1589
0
      f << "###name,";
1590
0
      MWAW_DEBUG_MSG(("CanvasParser::readViews: bad name\n"));
1591
0
    }
1592
0
    input->seek(pos+26, librevenge::RVNG_SEEK_SET);
1593
0
    ascii().addPos(pos);
1594
0
    ascii().addNote(f.str().c_str());
1595
0
  }
1596
0
  if (input->tell()!=endPos && m_state->m_numViews) {
1597
0
    ascii().addPos(input->tell());
1598
0
    ascii().addNote("View-End:");
1599
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1600
0
  }
1601
1602
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1603
0
  ascii().addPos(pos);
1604
0
  ascii().addNote(f.str().c_str());
1605
1606
0
  return true;
1607
0
}
1608
1609
bool CanvasParser::readEndV3()
1610
0
{
1611
0
  if (!decode(40)) {
1612
0
    MWAW_DEBUG_MSG(("CanvasParser::readEndV3: can not decode the input zone\n"));
1613
0
    return false;
1614
0
  }
1615
0
  MWAWInputStreamPtr input = getInput();
1616
0
  long pos=input->tell();
1617
0
  if (!input->checkPosition(pos+40)) {
1618
0
    MWAW_DEBUG_MSG(("CanvasParser::readEndV3: zone seems too short\n"));
1619
0
    return false;
1620
0
  }
1621
0
  libmwaw::DebugStream f;
1622
0
  f << "Entries(EndV3):lengths=[";
1623
0
  long lengths[10];
1624
0
  for (auto &l : lengths) {
1625
0
    l=long(input->readULong(4));
1626
0
    if (l)
1627
0
      f << l << ",";
1628
0
    else
1629
0
      f << "_,";
1630
0
  }
1631
0
  f << "],";
1632
0
  ascii().addPos(pos);
1633
0
  ascii().addNote(f.str().c_str());
1634
1635
0
  for (int i=0; i<10; ++i) {
1636
0
    if (lengths[i]==0)
1637
0
      continue;
1638
0
    if (!decode(lengths[i])) {
1639
0
      MWAW_DEBUG_MSG(("CanvasParser::readEndV3: can not decode the zone %d\n", i));
1640
0
      return false;
1641
0
    }
1642
0
    pos=input->tell();
1643
0
    int const expectedLengths[]= {60, 46, 34, 8, 132,
1644
0
                                  0, 0, 0, 0, 0
1645
0
                                 };
1646
0
    int const dataLength=expectedLengths[i];
1647
0
    long endPos=pos+lengths[i];
1648
0
    if (lengths[i]<0 || endPos<=pos || !input->checkPosition(endPos) ||
1649
0
        (dataLength && lengths[i]<dataLength)) {
1650
0
      MWAW_DEBUG_MSG(("CanvasParser::readEndV3: zone %d seems too short\n", i));
1651
0
      ascii().addPos(pos);
1652
0
      ascii().addNote("Entries(Bad):###");
1653
0
      return false;
1654
0
    }
1655
0
    bool done=false;
1656
0
    switch (i) {
1657
0
    case 0:
1658
0
      done=m_styleManager->readDashes(int(lengths[i]/60), true);
1659
0
      break;
1660
0
    case 4:
1661
0
      done=m_styleManager->readFonts(int(lengths[i]/132));
1662
0
      break;
1663
0
    default:
1664
0
      break;
1665
0
    }
1666
1667
0
    char const *wh[]= {"Dash", nullptr, nullptr, nullptr, "Font",
1668
0
                       nullptr, nullptr, nullptr, nullptr, nullptr
1669
0
                      };
1670
0
    std::string what;
1671
0
    if (wh[i])
1672
0
      what=wh[i];
1673
0
    else {
1674
0
      std::stringstream s;
1675
0
      s << "ZoneA" << i;
1676
0
      what=s.str();
1677
0
    }
1678
0
    if (done) {
1679
0
      if (input->tell()!=endPos) {
1680
0
        MWAW_DEBUG_MSG(("CanvasParser::readEndV3: find extra data for zone %d\n", i));
1681
0
        f.str("");
1682
0
        f << what << "-extra:###";
1683
0
        ascii().addPos(input->tell());
1684
0
        ascii().addNote(f.str().c_str());
1685
0
        input->seek(endPos, librevenge::RVNG_SEEK_SET);
1686
0
      }
1687
0
      continue;
1688
0
    }
1689
0
    f.str("");
1690
0
    f << "Entries(" << what << "):";
1691
0
    ascii().addPos(pos);
1692
0
    ascii().addNote(f.str().c_str());
1693
0
    if (dataLength>0) {
1694
0
      int n=0;
1695
0
      while (input->tell()+dataLength<=endPos) {
1696
0
        pos=input->tell();
1697
0
        f.str("");
1698
0
        f << what << "-" << n++ << ":";
1699
0
        ascii().addPos(pos);
1700
0
        ascii().addNote(f.str().c_str());
1701
0
        input->seek(pos+dataLength, librevenge::RVNG_SEEK_SET);
1702
0
      }
1703
0
      if (input->tell()!=endPos) {
1704
0
        f.str("");
1705
0
        f << what << ":extra##";
1706
0
        ascii().addPos(pos);
1707
0
        ascii().addNote(f.str().c_str());
1708
0
      }
1709
0
    }
1710
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1711
0
  }
1712
0
  return true;
1713
0
}
1714
1715
bool CanvasParser::readString(librevenge::RVNGString &string, int maxSize, bool canBeCString)
1716
75.3k
{
1717
75.3k
  return readString(getInput(), string, maxSize, canBeCString);
1718
75.3k
}
1719
1720
bool CanvasParser::readString(MWAWInputStreamPtr input, librevenge::RVNGString &string, int maxSize, bool canBeCString)
1721
75.3k
{
1722
75.3k
  string.clear();
1723
75.3k
  if (!input) {
1724
0
    MWAW_DEBUG_MSG(("CanvasParser::readString: can not find the input\n"));
1725
0
    return false;
1726
0
  }
1727
75.3k
  bool const isWindows=isWindowsFile();
1728
75.3k
  auto fontConverter=getFontConverter();
1729
75.3k
  int defaultFont=isWindows ? fontConverter->getId("CP1252") : 3;
1730
75.3k
  if (isWindows && canBeCString) {
1731
13.2k
    int n=0;
1732
130k
    while (!input->isEnd() && (maxSize<=0 || n<maxSize)) {
1733
125k
      char c=char(input->readULong(1));
1734
125k
      if (c==0)
1735
8.32k
        break;
1736
117k
      ++n;
1737
117k
      int unicode = fontConverter->unicode(defaultFont, static_cast<unsigned char>(c));
1738
117k
      if (unicode>0)
1739
80.9k
        libmwaw::appendUnicode(uint32_t(unicode), string);
1740
36.4k
      else {
1741
36.4k
        MWAW_DEBUG_MSG(("CanvasParser::readString: find unknown unicode for char=%d\n", int(c)));
1742
36.4k
      }
1743
117k
    }
1744
13.2k
    return true;
1745
13.2k
  }
1746
62.1k
  int sSz=int(input->readULong(1));
1747
62.1k
  if ((maxSize<=0 || sSz<maxSize) && input->checkPosition(input->tell()+sSz)) {
1748
91.8k
    for (int ch=0; ch<sSz; ++ch) {
1749
62.6k
      char c=char(input->readULong(1));
1750
62.6k
      if (c==0)
1751
5.23k
        break;
1752
57.4k
      int unicode = fontConverter->unicode(defaultFont, static_cast<unsigned char>(c));
1753
57.4k
      if (unicode>0)
1754
12.8k
        libmwaw::appendUnicode(uint32_t(unicode), string);
1755
44.6k
      else {
1756
44.6k
        MWAW_DEBUG_MSG(("CanvasParser::readString: find unknown unicode for char=%d\n", int(c)));
1757
44.6k
      }
1758
57.4k
    }
1759
34.4k
  }
1760
27.6k
  else {
1761
27.6k
    MWAW_DEBUG_MSG(("CanvasParser::readString: bad size=%d\n", sSz));
1762
27.6k
    return false;
1763
27.6k
  }
1764
34.4k
  return true;
1765
62.1k
}
1766
1767
// ------------------------------------------------------------
1768
// mac resource fork
1769
// ------------------------------------------------------------
1770
1771
bool CanvasParser::readPrintInfo(MWAWInputStreamPtr input, MWAWEntry const &entry, libmwaw::DebugFile &ascFile)
1772
0
{
1773
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
1774
0
    return false;
1775
0
  if (entry.length()<120) {
1776
0
    MWAW_DEBUG_MSG(("CanvasParser::readPrintInfo: the zone seems too small\n"));
1777
0
    return false;
1778
0
  }
1779
0
  entry.setParsed(true);
1780
0
  libmwaw::DebugStream f;
1781
0
  f << "Entries(PrintInfo)[" << entry.id() << "]:";
1782
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1783
0
  libmwaw::PrinterInfo info;
1784
0
  if (!info.read(input)) {
1785
0
    MWAW_DEBUG_MSG(("CanvasParser::readPrintInfo: can not read the zone length\n"));
1786
0
    f << "###";
1787
0
    ascFile.addPos(entry.begin()-4);
1788
0
    ascFile.addNote(f.str().c_str());
1789
0
    return false;
1790
0
  }
1791
0
  f << info;
1792
0
  MWAWVec2i paperSize = info.paper().size();
1793
0
  MWAWVec2i pageSize = info.page().size();
1794
0
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1795
0
      paperSize.x() <= 0 || paperSize.y() <= 0) {
1796
0
    f << "###";
1797
0
    ascFile.addPos(entry.begin()-4);
1798
0
    ascFile.addNote(f.str().c_str());
1799
0
    return false;
1800
0
  }
1801
1802
0
  if (entry.id()==10568) {
1803
    // define margin from print info
1804
0
    MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1805
0
    MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
1806
1807
    // move margin left | top
1808
0
    int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1809
0
    int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1810
0
    lTopMargin -= MWAWVec2i(decalX, decalY);
1811
0
    rBotMargin += MWAWVec2i(decalX, decalY);
1812
1813
    // decrease right | bottom
1814
0
    int rightMarg = rBotMargin.x() -10;
1815
0
    if (rightMarg < 0) rightMarg=0;
1816
0
    int botMarg = rBotMargin.y() -50;
1817
0
    if (botMarg < 0) botMarg=0;
1818
1819
0
    getPageSpan().setMarginTop(lTopMargin.y()/72.0);
1820
0
    getPageSpan().setMarginBottom(botMarg/72.0);
1821
0
    getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
1822
0
    getPageSpan().setMarginRight(rightMarg/72.0);
1823
0
    getPageSpan().setFormLength(paperSize.y()/72.);
1824
0
    getPageSpan().setFormWidth(paperSize.x()/72.);
1825
0
  }
1826
0
  else {
1827
0
    MWAW_DEBUG_MSG(("CanvasParser::readPrintInfo: find unexpected\n"));
1828
0
  }
1829
0
  if (entry.length()>124)
1830
0
    ascFile.addDelimiter(input->tell(),'|');
1831
0
  ascFile.addPos(entry.begin()-4);
1832
0
  ascFile.addNote(f.str().c_str());
1833
0
  return true;
1834
0
}
1835
1836
bool CanvasParser::readLPOL(MWAWInputStreamPtr input, MWAWEntry const &entry, libmwaw::DebugFile &ascFile)
1837
0
{
1838
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
1839
0
    return false;
1840
0
  if (entry.length()<2) {
1841
0
    MWAW_DEBUG_MSG(("CanvasParser::readLPOL: the zone seems too small\n"));
1842
0
    return false;
1843
0
  }
1844
0
  entry.setParsed(true);
1845
0
  libmwaw::DebugStream f;
1846
0
  f << "Entries(LPOL)[" << entry.id() << "]:";
1847
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1848
0
  int N=int(input->readULong(2));
1849
0
  if (2+4*N>entry.length()) {
1850
0
    f << "###N=" << N << ",";
1851
0
    MWAW_DEBUG_MSG(("CanvasParser::readLPOL: can not read the number of elements\n"));
1852
0
    ascFile.addPos(entry.begin()-4);
1853
0
    ascFile.addNote(f.str().c_str());
1854
0
    return false;
1855
0
  }
1856
0
  for (int i=0; i<N; ++i) {
1857
0
    f << "[";
1858
0
    for (int v=0; v<4; ++v) f << input->readLong(1) << ",";
1859
0
    f << "],";
1860
0
  }
1861
0
  if (input->tell()!=entry.end())
1862
0
    ascFile.addDelimiter(input->tell(),'|');
1863
0
  ascFile.addPos(entry.begin()-4);
1864
0
  ascFile.addNote(f.str().c_str());
1865
0
  return true;
1866
0
}
1867
1868
bool CanvasParser::readRSRCFileHeader(MWAWInputStreamPtr input, MWAWEntry const &entry, libmwaw::DebugFile &ascFile)
1869
0
{
1870
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
1871
0
    return false;
1872
0
  if (entry.length()<56) {
1873
0
    MWAW_DEBUG_MSG(("CanvasParser:readRSRCFileHeader: the zone seems too small\n"));
1874
0
    return false;
1875
0
  }
1876
0
  entry.setParsed(true);
1877
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1878
0
  libmwaw::DebugStream f;
1879
0
  f << "FileHeader[RSRC" << entry.id() << "]:";
1880
0
  f << "length?=[";
1881
0
  for (int i=0; i<13; ++i) {
1882
0
    auto length=input->readULong(4);
1883
0
    f << length << ",";
1884
0
  }
1885
0
  int val=int(input->readLong(2)); // v2: 100, v3: 104
1886
0
  switch (val) {
1887
0
  case 100:
1888
0
    f << "v2.0,";
1889
0
    break;
1890
0
  case 102:
1891
0
    f << "v2.1,";
1892
0
    break;
1893
0
  case 104:
1894
0
    f << "v3.0,";
1895
0
    break;
1896
0
  default:
1897
0
    f << "version=" << val << ",";
1898
0
    break;
1899
0
  }
1900
0
  val=int(input->readULong(2));
1901
0
  if (val!=1) f << "vers=" << val+1 << ",";
1902
1903
0
  if (input->tell()!=entry.end())
1904
0
    ascFile.addDelimiter(input->tell(),'|');
1905
0
  ascFile.addPos(entry.begin()-4);
1906
0
  ascFile.addNote(f.str().c_str());
1907
0
  return true;
1908
0
}
1909
1910
bool CanvasParser::readUsers(MWAWInputStreamPtr input, MWAWEntry const &entry, libmwaw::DebugFile &ascFile)
1911
0
{
1912
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
1913
0
    return false;
1914
0
  if (entry.length()<514) {
1915
0
    MWAW_DEBUG_MSG(("CanvasParser::readUsers: the zone seems too small\n"));
1916
0
    return false;
1917
0
  }
1918
0
  entry.setParsed(true);
1919
0
  libmwaw::DebugStream f;
1920
0
  f << "Entries(Users)[" << entry.id() << "]:";
1921
1922
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1923
0
  librevenge::RVNGString text;
1924
0
  if (readString(input, text, 64)) { // user name
1925
0
    if (!text.empty())
1926
0
      m_state->m_metaData.insert("meta:initial-creator", text);
1927
0
    f << text.cstr() << ",";
1928
0
  }
1929
0
  else {
1930
0
    f << "###name,";
1931
0
    MWAW_DEBUG_MSG(("CanvasParser::readUsers: bad user name\n"));
1932
0
  }
1933
0
  input->seek(entry.begin()+64,librevenge::RVNG_SEEK_SET);
1934
0
  ascFile.addDelimiter(input->tell(),'|');
1935
0
  input->seek(entry.begin()+128,librevenge::RVNG_SEEK_SET);
1936
0
  ascFile.addPos(entry.begin()-4);
1937
0
  ascFile.addNote(f.str().c_str());
1938
1939
0
  long pos=input->tell();
1940
0
  f.str("");
1941
0
  f << "Users-0:";
1942
0
  input->seek(pos+128,librevenge::RVNG_SEEK_SET);
1943
0
  ascFile.addPos(pos);
1944
0
  ascFile.addNote(f.str().c_str());
1945
1946
0
  pos=input->tell();
1947
0
  f.str("");
1948
0
  f << "Users-1:";
1949
0
  int val=int(input->readLong(2));
1950
0
  if (val) f << "f0=" << val << ",";
1951
0
  if (readString(input, text, 64)) // limits?
1952
0
    f << text.cstr() << ",";
1953
0
  else {
1954
0
    f << "###dir,";
1955
0
    MWAW_DEBUG_MSG(("CanvasParser::readUsers: bad dir\n"));
1956
0
  }
1957
0
  input->seek(pos+2+64,librevenge::RVNG_SEEK_SET);
1958
0
  ascFile.addDelimiter(input->tell(),'|');
1959
0
  input->seek(pos+128,librevenge::RVNG_SEEK_SET);
1960
0
  ascFile.addPos(pos);
1961
0
  ascFile.addNote(f.str().c_str());
1962
1963
0
  pos=input->tell();
1964
0
  f.str("");
1965
0
  f << "Users-2:";
1966
0
  input->seek(pos+130,librevenge::RVNG_SEEK_SET);
1967
0
  ascFile.addPos(pos);
1968
0
  ascFile.addNote(f.str().c_str());
1969
1970
0
  if (input->tell()!=entry.end())
1971
0
    ascFile.addDelimiter(input->tell(),'|');
1972
0
  return true;
1973
0
}
1974
1975
bool CanvasParser::readWindows(MWAWInputStreamPtr input, MWAWEntry const &entry, libmwaw::DebugFile &ascFile)
1976
0
{
1977
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
1978
0
    return false;
1979
0
  if (entry.length()<20) {
1980
0
    MWAW_DEBUG_MSG(("CanvasParser::readWindows: the zone seems too small\n"));
1981
0
    return false;
1982
0
  }
1983
0
  entry.setParsed(true);
1984
0
  libmwaw::DebugStream f;
1985
0
  f << "Entries(Windows)[" << entry.id() << "]:";
1986
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
1987
0
  int dim[4];
1988
0
  for (auto &d : dim) d=int(input->readLong(2));
1989
0
  f << "win=" << MWAWBox2i(MWAWVec2i(dim[0],dim[1]),MWAWVec2i(dim[2],dim[3])) << ",";
1990
0
  for (int i=0; i<6; ++i) { // f6=small number
1991
0
    int val=int(input->readLong(2));
1992
0
    if (val)
1993
0
      f << "f" << i << "=" << val << ",";
1994
0
  }
1995
0
  if (input->tell()!=entry.end())
1996
0
    ascFile.addDelimiter(input->tell(),'|');
1997
0
  ascFile.addPos(entry.begin()-4);
1998
0
  ascFile.addNote(f.str().c_str());
1999
0
  return true;
2000
0
}
2001
2002
// ------------------------------------------------------------
2003
// windows resource fork
2004
// ------------------------------------------------------------
2005
2006
bool CanvasParser::readRSRCWindowsFile()
2007
0
{
2008
0
  auto input=getInput();
2009
0
  if (!input)
2010
0
    return false;
2011
2012
0
  MWAWEntry entries[2];
2013
0
  for (int step=0; step<2; ++step) {
2014
0
    if (!m_state->m_decoder.append(4)) {
2015
0
      MWAW_DEBUG_MSG(("CanvasParser::readRSRCWindowsFile: zone5 can not retrieve the length of zone %dB\n", step));
2016
0
      return false;
2017
0
    }
2018
0
    input->recomputeStreamSize();
2019
0
    long pos=input->tell();
2020
0
    long sz=long(input->readULong(4));
2021
0
    long endPos=pos+4+sz;
2022
0
    if (sz<0 || !decode(sz) || !input->checkPosition(endPos)) {
2023
0
      MWAW_DEBUG_MSG(("CanvasParser::readRSRCWindowsFile: can not decode zone %dB\n", step));
2024
0
      return false;
2025
0
    }
2026
2027
0
    entries[step].setBegin(pos+4);
2028
0
    entries[step].setLength(sz);
2029
0
    libmwaw::DebugStream f;
2030
0
    if (step==0)
2031
0
      f << "Entries(RSRCMap):";
2032
0
    else
2033
0
      f << "Entries(RSRCData):";
2034
0
    ascii().addPos(pos);
2035
0
    ascii().addNote(f.str().c_str());
2036
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
2037
0
  }
2038
2039
0
  long endPos=input->tell();
2040
0
  int N=int(entries[0].length()/64);
2041
0
  input->seek(entries[0].begin(), librevenge::RVNG_SEEK_SET);
2042
0
  for (int n=0; n<N; ++n) {
2043
0
    long pos=input->tell();
2044
0
    libmwaw::DebugStream f;
2045
0
    f << "RSRCMap-" << n << ":";
2046
2047
0
    bool ok=true;
2048
0
    std::string types[2];
2049
0
    for (auto &text : types) {
2050
0
      for (int c=0; c<4; ++c) {
2051
0
        char ch=char(input->readULong(1));
2052
0
        if (ch==0) {
2053
0
          ok=false;
2054
0
          break;
2055
0
        }
2056
0
        text+=ch;
2057
0
      }
2058
0
      if (!ok) break;
2059
0
      f << text << ",";
2060
0
    }
2061
0
    if (!ok) { // empty field
2062
0
      ascii().addPos(pos);
2063
0
      ascii().addNote("_");
2064
0
      input->seek(pos+64, librevenge::RVNG_SEEK_SET);
2065
0
      continue;
2066
0
    }
2067
2068
0
    int val=int(input->readULong(2)); // 1 or 100
2069
0
    if (val!=1) f << "f0=" << val << ",";
2070
0
    librevenge::RVNGString name;
2071
0
    if (!readString(name, 28, true))
2072
0
      f << "##name,";
2073
0
    else if (!name.empty())
2074
0
      f << name.cstr() << ",";
2075
0
    input->seek(pos+38, librevenge::RVNG_SEEK_SET);
2076
0
    MWAWEntry entry;
2077
0
    entry.setBegin(entries[1].begin()+input->readLong(4));
2078
0
    entry.setLength(input->readLong(4));
2079
0
    f << "unkn=" << std::hex << input->readULong(4) << std::dec << ",";
2080
0
    val=int(input->readLong(4));
2081
0
    if (val!=n)
2082
0
      f << "id0=" << val << ",";
2083
0
    int val2=int(input->readLong(4));
2084
0
    if (val2!=val)
2085
0
      f << "id1=" << val2 << ",";
2086
0
    entry.setId(int(input->readLong(2)));
2087
0
    if (entry.valid()) {
2088
0
      f << std::hex << entry.begin() << "<->" << entry.end() << std::dec << entry << ",";
2089
0
      if (entry.end()<=endPos) {
2090
0
        static std::map<std::string, int> const nameToId= {
2091
0
          { "Page", 0}, {"PSST", 1}, {"DevM", 2}, {"CSet", 3}, {"CVal", 4}, {"CNam", 5},
2092
0
          { "FLDF", 6}
2093
0
        };
2094
0
        int wh=nameToId.find(types[1])!=nameToId.end() ? nameToId.find(types[1])->second : -1;
2095
0
        bool done=false;
2096
0
        long actPos=input->tell();
2097
0
        switch (wh) {
2098
0
        case 0:
2099
0
          done=readPage(entry);
2100
0
          break;
2101
0
        case 1:
2102
0
          done=readPrinterSST(entry);
2103
0
          break;
2104
0
        case 2:
2105
0
          done=readPrinterDev(entry);
2106
0
          break;
2107
0
        case 3:
2108
0
          done=readCSet(entry);
2109
0
          break;
2110
0
        case 4:
2111
0
          done=m_styleManager->readColorValues(entry);
2112
0
          break;
2113
0
        case 5:
2114
0
          done=readCNam(entry);
2115
0
          break;
2116
0
        case 6: {
2117
0
          MWAWGraphicStyle::Gradient gradient;
2118
0
          done=m_styleManager->readGradient(entry, gradient);
2119
0
          break;
2120
0
        }
2121
0
        default:
2122
0
          break;
2123
0
        }
2124
0
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
2125
0
        if (!done) {
2126
0
          libmwaw::DebugStream f2;
2127
0
          f2 << "RSRCData-" << types[1] << "[" << entry.id() << "]:";
2128
0
          ascii().addPos(entry.begin());
2129
0
          ascii().addNote(f2.str().c_str());
2130
0
        }
2131
0
      }
2132
0
      else
2133
0
        f << "###";
2134
0
    }
2135
0
    ascii().addDelimiter(input->tell(),'|');
2136
0
    ascii().addPos(pos);
2137
0
    ascii().addNote(f.str().c_str());
2138
0
    input->seek(pos+64, librevenge::RVNG_SEEK_SET);
2139
0
  }
2140
0
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2141
0
  return true;
2142
0
}
2143
2144
bool CanvasParser::readCNam(MWAWEntry const &entry)
2145
0
{
2146
0
  auto input=getInput();
2147
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
2148
0
    return false;
2149
0
  if (entry.length()<256) {
2150
0
    MWAW_DEBUG_MSG(("CanvasParser::readCNam: the zone seems too small\n"));
2151
0
    return false;
2152
0
  }
2153
  // checkme: find always an empty zone
2154
0
  libmwaw::DebugStream f;
2155
0
  f << "Entries(CNam)[" << entry.id() << "]:";
2156
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
2157
0
  ascii().addPos(entry.begin());
2158
0
  ascii().addNote(f.str().c_str());
2159
2160
0
  for (int st=0; st<2; ++st) {
2161
0
    long pos=input->tell();
2162
0
    f.str("");
2163
0
    f << "CNam-" << st << ":";
2164
0
    for (int i=0; i<64; ++i) {
2165
0
      int val=int(input->readLong(2));
2166
0
      if (val)
2167
0
        f << "f" << i << "=" << val << ",";
2168
0
    }
2169
0
    ascii().addPos(pos);
2170
0
    ascii().addNote(f.str().c_str());
2171
0
  }
2172
0
  return true;
2173
0
}
2174
2175
bool CanvasParser::readCSet(MWAWEntry const &entry)
2176
0
{
2177
0
  auto input=getInput();
2178
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
2179
0
    return false;
2180
0
  if (entry.length()<160) {
2181
0
    MWAW_DEBUG_MSG(("CanvasParser::readCSet: the zone seems too small\n"));
2182
0
    return false;
2183
0
  }
2184
0
  libmwaw::DebugStream f;
2185
0
  f << "Entries(CSet)[" << entry.id() << "]:";
2186
0
  input->seek(entry.begin()+31,librevenge::RVNG_SEEK_SET);
2187
0
  ascii().addDelimiter(input->tell(), '|');
2188
0
  librevenge::RVNGString name;
2189
0
  if (!readString(name, 128, true)) // find Default
2190
0
    f << "##name,";
2191
0
  else if (!name.empty())
2192
0
    f << name.cstr() << ",";
2193
0
  input->seek(entry.begin()+31+128, librevenge::RVNG_SEEK_SET);
2194
0
  ascii().addDelimiter(input->tell(), '|');
2195
0
  ascii().addPos(entry.begin());
2196
0
  ascii().addNote(f.str().c_str());
2197
0
  return true;
2198
0
}
2199
2200
bool CanvasParser::readPage(MWAWEntry const &entry)
2201
0
{
2202
0
  auto input=getInput();
2203
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
2204
0
    return false;
2205
0
  if (entry.length()<936) {
2206
0
    MWAW_DEBUG_MSG(("CanvasParser::readPage: the zone seems too small\n"));
2207
0
    return false;
2208
0
  }
2209
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
2210
0
  libmwaw::DebugStream f;
2211
0
  f << "Entries(Page)[" << entry.id() << "]:";
2212
0
  int val;
2213
0
  for (int i=0; i<64; ++i) { // f0=1
2214
0
    val=int(input->readLong(2));
2215
0
    if (val)
2216
0
      f << "f" << i << "=" << val << ",";
2217
0
  }
2218
0
  ascii().addPos(entry.begin());
2219
0
  ascii().addNote(f.str().c_str());
2220
2221
0
  long pos=input->tell();
2222
0
  f.str("");
2223
0
  f << "Page-A0:";
2224
0
  for (int i=0; i<2; ++i) {
2225
0
    val=int(input->readLong(2));
2226
0
    if (val)
2227
0
      f << "f" << i << "=" << val << ",";
2228
0
  }
2229
0
  librevenge::RVNGString name;
2230
0
  if (!readString(name, 128, true))
2231
0
    f << "##name,";
2232
0
  else if (!name.empty())
2233
0
    f << "printer=" << name.cstr() << ",";
2234
0
  input->seek(pos+4+128, librevenge::RVNG_SEEK_SET);
2235
0
  ascii().addPos(pos);
2236
0
  ascii().addNote(f.str().c_str());
2237
2238
0
  pos=input->tell();
2239
0
  f.str("");
2240
0
  f << "Page-A1:";
2241
0
  for (int i=0; i<64; ++i) {
2242
0
    val=int(input->readLong(2));
2243
0
    if (val)
2244
0
      f << "f" << i << "=" << val << ",";
2245
0
  }
2246
0
  ascii().addPos(pos);
2247
0
  ascii().addNote(f.str().c_str());
2248
2249
0
  pos=input->tell();
2250
0
  f.str("");
2251
0
  f << "Page-A2:";
2252
0
  for (int i=0; i<18; ++i) {
2253
0
    val=int(input->readLong(2));
2254
0
    int const expected[]= {
2255
0
      1/*or 7*/,1,0,8,0,
2256
0
      0xe/*or 0x13*/,0, 0x30f, 0, 0x255/* or 251*/,
2257
0
      0, 0x318, 0, 0x264, 0/* or 4*/,
2258
0
      0,1,1
2259
0
    };
2260
0
    if (val!=expected[i])
2261
0
      f << "f" << i << "=" << val << ",";
2262
0
  }
2263
0
  for (int i=0; i<46; ++i) {
2264
0
    val=int(input->readLong(2));
2265
0
    if (val)
2266
0
      f << "g" << i << "=" << val << ",";
2267
0
  }
2268
0
  ascii().addPos(pos);
2269
0
  ascii().addNote(f.str().c_str());
2270
0
  input->seek(pos+128, librevenge::RVNG_SEEK_SET);
2271
2272
0
  for (int wh=3; wh<7; ++wh) {
2273
0
    pos=input->tell();
2274
0
    f.str("");
2275
0
    f << "Page-A" << wh << ":";
2276
0
    for (int i=0; i<(wh==6 ? 18 : 64); ++i) {
2277
0
      val=int(input->readLong(2));
2278
0
      if (val)
2279
0
        f << "f" << i << "=" << val << ",";
2280
0
    }
2281
0
    ascii().addPos(pos);
2282
0
    ascii().addNote(f.str().c_str());
2283
0
  }
2284
0
  return true;
2285
0
}
2286
2287
bool CanvasParser::readPrinterDev(MWAWEntry const &entry)
2288
0
{
2289
0
  auto input=getInput();
2290
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
2291
0
    return false;
2292
0
  if (entry.length()<198) {
2293
0
    MWAW_DEBUG_MSG(("CanvasParser::readPrinterDev: the zone seems too small\n"));
2294
0
    return false;
2295
0
  }
2296
0
  libmwaw::DebugStream f;
2297
0
  f << "Entries(Printer)[Dev," << entry.id() << "]:";
2298
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
2299
0
  librevenge::RVNGString name;
2300
0
  if (!readString(name, 32, true))
2301
0
    f << "##name,";
2302
0
  else if (!name.empty())
2303
0
    f << name.cstr() << ",";
2304
0
  input->seek(entry.begin()+32, librevenge::RVNG_SEEK_SET);
2305
2306
0
  ascii().addDelimiter(input->tell(),'|');
2307
0
  ascii().addPos(entry.begin());
2308
0
  ascii().addNote(f.str().c_str());
2309
0
  input->seek(entry.begin()+128, librevenge::RVNG_SEEK_SET);
2310
2311
0
  long pos=input->tell();
2312
0
  f.str("");
2313
0
  f << "Printer-A[Dev]:";
2314
0
  ascii().addPos(pos);
2315
0
  ascii().addNote(f.str().c_str());
2316
0
  return true;
2317
0
}
2318
2319
bool CanvasParser::readPrinterSST(MWAWEntry const &entry)
2320
0
{
2321
0
  auto input=getInput();
2322
0
  if (!input || !entry.valid() || !input->checkPosition(entry.end()))
2323
0
    return false;
2324
0
  if (entry.length()<113) {
2325
0
    MWAW_DEBUG_MSG(("CanvasParser::readPrinterSST: the zone seems too small\n"));
2326
0
    return false;
2327
0
  }
2328
0
  libmwaw::DebugStream f;
2329
0
  f << "Entries(Printer)[" << entry.id() << "]:";
2330
0
  input->seek(entry.begin(),librevenge::RVNG_SEEK_SET);
2331
0
  for (int i=0; i<4; ++i) { // find FILE:, "", driver file, driver name
2332
0
    long pos=input->tell();
2333
0
    librevenge::RVNGString name;
2334
0
    if (!readString(name, 25, true))
2335
0
      f << "##name,";
2336
0
    else if (!name.empty())
2337
0
      f << "text" << i << "=" << name.cstr() << ",";
2338
0
    input->seek(pos+25, librevenge::RVNG_SEEK_SET);
2339
0
  }
2340
0
  int val;
2341
0
  for (int i=0; i<4; ++i) {
2342
0
    val=int(input->readLong(i==3 ? 1 : 2));
2343
0
    if (val) f << "f" << i << "=" << val << ",";
2344
0
  }
2345
0
  for (int i=0; i<3; ++i) {
2346
0
    val=int(input->readLong(2));
2347
0
    int const expected[]= {1, 0xc6 /*or c8 or 34c */, 1};
2348
0
    if (val!=expected[i]) f << "f" << i << "=" << val << ",";
2349
0
  }
2350
0
  ascii().addPos(entry.begin());
2351
0
  ascii().addNote(f.str().c_str());
2352
0
  return true;
2353
0
}
2354
////////////////////////////////////////////////////////////
2355
//
2356
// send data
2357
//
2358
////////////////////////////////////////////////////////////
2359
2360
2361
bool CanvasParser::send(CanvasParserInternal::Layer const &layer)
2362
0
{
2363
0
  MWAWGraphicListenerPtr listener=getGraphicListener();
2364
0
  if (!listener) {
2365
0
    MWAW_DEBUG_MSG(("CanvasParser::send[layer]: can not find the listener\n"));
2366
0
    return false;
2367
0
  }
2368
0
  if (layer.m_shapesId.empty())
2369
0
    return true;
2370
0
  bool openLayer=false;
2371
0
  if (!layer.m_name.empty())
2372
0
    openLayer=listener->openLayer(layer.m_name);
2373
0
  for (auto const &id : layer.m_shapesId)
2374
0
    m_graphParser->sendShape(id);
2375
0
  if (openLayer)
2376
0
    listener->closeLayer();
2377
0
  return true;
2378
0
}
2379
2380
2381
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: