Coverage Report

Created: 2026-09-06 07:18

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
23.5k
    : m_version(2)
85
23.5k
    , m_isWindows(false)
86
23.5k
    , m_input()
87
23.5k
    , m_inputPos(0)
88
23.5k
    , m_stream()
89
23.5k
  {
90
23.5k
  }
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
12.6k
{
123
12.6k
  if (n<=0 || n>256 || &buffer == &buffer2) {
124
234
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::unpackBits: bad arguments\n"));
125
234
    return false;
126
234
  }
127
12.4k
  int r=0;
128
12.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
12.4k
  bool lastCopy=false;
132
53.1k
  while (r+1<n) {
133
42.6k
    int c=buffer[r++];
134
42.6k
    if (c>=0x81) {
135
14.8k
      unsigned char val=buffer[r++];
136
14.8k
      int num=0x101-c;
137
14.8k
      if (n2+num>256)
138
252
        return false;
139
160k
      for (int i=0; i<num; ++i)
140
145k
        buffer2[n2++]=val;
141
14.6k
      lastCopy=false;
142
14.6k
    }
143
27.7k
    else {
144
      // normally c==0x80 is reserved, but must not be used
145
27.7k
      if (lastCopy && !m_isWindows)
146
900
        return false;
147
26.8k
      int num=c+1;
148
26.8k
      if (r+num>n || n2+num>256)
149
881
        return false;
150
94.6k
      for (int i=0; i<num; ++i)
151
68.6k
        buffer2[n2++]=buffer[r++];
152
26.0k
      lastCopy=true;
153
26.0k
    }
154
42.6k
  }
155
10.4k
  return r==n;
156
12.4k
}
157
158
bool Decoder::initOutput(MWAWInputStreamPtr &input, unsigned long const headerSize)
159
9.54k
{
160
9.54k
  m_input=input;
161
9.54k
  if (!m_input || !m_input->checkPosition(long(headerSize)+20)) {
162
261
    MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::initOutput: can not find the input\n"));
163
261
    return false;
164
261
  }
165
166
9.28k
  m_input->seek(0, librevenge::RVNG_SEEK_SET);
167
9.28k
  unsigned long read;
168
9.28k
  const unsigned char *dt = m_input->read(headerSize, read);
169
9.28k
  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
9.28k
  m_stream.reset(new MWAWStringStream(dt, unsigned(headerSize)));
174
9.28k
  m_inputPos=long(headerSize);
175
9.28k
  return true;
176
9.28k
}
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.95k
{
210
8.95k
  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.95k
  auto actIPos=m_input->tell();
215
8.95k
  auto actOPos=m_stream->tell();
216
8.95k
  m_input->seek(m_inputPos, librevenge::RVNG_SEEK_SET);
217
8.95k
  m_stream->seek(0, librevenge::RVNG_SEEK_END);
218
219
8.95k
  long lastPos=m_input->size();
220
8.95k
  bool ok=true;
221
8.95k
  if (m_inputPos>=lastPos)
222
1
    ok=false;
223
8.95k
  if (m_version<=2) {
224
2.86k
    long nWrite=0;
225
2.86k
    unsigned char data[256], data2[256];
226
3.68k
    while (ok && !m_input->isEnd()) {
227
3.66k
      if (length>=0 && nWrite>=length)
228
5
        break;
229
3.66k
      long pos=m_input->tell();
230
3.66k
      int zSz=int(m_input->readULong(1));
231
3.66k
      long endPos=pos+zSz;
232
3.66k
      if (zSz==0 || endPos>lastPos) {
233
1.24k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not read some data zSz=%d, pos=%lx\n", zSz, (unsigned long) pos));
234
1.24k
        ok=false;
235
1.24k
        break;
236
1.24k
      }
237
177k
      for (int i=0; i<zSz; ++i) data[i]=(unsigned char)(m_input->readULong(1));
238
2.42k
      int n;
239
2.42k
      if (!unpackBits(data, zSz, data2, n)) {
240
1.59k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not read some data at %lx\n", (unsigned long) pos));
241
1.59k
        ok=false;
242
1.59k
        break;
243
1.59k
      }
244
822
      m_stream->append(data2, static_cast<unsigned int>(n));
245
822
      nWrite+=n;
246
822
    }
247
2.86k
    if (ok && length>=0 && nWrite!=length) {
248
18
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode: can not decode some data\n"));
249
18
      ok=false;
250
18
    }
251
2.86k
  }
252
6.09k
  else if (ok)
253
6.09k
    ok=decode3(length);
254
255
8.95k
  if (ok)
256
83
    m_inputPos=m_input->tell();
257
258
8.95k
  m_input->seek(actIPos, librevenge::RVNG_SEEK_SET);
259
8.95k
  m_stream->seek(actOPos, librevenge::RVNG_SEEK_SET);
260
8.95k
  return ok;
261
8.95k
}
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
6.09k
{
269
6.09k
  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
6.09k
  long lastPos=m_input->size();
274
6.09k
  long numWrite=0;
275
276
6.09k
  int const maxFinalSize=120;
277
6.09k
  unsigned char data[256], data2[256];
278
6.09k
  bool forceDict=false;
279
280
6.09k
  unsigned char m_dict[30];
281
6.09k
  std::set<unsigned char> m_dictKeys;
282
6.09k
  bool m_isDictInitialized=false;
283
6.09k
  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
29.2k
  while (m_input->tell()<lastPos) {
293
29.1k
    if (length>=0 && numWrite>=length)
294
80
      return numWrite==length;
295
296
29.1k
    long pos=m_input->tell();
297
29.1k
    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
29.1k
    if ((length<0 || numWrite==0) && lastDictPos+30!=pos && (zSz<2 || zSz>maxFinalSize+3 || forceDict)) {
301
5.79k
      if (pos+30>lastPos) {
302
238
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: can not read a dictionary at pos=%lx\n", (unsigned long) pos));
303
238
        return false;
304
238
      }
305
      // create the dictionary
306
5.56k
      lastDictPos=pos;
307
5.56k
      m_dict[0]=(unsigned char)(zSz);
308
166k
      for (int i=1; i<30; ++i)
309
161k
        m_dict[i]=(unsigned char)m_input->readULong(1);
310
5.56k
      m_dictKeys.clear();
311
166k
      for (auto &c : m_dict) m_dictKeys.insert(c);
312
5.56k
      m_isDictInitialized=true;
313
5.56k
      forceDict=false;
314
5.56k
      continue;
315
5.79k
    }
316
23.3k
    else if (forceDict) {
317
5.69k
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: can not place a dictionary at pos=%lx\n", (unsigned long) pos));
318
5.69k
      return false;
319
5.69k
    }
320
321
17.6k
    long endPos=pos+1+zSz;
322
17.6k
    if (endPos>lastPos) {
323
863
      MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: force a dictionary in pos=%lx\n", (unsigned long) pos));
324
863
      forceDict=true;
325
863
      m_input->seek(pos, librevenge::RVNG_SEEK_SET);
326
863
      continue;
327
863
    }
328
    // FIXME: find a method if the data are compressed or not
329
16.7k
    int const lastChecksumSz=m_isWindows ? 1 : 0;
330
36.9k
    for (int step=0; step<3; ++step) {
331
36.9k
      if (step==2) {
332
8.01k
        MWAW_DEBUG_MSG(("CanvasParserInternal::Decoder::decode3: force a dictionary in pos=%lx\n", (unsigned long) pos));
333
8.01k
        forceDict=true;
334
8.01k
        m_input->seek(pos, librevenge::RVNG_SEEK_SET);
335
8.01k
        break;
336
8.01k
      }
337
28.9k
      m_input->seek(pos+1, librevenge::RVNG_SEEK_SET);
338
28.9k
      int numChar=int(m_input->readULong(1));
339
#ifdef DEBUG_WITH_FILES
340
      int nChar=numChar;
341
#endif
342
28.9k
      if (step==0) {
343
16.7k
        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.47k
        bool ok=true;
346
7.47k
        int w=0;
347
7.47k
        unsigned char c;
348
7.47k
        bool readC=false;
349
97.0k
        while (m_input->tell()<=endPos && w<numChar) {
350
90.3k
          int newC=0;
351
175k
          for (int st=0; st<4; ++st) {
352
163k
            int val;
353
163k
            if (!readC) {
354
82.3k
              if (m_input->tell()>endPos) {
355
198
                ok=false;
356
198
                break;
357
198
              }
358
82.1k
              c=(unsigned char) m_input->readULong(1);
359
82.1k
              val=int(c>>4);
360
82.1k
            }
361
81.6k
            else
362
81.6k
              val=int(c&0xf);
363
163k
            readC=!readC;
364
365
163k
            if (val && st<2) {
366
78.0k
              data[w++]=m_dict[15*st+val-1];
367
78.0k
              break;
368
78.0k
            }
369
85.6k
            newC=(newC<<4)|val;
370
85.6k
            if (st==3) {
371
12.0k
              if (m_dictKeys.find((unsigned char) newC)!=m_dictKeys.end()) {
372
591
                ok=false;
373
591
                break;
374
591
              }
375
11.4k
              data[w++]=(unsigned char) newC;
376
11.4k
            }
377
85.6k
          }
378
90.3k
          if (ok==false)
379
789
            break;
380
90.3k
        }
381
7.47k
        if (ok==false || w!=numChar || m_input->tell()<endPos)
382
1.48k
          continue;
383
7.47k
      }
384
12.1k
      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
12.1k
        if (numChar+1!=zSz) {
389
11.5k
          m_input->seek(-1, librevenge::RVNG_SEEK_CUR);
390
11.5k
          numChar=zSz;
391
11.5k
        }
392
355k
        for (int i=0; i<numChar; ++i)
393
343k
          data[i]=(unsigned char) m_input->readULong(1);
394
12.1k
      }
395
396
      // first check the checksum
397
18.1k
      int checkSum;
398
18.1k
      bool ok=false;
399
26.5k
      for (int step2=0; step2<2; ++step2) {
400
26.1k
        if (step2==1) {
401
7.98k
          if (!m_isWindows || step!=1 || numChar+1!=zSz)
402
7.54k
            break;
403
440
          m_input->seek(-zSz, librevenge::RVNG_SEEK_CUR);
404
440
          numChar=zSz;
405
13.5k
          for (int i=0; i<numChar; ++i)
406
13.1k
            data[i]=(unsigned char) m_input->readULong(1);
407
440
        }
408
18.6k
        checkSum=0;
409
390k
        for (int i=0; i<numChar-1; ++i)
410
371k
          checkSum+=int(data[i]);
411
18.6k
        if (numChar==0 || (checkSum&0xff)!=int(data[numChar-1]))
412
8.34k
          continue;
413
10.2k
        ok=true;
414
10.2k
        break;
415
18.6k
      }
416
18.1k
      if (!ok) continue;
417
418
10.2k
      --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
10.2k
      int finalN;
431
10.2k
      if (!unpackBits(data, numChar, data2, finalN) || finalN>maxFinalSize+lastChecksumSz || (m_isWindows && finalN<=numChar) ||
432
8.24k
          (length>=0 && numWrite+finalN>length+lastChecksumSz) || finalN<1+lastChecksumSz) {
433
8.24k
        if (m_isWindows && (length<0 || numWrite+numChar<=length+lastChecksumSz) &&
434
7.39k
            numChar<=maxFinalSize+lastChecksumSz && numChar>=1+lastChecksumSz) {
435
51.2k
          for (int i=0; i < numChar; ++i)
436
44.3k
            data2[i]=data[i];
437
6.89k
          finalN=numChar;
438
6.89k
        }
439
1.35k
        else
440
1.35k
          continue;
441
8.24k
      }
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.91k
      if (lastChecksumSz==1) {
453
6.89k
        checkSum=0;
454
44.4k
        for (int i=0; i<finalN-1; ++i)
455
37.5k
          checkSum+=int(data2[i]);
456
6.89k
        if ((checkSum&0xff)!=int(data2[finalN-1]))
457
172
          continue;
458
6.72k
        --finalN;
459
6.72k
      }
460
8.74k
      m_stream->append(data2, static_cast<unsigned int>(finalN));
461
8.74k
      numWrite+=finalN;
462
8.74k
      break;
463
8.91k
    }
464
16.7k
  }
465
77
  return length<0 || numWrite==length;
466
6.09k
}
467
////////////////////////////////////////
468
//! Internal: the state of a CanvasParser
469
struct State {
470
  //! constructor
471
  State()
472
15.7k
    : m_isWindowsFile(false)
473
15.7k
    , m_lengths()
474
15.7k
    , m_brushLengths()
475
15.7k
    , m_bitmapSize(0)
476
15.7k
    , m_input()
477
15.7k
    , m_decoder()
478
15.7k
    , m_numLayers(1)
479
15.7k
    , m_numShapes(0)
480
15.7k
    , m_numViews(0)
481
15.7k
    , m_numColors(256) // FIXME: check if this number is stored in the file or not
482
15.7k
    , m_numPatterns(120)
483
15.7k
    , m_sprayLengths()
484
485
15.7k
    , m_numPages(1,1)
486
15.7k
    , m_pageDimension(425, 624)
487
15.7k
    , m_layers()
488
489
15.7k
    , m_metaData()
490
15.7k
  {
491
15.7k
  }
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
15.7k
  : MWAWGraphicParser(input, rsrcParser, header)
536
15.7k
  , m_state()
537
15.7k
  , m_graphParser()
538
15.7k
  , m_styleManager()
539
15.7k
{
540
15.7k
  resetGraphicListener();
541
15.7k
  setAsciiName("main-1");
542
543
15.7k
  m_state.reset(new CanvasParserInternal::State);
544
545
15.7k
  m_styleManager.reset(new CanvasStyleManager(*this));
546
15.7k
  m_graphParser.reset(new CanvasGraph(*this));
547
548
15.7k
  getPageSpan().setMargins(0.1);
549
15.7k
}
550
551
CanvasParser::~CanvasParser()
552
15.7k
{
553
15.7k
}
554
555
MWAWInputStreamPtr &CanvasParser::getInput()
556
121k
{
557
121k
  if (m_state->m_input)
558
94.7k
    return m_state->m_input;
559
26.2k
  return MWAWGraphicParser::getInput();
560
121k
}
561
562
bool CanvasParser::decode(long length)
563
1.52k
{
564
1.52k
  long prevSize=m_state->m_input ? m_state->m_input->size() : 0;
565
1.52k
  if (!m_state->m_input || !m_state->m_decoder.decode(length)) {
566
1.51k
    if (m_state->m_decoder.m_stream)
567
1.51k
      m_state->m_decoder.m_stream->resize((unsigned long)(prevSize));
568
1.51k
    return false;
569
1.51k
  }
570
12
  m_state->m_input->recomputeStreamSize();
571
12
  return true;
572
1.52k
}
573
574
bool CanvasParser::isWindowsFile() const
575
86.4k
{
576
86.4k
  return m_state->m_isWindowsFile;
577
86.4k
}
578
579
////////////////////////////////////////////////////////////
580
// the parser
581
////////////////////////////////////////////////////////////
582
void CanvasParser::parse(librevenge::RVNGDrawingInterface *docInterface)
583
2.11k
{
584
2.11k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
585
2.11k
  bool ok = false;
586
2.11k
  try {
587
2.11k
    checkHeader(nullptr);
588
2.11k
    ascii().setStream(getInput());
589
2.11k
    ascii().open(asciiName());
590
2.11k
    if (!readFileHeader())
591
0
      throw libmwaw::ParseException();
592
593
2.11k
    bool const isWindows=isWindowsFile();
594
2.11k
    m_state->m_decoder.m_isWindows=isWindows;
595
2.11k
    m_state->m_decoder.m_version=version();
596
2.11k
    if (!m_state->m_decoder.initOutput(getInput(), isWindows ? (unsigned long)(0x920+m_state->m_bitmapSize) : 0x89c) || !m_state->m_decoder.m_stream)
597
190
      throw libmwaw::ParseException();
598
1.92k
    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.92k
    m_styleManager->setInput(m_state->m_input);
602
1.92k
    m_graphParser->setInput(m_state->m_input);
603
1.92k
    ascii().setStream(m_state->m_input);
604
605
1.92k
    ok = createZones();
606
1.92k
    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.92k
  }
613
2.11k
  catch (...) {
614
190
    MWAW_DEBUG_MSG(("CanvasParser::parse: exception catched when parsing\n"));
615
190
    ok = false;
616
190
  }
617
618
2.11k
  ascii().reset();
619
2.11k
  resetGraphicListener();
620
2.11k
  if (!ok) throw(libmwaw::ParseException());
621
2.11k
}
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.92k
{
657
1.92k
  auto input=getInput();
658
1.92k
  if (!input) return false;
659
660
1.92k
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
661
1.92k
  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.92k
  bool const isWindows=m_state->m_isWindowsFile;
695
1.92k
  input->seek(0x3c, librevenge::RVNG_SEEK_SET);
696
1.92k
  if (isWindows) {
697
873
    if (!m_graphParser->readFileBitmap(m_state->m_bitmapSize) || !input->checkPosition(input->tell()+132))
698
406
      return false;
699
467
    long pos=input->tell();
700
467
    libmwaw::DebugStream f;
701
467
    f << "Entries(Brush):lengths=[";
702
15.4k
    for (int i=0; i<32; ++i) {
703
14.9k
      auto length=input->readULong(4);
704
14.9k
      m_state->m_brushLengths.push_back(length);
705
14.9k
      f << length << ",";
706
14.9k
    }
707
467
    f << "],";
708
467
    f << "f0=" << input->readULong(4) << ","; // small number
709
467
    ascii().addPos(pos);
710
467
    ascii().addNote(f.str().c_str());
711
467
  }
712
1.51k
  if (!readUnknownZoneHeader() || !m_styleManager->readPenSize() || !readDocumentHeader() || !readMacroNames() ||
713
1.51k
      !readUnknownZone0() || !m_styleManager->readArrows() || !readFormats() || !readGrids() || !readUnknownZone1())
714
0
    return false;
715
716
1.51k
  if (!m_graphParser->readShapes(m_state->m_numShapes, m_state->m_lengths[0], m_state->m_lengths[1]))
717
1.51k
    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
17.8k
{
845
17.8k
  MWAWInputStreamPtr input = getInput();
846
17.8k
  if (!input || !input->hasDataFork() || !input->checkPosition(0x89e))
847
0
    return false;
848
849
17.8k
  input->setReadInverted(false);
850
17.8k
  input->seek(0x36, librevenge::RVNG_SEEK_SET);
851
17.8k
  int val=int(input->readULong(2));
852
17.8k
  int vers=0;
853
17.8k
  switch (val) {
854
4.61k
  case 1:
855
4.61k
    vers=2;
856
4.61k
    break;
857
6.00k
  case 2:
858
6.00k
    vers=3;
859
6.00k
    break;
860
7.14k
  case 0x100:
861
7.14k
    input->setReadInverted(true);
862
7.14k
    m_state->m_isWindowsFile=true;
863
7.14k
    vers=3;
864
7.14k
    break;
865
91
  default:
866
91
    MWAW_DEBUG_MSG(("CanvasParser::checkHeader: unknown version=%d\n", val));
867
91
    return false;
868
17.8k
  }
869
870
17.7k
  input->seek(0, librevenge::RVNG_SEEK_SET);
871
17.7k
  unsigned long lengths[3];
872
52.7k
  for (auto &l : lengths) {
873
    // check that no shape/shape data/layer lengths is empty
874
52.7k
    l=input->readULong(4);
875
52.7k
    if (l==0)
876
607
      return false;
877
52.7k
  }
878
17.1k
  if (strict) {
879
    // try to decode the shape and the shape data zone
880
7.81k
    CanvasParserInternal::Decoder decoder;
881
7.81k
    decoder.m_isWindows=m_state->m_isWindowsFile;
882
7.81k
    decoder.m_version=vers;
883
7.81k
    input->seek(0x38, librevenge::RVNG_SEEK_SET);
884
7.81k
    unsigned long bitmapSize=m_state->m_isWindowsFile ? input->readULong(4) : 0;
885
7.81k
    if (long(bitmapSize)<0 || (m_state->m_isWindowsFile && !input->checkPosition(long(0x920+bitmapSize))) ||
886
7.43k
        !decoder.initOutput(input, m_state->m_isWindowsFile ? 0x920+bitmapSize : 0x89c) ||
887
7.35k
        !decoder.decode(long(lengths[0])) || !decoder.decode(long(lengths[1])))
888
7.81k
      return false;
889
7.81k
  }
890
9.33k
  setVersion(vers);
891
9.33k
  if (header)
892
5.11k
    header->reset(MWAWDocument::MWAW_T_CANVAS, vers, MWAWDocument::MWAW_K_DRAW);
893
894
9.33k
  return true;
895
17.1k
}
896
897
bool CanvasParser::readFileHeader()
898
2.11k
{
899
2.11k
  auto input=getInput();
900
2.11k
  long const endPos=0x3c;
901
2.11k
  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
2.11k
  m_state->m_lengths.clear();
907
908
2.11k
  libmwaw::DebugStream f;
909
2.11k
  f << "FileHeader:";
910
2.11k
  input->seek(0, librevenge::RVNG_SEEK_SET);
911
2.11k
  f << "length=[";
912
29.5k
  for (int i=0; i<13; ++i) {
913
27.4k
    auto length=input->readULong(4);
914
27.4k
    if (i>=4 && i<12)
915
16.8k
      m_state->m_brushLengths.push_back(length);
916
10.5k
    else
917
10.5k
      m_state->m_lengths.push_back(length);
918
27.4k
    f << length << ",";
919
27.4k
  }
920
2.11k
  f << "],";
921
2.11k
  ascii().addPos(0);
922
2.11k
  ascii().addNote(f.str().c_str());
923
924
2.11k
  long pos=input->tell();
925
2.11k
  f.str("");
926
2.11k
  f << "FileHeader-end:";
927
2.11k
  int val;
928
2.11k
  val=int(input->readLong(1));
929
2.11k
  if (val==1)
930
1.06k
    f << "little[endian],";
931
1.04k
  else if (val)
932
0
    f << "##endian=" << val << ",";
933
2.11k
  val=int(input->readULong(1)); // v2: 100, v3: 104
934
2.11k
  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
2.10k
  default:
951
2.10k
    f << "version=" << val << ",";
952
2.10k
    break;
953
2.11k
  }
954
2.11k
  val=int(input->readULong(2));
955
2.11k
  if (val!=1) f << "vers=" << val+1 << ",";
956
2.11k
  if (isWindowsFile()) {
957
1.06k
    m_state->m_bitmapSize=long(input->readULong(4));
958
1.06k
    f << "bitmap[size]=" << m_state->m_bitmapSize << ",";
959
1.06k
  }
960
2.11k
  if (input->tell()!=endPos)
961
1.04k
    ascii().addDelimiter(input->tell(),'|');
962
2.11k
  ascii().addPos(pos);
963
2.11k
  ascii().addNote(f.str().c_str());
964
2.11k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
965
2.11k
  return true;
966
2.11k
}
967
968
bool CanvasParser::readDocumentHeader()
969
1.51k
{
970
1.51k
  auto input=getInput();
971
1.51k
  long pos=input ? input->tell() : 0;
972
1.51k
  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.51k
  libmwaw::DebugStream f;
978
1.51k
  f << "Entries(Document):";
979
1.51k
  input->seek(pos+46, librevenge::RVNG_SEEK_SET);
980
1.51k
  ascii().addDelimiter(input->tell(),'|');
981
1.51k
  int dim[2];
982
3.03k
  for (auto &d : dim) d=int(input->readULong(2));
983
1.51k
  if (dim[0]!=1 || dim[1]!=1) {
984
1.50k
    m_state->m_numPages=MWAWVec2i(dim[0], dim[1]);
985
1.50k
    f << "pages=" << m_state->m_numPages << ",";
986
1.50k
    if (dim[0]<=0 || dim[0]>15 || dim[1]<=0 || dim[1]>15) {
987
1.49k
      MWAW_DEBUG_MSG(("CanvasParser::readDocumentHeader: the number of pages seems bad\n"));
988
1.49k
      f << "###";
989
1.49k
      m_state->m_numPages=MWAWVec2i(1,1);
990
1.49k
    }
991
1.50k
  }
992
1.51k
  ascii().addDelimiter(input->tell(),'|');
993
1.51k
  input->seek(pos+60, librevenge::RVNG_SEEK_SET);
994
1.51k
  ascii().addPos(pos);
995
1.51k
  ascii().addNote(f.str().c_str());
996
997
1.51k
  pos=input->tell();
998
1.51k
  f.str("");
999
1.51k
  f << "Document-0:";
1000
1.51k
  m_state->m_numPatterns=int(input->readULong(2));
1001
1.51k
  if (m_state->m_numPatterns!=120)
1002
1.51k
    f << "num[patterns]=" << m_state->m_numPatterns << ",";
1003
1.51k
  ascii().addDelimiter(input->tell(),'|');
1004
1.51k
  input->seek(pos+58, librevenge::RVNG_SEEK_SET);
1005
1.51k
  ascii().addPos(pos);
1006
1.51k
  ascii().addNote(f.str().c_str());
1007
1008
1.51k
  pos=input->tell();
1009
1.51k
  f.str("");
1010
1.51k
  f << "Document-1:";
1011
1.51k
  int val=int(input->readULong(2));
1012
1.51k
  m_state->m_numShapes=int(input->readULong(2));
1013
1.51k
  f << "num[shapes]=" << m_state->m_numShapes << ",";
1014
1.51k
  if (val!=m_state->m_numShapes)
1015
959
    f << "max[shapes]=" << val << ",";
1016
1.51k
  val=int(input->readULong(2));
1017
1.51k
  f << "f0=" << val << ","; // small number
1018
1.51k
  ascii().addDelimiter(input->tell(),'|');
1019
1.51k
  input->seek(pos+30, librevenge::RVNG_SEEK_SET);
1020
1.51k
  ascii().addPos(pos);
1021
1.51k
  ascii().addNote(f.str().c_str());
1022
1023
1.51k
  pos=input->tell();
1024
1.51k
  f.str("");
1025
1.51k
  f << "Document-2:";
1026
15.1k
  for (int i=0; i<9; ++i) { // f0=-1|1, f1=1|5, f2=0|1,f3=0|2, f7=-1000|-2000
1027
13.6k
    val=int(input->readLong(2));
1028
13.6k
    int const expected[]= {-1,1,0,0,1,0,0, -1000, -1000};
1029
13.6k
    if (val==expected[i])
1030
1.59k
      continue;
1031
12.0k
    if (i==4) {
1032
1.49k
      m_state->m_numLayers=val;
1033
1.49k
      f << "N[layer]=" << val << ",";
1034
1.49k
    }
1035
10.5k
    else if (i==6) {
1036
1.17k
      m_state->m_numViews=val;
1037
1.17k
      f << "N[view]=" << val << ",";
1038
1.17k
    }
1039
9.37k
    else
1040
9.37k
      f << "f" << i << "=" << val << ",";
1041
12.0k
  }
1042
1.51k
  if (version()==2) {
1043
405
    librevenge::RVNGString text;
1044
405
    if (readString(text, 64)) // find "1page Grp B&W"
1045
277
      f << text.cstr() << ",";
1046
128
    else
1047
128
      f << "###string,";
1048
405
  }
1049
1.11k
  else // something like 0a40800...0
1050
1.11k
    ascii().addDelimiter(input->tell(),'|');
1051
1.51k
  input->seek(pos+18+64, librevenge::RVNG_SEEK_SET);
1052
1.51k
  ascii().addPos(pos);
1053
1.51k
  ascii().addNote(f.str().c_str());
1054
1.51k
  return true;
1055
1.51k
}
1056
1057
bool CanvasParser::readMacroNames()
1058
1.51k
{
1059
1.51k
  auto input=getInput();
1060
1.51k
  long pos=input ? input->tell() : 0;
1061
1.51k
  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.51k
  libmwaw::DebugStream f;
1067
49.9k
  for (int i=0; i<32; ++i) {
1068
48.4k
    pos=input->tell();
1069
48.4k
    f.str("");
1070
48.4k
    f << "Entries(Macro)[" << i << "]:";
1071
48.4k
    librevenge::RVNGString text;
1072
48.4k
    if (readString(text, 20, true)) {
1073
33.5k
      if (text.empty()) {
1074
23.6k
        ascii().addPos(pos);
1075
23.6k
        ascii().addNote("_");
1076
23.6k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1077
23.6k
        continue;
1078
23.6k
      }
1079
9.87k
      f << "name=" << text.cstr() << ",";
1080
9.87k
    }
1081
14.9k
    else
1082
14.9k
      f << "##name,";
1083
24.7k
    ascii().addPos(pos);
1084
24.7k
    ascii().addNote(f.str().c_str());
1085
24.7k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1086
24.7k
  }
1087
1.51k
  return true;
1088
1.51k
}
1089
1090
bool CanvasParser::readUnknownZoneHeader()
1091
1.51k
{
1092
1.51k
  auto input=getInput();
1093
1.51k
  long pos=input ? input->tell() : 0;
1094
1.51k
  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.51k
  libmwaw::DebugStream f;
1100
1.51k
  f << "Entries(ZoneH):";
1101
1.51k
  ascii().addPos(pos);
1102
1.51k
  ascii().addNote(f.str().c_str());
1103
1.51k
  input->seek(pos+28, librevenge::RVNG_SEEK_SET);
1104
1.51k
  return true;
1105
1.51k
}
1106
1107
bool CanvasParser::readUnknownZone0()
1108
1.51k
{
1109
1.51k
  auto input=getInput();
1110
1.51k
  long pos=input ? input->tell() : 0;
1111
1.51k
  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.51k
  libmwaw::DebugStream f;
1117
1.51k
  f << "Entries(Zone0):";
1118
1.51k
  int val=int(input->readLong(2));
1119
1.51k
  if (val!=-1) // or 5
1120
1.43k
    f << "f0=" << val << ",";
1121
31.8k
  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
30.3k
    val=int(input->readULong(2));
1123
30.3k
    if (!val) continue;
1124
22.5k
    if (val<0x1000)
1125
8.56k
      f << "f" << i+1 << "=" << val << ",";
1126
13.9k
    else
1127
13.9k
      f << "f" << i+1 << "=" << std::hex << val << std::dec << ",";
1128
22.5k
  }
1129
4.54k
  for (int st=0; st<2; ++st) {
1130
3.03k
    unsigned char col[3];
1131
9.09k
    for (auto &c : col) c=(unsigned char)(input->readULong(2)>>8);
1132
3.03k
    MWAWColor color(col[0],col[1],col[2]);
1133
3.03k
    if (color!=MWAWColor::black())
1134
2.53k
      f << "col" << st << "=" << color << ",";
1135
3.03k
  }
1136
1.51k
  f << "id=" << std::hex << input->readULong(4) << std::dec << ",";
1137
1.51k
  ascii().addPos(pos);
1138
1.51k
  ascii().addNote(f.str().c_str());
1139
1140
1.51k
  pos=input->tell();
1141
1.51k
  f.str("");
1142
1.51k
  f << "Zone0-1:";
1143
15.1k
  for (int i=0; i<9; ++i) { // f0=3|5|4e, f1=1
1144
13.6k
    val=int(input->readULong(2));
1145
13.6k
    if (!val) continue;
1146
10.1k
    if (val<0x1000)
1147
3.79k
      f << "f" << i+1 << "=" << val << ",";
1148
6.38k
    else
1149
6.38k
      f << "f" << i+1 << "=" << std::hex << val << std::dec << ",";
1150
10.1k
  }
1151
1.51k
  librevenge::RVNGString text;
1152
1.51k
  if (readString(text, 20))
1153
821
    f << "name=" << text.cstr() << ","; // Layer
1154
694
  else
1155
694
    f << "###name,";
1156
1.51k
  input->seek(pos+18+20, librevenge::RVNG_SEEK_SET);
1157
1.51k
  ascii().addPos(pos);
1158
1.51k
  ascii().addNote(f.str().c_str());
1159
1160
1.51k
  pos=input->tell();
1161
1.51k
  f.str("");
1162
1.51k
  f << "Zone0-2:";
1163
1.51k
  f << "font=[";
1164
1.51k
  f << "id=" << input->readULong(2) << ",";
1165
1.51k
  val=int(input->readULong(2));
1166
1.51k
  if (val) f << "fl=" << std::hex << val << std::dec << ",";
1167
1.51k
  f << "sz=" << input->readULong(2) << ",";
1168
1.51k
  f << "],";
1169
56.0k
  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
54.5k
    val=int(input->readLong(2));
1171
54.5k
    if (!val) continue;
1172
40.1k
    f << "f" << i << "=" << val << ",";
1173
40.1k
  }
1174
1.51k
  ascii().addPos(pos);
1175
1.51k
  ascii().addNote(f.str().c_str());
1176
1177
1.51k
  pos=input->tell();
1178
1.51k
  f.str("");
1179
1.51k
  f << "Zone0-3:";
1180
12.1k
  for (int i=0; i<7; ++i) {
1181
10.6k
    val=int(input->readLong(2));
1182
10.6k
    int const expected[]= {-50,16, -26,0,0,0,0};
1183
10.6k
    if (val==expected[i]) continue;
1184
9.04k
    f << "f" << i << "=" << val << ",";
1185
9.04k
  }
1186
4.54k
  for (int st=0; st<2; ++st) {
1187
3.03k
    int dim[4];
1188
12.1k
    for (auto &d : dim) d=int(input->readLong(2));
1189
3.03k
    if (dim[0]!=dim[2])
1190
1.80k
      f << "box" << st << "=" << MWAWBox2i(MWAWVec2i(dim[0],dim[1]),MWAWVec2i(dim[2],dim[3])) << ",";
1191
3.03k
  }
1192
19.6k
  for (int i=0; i<12; ++i) {
1193
18.1k
    val=int(input->readLong(2));
1194
18.1k
    int const expected[]= {1,16,0,3,1,0,0x48 /* or 4b*/, 0, 1, 0, 1, 0};
1195
18.1k
    if (val==expected[i]) continue;
1196
16.0k
    f << "g" << i << "=" << val << ",";
1197
16.0k
  }
1198
1.51k
  if (readString(text, 20)) // checkme: in v3.5 windows, probably junk
1199
866
    f << "name=" << text.cstr() << ",";
1200
649
  else
1201
649
    f << "###name,";
1202
1.51k
  input->seek(pos+14+16+24+20, librevenge::RVNG_SEEK_SET);
1203
4.54k
  for (int i=0; i<2; ++i) {
1204
3.03k
    val=int(input->readLong(2));
1205
3.03k
    if (!val) continue;
1206
2.24k
    f << "overlap[" << (i==0 ? "H" : "V") << "]=" << val << ",";
1207
2.24k
  }
1208
1.51k
  ascii().addPos(pos);
1209
1.51k
  ascii().addNote(f.str().c_str());
1210
1.51k
  return true;
1211
1.51k
}
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.51k
{
1319
1.51k
  auto input=getInput();
1320
1.51k
  long pos=input ? input->tell() : 0;
1321
1.51k
  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.51k
  libmwaw::DebugStream f;
1327
1.51k
  f << "Entries(Format):";
1328
1.51k
  input->seek(pos+8, librevenge::RVNG_SEEK_SET);
1329
1.51k
  ascii().addPos(pos);
1330
1.51k
  ascii().addNote(f.str().c_str());
1331
10.6k
  for (int u=0; u<6; ++u) {
1332
9.09k
    pos=input->tell();
1333
9.09k
    f.str("");
1334
9.09k
    f << "Format-" << u << ":";
1335
9.09k
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
1336
9.09k
    ascii().addDelimiter(input->tell(),'|');
1337
45.4k
    for (int i=0; i<4; ++i) {
1338
36.3k
      int val=int(input->readULong(4));
1339
36.3k
      if (val!=0x10000)
1340
36.1k
        f << "dim" << i << "=" << double(val)/double(0x10000) << ",";
1341
36.3k
    }
1342
9.09k
    librevenge::RVNGString text;
1343
9.09k
    if (readString(text, 20))
1344
5.20k
      f << "name=" << text.cstr() << ",";
1345
3.88k
    else
1346
3.88k
      f << "###name,";
1347
9.09k
    input->seek(pos+44, librevenge::RVNG_SEEK_SET);
1348
9.09k
    ascii().addPos(pos);
1349
9.09k
    ascii().addNote(f.str().c_str());
1350
9.09k
  }
1351
1.51k
  return true;
1352
1.51k
}
1353
1354
bool CanvasParser::readGrids()
1355
1.51k
{
1356
1.51k
  auto input=getInput();
1357
1.51k
  long pos=input ? input->tell() : 0;
1358
1.51k
  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.51k
  libmwaw::DebugStream f;
1364
6.06k
  for (int i=0; i<3; ++i) {
1365
4.54k
    pos=input->tell();
1366
4.54k
    f.str("");
1367
4.54k
    f << "Entries(Grid)[" << i << "]:";
1368
4.54k
    librevenge::RVNGString text;
1369
4.54k
    if (readString(text, 20)) {
1370
2.63k
      if (text.empty()) {
1371
2.32k
        ascii().addPos(pos);
1372
2.32k
        ascii().addNote("_");
1373
2.32k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1374
2.32k
        continue;
1375
2.32k
      }
1376
310
      f << "name=" << text.cstr() << ",";
1377
310
    }
1378
1.91k
    else
1379
1.91k
      f << "###name,";
1380
2.22k
    ascii().addPos(pos);
1381
2.22k
    ascii().addNote(f.str().c_str());
1382
2.22k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1383
2.22k
  }
1384
1.51k
  pos=input->tell();
1385
1.51k
  f.str("");
1386
1.51k
  f << "Entries(Spray):lengths=[";
1387
31.8k
  for (int i=0; i<20; ++i) {
1388
30.3k
    m_state->m_sprayLengths.push_back(input->readULong(4));
1389
30.3k
    if (m_state->m_sprayLengths.back())
1390
24.6k
      f << m_state->m_sprayLengths.back() << ",";
1391
5.62k
    else
1392
5.62k
      f << "_,";
1393
30.3k
  }
1394
1.51k
  f << "],";
1395
1.51k
  ascii().addPos(pos);
1396
1.51k
  ascii().addNote(f.str().c_str());
1397
18.1k
  for (int i=0; i<11; ++i) {
1398
    // checkme: make no sense
1399
16.6k
    pos=input->tell();
1400
16.6k
    f.str("");
1401
16.6k
    f << "Entries(Grid)[" << i+3 << "]:";
1402
16.6k
    librevenge::RVNGString text;
1403
16.6k
    if (readString(text, 20)) {
1404
9.51k
      if (text.empty()) {
1405
8.38k
        ascii().addPos(pos);
1406
8.38k
        ascii().addNote("_");
1407
8.38k
        input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1408
8.38k
        continue;
1409
8.38k
      }
1410
1.12k
      f << "name=" << text.cstr() << ",";
1411
1.12k
    }
1412
7.15k
    else
1413
7.15k
      f << "###name,";
1414
8.27k
    ascii().addPos(pos);
1415
8.27k
    ascii().addNote(f.str().c_str());
1416
8.27k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
1417
8.27k
  }
1418
1.51k
  return true;
1419
1.51k
}
1420
1421
bool CanvasParser::readUnknownZone1()
1422
1.51k
{
1423
1.51k
  auto input=getInput();
1424
1.51k
  long pos=input ? input->tell() : 0;
1425
1.51k
  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.51k
  libmwaw::DebugStream f;
1431
1.51k
  f << "Entries(Zone1):";
1432
1.51k
  int val;
1433
28.7k
  for (int i=0; i<18; ++i) {
1434
27.2k
    val=int(input->readULong(2));
1435
27.2k
    if (!val) continue;
1436
20.7k
    f << "f" << i << "=" << val << ",";
1437
20.7k
  }
1438
25.7k
  for (int i=0; i<16; ++i) {
1439
24.2k
    val=int(input->readLong(2));
1440
24.2k
    int const expected[]= { 1, 0, 1, 1, 10, 0, 10, 0, 100 /* or 10000 */, 1,
1441
24.2k
                            2, 1/* or 4*/, 0/*or 1*/, 0, 1, 1
1442
24.2k
                          };
1443
24.2k
    if (val==expected[i]) continue;
1444
22.2k
    f << "g" << i << "=" << val << ",";
1445
22.2k
  }
1446
15.1k
  for (int i=0; i<9; ++i) {
1447
13.6k
    val=int(input->readLong(4));
1448
13.6k
    int const expected[]= { 100 /* or 120*/, 100, 100, 1 /* or 4*/, 1, 1, 1, 1, 1 };
1449
13.6k
    if (val==65536*expected[i]) continue;
1450
13.6k
    f << "h" << i << "=" << double(val)/65536. << ",";
1451
13.6k
  }
1452
1.51k
  ascii().addPos(pos);
1453
1.51k
  ascii().addNote(f.str().c_str());
1454
1.51k
  pos=input->tell();
1455
1.51k
  f.str("");
1456
1.51k
  f << "Zone1-1:";
1457
16.6k
  for (int i=0; i<10; ++i) { // f5=small number, f6/f7: related to spray(a list of bit?) f14: related to brush?
1458
15.1k
    val=int(input->readLong(2));
1459
15.1k
    int const expected[]= { 50, 10, 0 /* or 1*/, 0, 0, 0, 2, 0, 0, 0};
1460
15.1k
    if (val==expected[i]) continue;
1461
12.7k
    f << "f" << i << "=" << val << ",";
1462
12.7k
  }
1463
30.3k
  for (int i=0; i<19; ++i) { // f27= almost always 1, f28=almost always 3
1464
28.7k
    val=int(input->readLong(2));
1465
28.7k
    if (!val) continue;
1466
21.9k
    f << "f" << i+10 << "=" << val << ",";
1467
21.9k
  }
1468
1.51k
  ascii().addPos(pos);
1469
1.51k
  ascii().addNote(f.str().c_str());
1470
1.51k
  return true;
1471
1.51k
}
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
82.2k
{
1717
82.2k
  return readString(getInput(), string, maxSize, canBeCString);
1718
82.2k
}
1719
1720
bool CanvasParser::readString(MWAWInputStreamPtr input, librevenge::RVNGString &string, int maxSize, bool canBeCString)
1721
82.2k
{
1722
82.2k
  string.clear();
1723
82.2k
  if (!input) {
1724
0
    MWAW_DEBUG_MSG(("CanvasParser::readString: can not find the input\n"));
1725
0
    return false;
1726
0
  }
1727
82.2k
  bool const isWindows=isWindowsFile();
1728
82.2k
  auto fontConverter=getFontConverter();
1729
82.2k
  int defaultFont=isWindows ? fontConverter->getId("CP1252") : 3;
1730
82.2k
  if (isWindows && canBeCString) {
1731
14.9k
    int n=0;
1732
151k
    while (!input->isEnd() && (maxSize<=0 || n<maxSize)) {
1733
145k
      char c=char(input->readULong(1));
1734
145k
      if (c==0)
1735
9.28k
        break;
1736
136k
      ++n;
1737
136k
      int unicode = fontConverter->unicode(defaultFont, static_cast<unsigned char>(c));
1738
136k
      if (unicode>0)
1739
89.5k
        libmwaw::appendUnicode(uint32_t(unicode), string);
1740
46.5k
      else {
1741
46.5k
        MWAW_DEBUG_MSG(("CanvasParser::readString: find unknown unicode for char=%d\n", int(c)));
1742
46.5k
      }
1743
136k
    }
1744
14.9k
    return true;
1745
14.9k
  }
1746
67.2k
  int sSz=int(input->readULong(1));
1747
67.2k
  if ((maxSize<=0 || sSz<maxSize) && input->checkPosition(input->tell()+sSz)) {
1748
100k
    for (int ch=0; ch<sSz; ++ch) {
1749
67.8k
      char c=char(input->readULong(1));
1750
67.8k
      if (c==0)
1751
5.75k
        break;
1752
62.1k
      int unicode = fontConverter->unicode(defaultFont, static_cast<unsigned char>(c));
1753
62.1k
      if (unicode>0)
1754
13.2k
        libmwaw::appendUnicode(uint32_t(unicode), string);
1755
48.8k
      else {
1756
48.8k
        MWAW_DEBUG_MSG(("CanvasParser::readString: find unknown unicode for char=%d\n", int(c)));
1757
48.8k
      }
1758
62.1k
    }
1759
37.9k
  }
1760
29.3k
  else {
1761
29.3k
    MWAW_DEBUG_MSG(("CanvasParser::readString: bad size=%d\n", sSz));
1762
29.3k
    return false;
1763
29.3k
  }
1764
37.9k
  return true;
1765
67.2k
}
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: