Coverage Report

Created: 2026-09-06 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/ZWrtParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <iomanip>
35
#include <iostream>
36
#include <limits>
37
#include <set>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWTextListener.hxx"
43
#include "MWAWFontConverter.hxx"
44
#include "MWAWHeader.hxx"
45
#include "MWAWPosition.hxx"
46
#include "MWAWPrinter.hxx"
47
#include "MWAWRSRCParser.hxx"
48
#include "MWAWSubDocument.hxx"
49
50
#include "ZWrtText.hxx"
51
52
#include "ZWrtParser.hxx"
53
54
/** Internal: the structures of a ZWrtParser */
55
namespace ZWrtParserInternal
56
{
57
////////////////////////////////////////
58
//! Internal: the state of a ZWrtParser
59
struct State {
60
  //! constructor
61
  State()
62
10.7k
    : m_actPage(0)
63
10.7k
    , m_numPages(0)
64
10.7k
    , m_headerUsed(true)
65
10.7k
    , m_footerUsed(true)
66
10.7k
    , m_headerHeight(0)
67
10.7k
    , m_footerHeight(0)
68
10.7k
  {
69
10.7k
  }
70
71
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
72
73
  //! true if the header is used
74
  bool m_headerUsed;
75
  //! true if the footer is used
76
  bool m_footerUsed;
77
  int m_headerHeight /** the header height if known */,
78
      m_footerHeight /** the footer height if known */;
79
};
80
81
////////////////////////////////////////
82
//! Internal: the subdocument of a ZWrtParser
83
class SubDocument final : public MWAWSubDocument
84
{
85
public:
86
  SubDocument(ZWrtParser &pars, MWAWInputStreamPtr const &input, bool header)
87
1.81k
    : MWAWSubDocument(&pars, input, MWAWEntry())
88
1.81k
    , m_isHeader(header)
89
1.81k
  {
90
1.81k
  }
91
92
  //! destructor
93
0
  ~SubDocument() final {}
94
95
  //! operator!=
96
  bool operator!=(MWAWSubDocument const &doc) const final
97
0
  {
98
0
    if (MWAWSubDocument::operator!=(doc)) return true;
99
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
100
0
    if (!sDoc) return true;
101
0
    if (m_isHeader != sDoc->m_isHeader) return true;
102
0
    return false;
103
0
  }
104
105
  //! the parser function
106
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
107
108
protected:
109
  //! true if we need to send the parser
110
  int m_isHeader;
111
};
112
113
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
114
1.81k
{
115
1.81k
  if (!listener.get()) {
116
0
    MWAW_DEBUG_MSG(("ZWrtParserInternal::SubDocument::parse: no listener\n"));
117
0
    return;
118
0
  }
119
1.81k
  auto *parser=dynamic_cast<ZWrtParser *>(m_parser);
120
1.81k
  if (!parser) {
121
0
    MWAW_DEBUG_MSG(("ZWrtParserInternal::SubDocument::parse: no parser\n"));
122
0
    return;
123
0
  }
124
125
1.81k
  parser->sendHeaderFooter(m_isHeader);
126
1.81k
}
127
}
128
129
130
////////////////////////////////////////////////////////////
131
// constructor/destructor, ...
132
////////////////////////////////////////////////////////////
133
ZWrtParser::ZWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
134
4.36k
  : MWAWTextParser(input, rsrcParser, header)
135
4.36k
  , m_state()
136
4.36k
  , m_textParser()
137
4.36k
{
138
4.36k
  init();
139
4.36k
}
140
141
ZWrtParser::~ZWrtParser()
142
4.36k
{
143
4.36k
}
144
145
void ZWrtParser::init()
146
4.36k
{
147
4.36k
  resetTextListener();
148
4.36k
  setAsciiName("main-1");
149
150
4.36k
  m_state.reset(new ZWrtParserInternal::State);
151
152
  // reduce the margin (in case, the page is not defined)
153
4.36k
  getPageSpan().setMargins(0.1);
154
155
4.36k
  m_textParser.reset(new ZWrtText(*this));
156
4.36k
}
157
158
MWAWInputStreamPtr ZWrtParser::rsrcInput()
159
43.1k
{
160
43.1k
  return getRSRCParser()->getInput();
161
43.1k
}
162
163
libmwaw::DebugFile &ZWrtParser::rsrcAscii()
164
22.6k
{
165
22.6k
  return getRSRCParser()->ascii();
166
22.6k
}
167
168
////////////////////////////////////////////////////////////
169
// position and height
170
////////////////////////////////////////////////////////////
171
MWAWVec2f ZWrtParser::getPageLeftTop() const
172
0
{
173
0
  return MWAWVec2f(float(getPageSpan().getMarginLeft()),
174
0
                   float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
175
0
}
176
177
////////////////////////////////////////////////////////////
178
// interface with the text parser
179
////////////////////////////////////////////////////////////
180
bool ZWrtParser::sendHeaderFooter(bool header)
181
1.81k
{
182
1.81k
  MWAWInputStreamPtr rsrc = rsrcInput();
183
1.81k
  long rsrcPos = rsrc->tell();
184
1.81k
  m_textParser->sendHeaderFooter(header);
185
1.81k
  rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
186
1.81k
  return true;
187
1.81k
}
188
189
////////////////////////////////////////////////////////////
190
// new page
191
////////////////////////////////////////////////////////////
192
void ZWrtParser::newPage(int number)
193
3.70k
{
194
3.70k
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
195
0
    return;
196
197
7.41k
  while (m_state->m_actPage < number) {
198
3.70k
    m_state->m_actPage++;
199
3.70k
    if (!getTextListener() || m_state->m_actPage == 1)
200
1.88k
      continue;
201
1.81k
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
202
1.81k
  }
203
3.70k
}
204
205
////////////////////////////////////////////////////////////
206
// the parser
207
////////////////////////////////////////////////////////////
208
void ZWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
209
2.00k
{
210
2.00k
  if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
211
2.00k
  bool ok = false;
212
2.00k
  try {
213
2.00k
    checkHeader(nullptr);
214
2.00k
    ok = createZones();
215
2.00k
    if (ok) {
216
2.00k
      createDocument(docInterface);
217
2.00k
      m_textParser->sendMainText();
218
#ifdef DEBUG
219
      m_textParser->flushExtra();
220
#endif
221
2.00k
    }
222
2.00k
  }
223
2.00k
  catch (...) {
224
0
    MWAW_DEBUG_MSG(("ZWrtParser::parse: exception catched when parsing\n"));
225
0
    ok = false;
226
0
  }
227
228
2.00k
  resetTextListener();
229
2.00k
  if (!ok) throw(libmwaw::ParseException());
230
2.00k
}
231
232
////////////////////////////////////////////////////////////
233
// create the document
234
////////////////////////////////////////////////////////////
235
void ZWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
236
2.00k
{
237
2.00k
  if (!documentInterface) return;
238
2.00k
  if (getTextListener()) {
239
0
    MWAW_DEBUG_MSG(("ZWrtParser::createDocument: listener already exist\n"));
240
0
    return;
241
0
  }
242
243
  // update the page
244
2.00k
  m_state->m_actPage = 0;
245
246
  // create the page list
247
2.00k
  int numPages = 1;
248
2.00k
  if (m_textParser->numPages() > numPages)
249
1.70k
    numPages = m_textParser->numPages();
250
2.00k
  m_state->m_numPages = numPages;
251
252
2.00k
  MWAWPageSpan ps(getPageSpan());
253
2.00k
  if (m_state->m_headerUsed && m_textParser->hasHeaderFooter(true)) {
254
1.34k
    MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
255
1.34k
    header.m_subDocument.reset(new ZWrtParserInternal::SubDocument(*this, getInput(), true));
256
1.34k
    ps.setHeaderFooter(header);
257
1.34k
  }
258
2.00k
  if (m_state->m_footerUsed && m_textParser->hasHeaderFooter(false)) {
259
472
    MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
260
472
    footer.m_subDocument.reset(new ZWrtParserInternal::SubDocument(*this, getInput(), false));
261
472
    ps.setHeaderFooter(footer);
262
472
  }
263
2.00k
  ps.setPageSpan(m_state->m_numPages+1);
264
2.00k
  std::vector<MWAWPageSpan> pageList(1,ps);
265
2.00k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
266
2.00k
  setTextListener(listen);
267
2.00k
  listen->startDocument();
268
2.00k
}
269
270
271
////////////////////////////////////////////////////////////
272
//
273
// Intermediate level
274
//
275
////////////////////////////////////////////////////////////
276
bool ZWrtParser::createZones()
277
2.00k
{
278
2.00k
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
279
2.00k
  if (!rsrcParser) {
280
0
    MWAW_DEBUG_MSG(("ZWrtParser::createZones: can not find the entry map\n"));
281
0
    return false;
282
0
  }
283
2.00k
  auto const &entryMap = rsrcParser->getEntriesMap();
284
285
  // the 128 zones
286
2.00k
  char const *zNames[] = {"BBAR", "HTML", "PRIN", "RANG", "WPOS", "PGPT"};
287
14.0k
  for (int z = 0; z < 6; z++) {
288
12.0k
    auto it = entryMap.lower_bound(zNames[z]);
289
22.4k
    while (it != entryMap.end()) {
290
22.2k
      if (it->first != zNames[z])
291
11.7k
        break;
292
10.4k
      MWAWEntry const &entry = it++->second;
293
10.4k
      bool done=true;
294
10.4k
      switch (z) {
295
1.86k
      case 0:
296
1.86k
        done=readBarState(entry);
297
1.86k
        break;
298
1.54k
      case 1:
299
1.54k
        done=readHTMLPref(entry);
300
1.54k
        break;
301
1.58k
      case 2:
302
1.58k
        done=readPrintInfo(entry);
303
1.58k
        break;
304
2.00k
      case 3:
305
2.00k
        done=readSectionRange(entry);
306
2.00k
        break;
307
1.87k
      case 4:
308
1.87k
        done=readWindowPos(entry);
309
1.87k
        break;
310
1.54k
      case 5:
311
1.54k
        done=readCPRT(entry);
312
1.54k
        break;
313
0
      default:
314
0
        done=false;
315
0
        break;
316
10.4k
      }
317
10.4k
      if (done || !entry.valid()) continue;
318
32
      readUnknownZone(entry);
319
32
    }
320
12.0k
  }
321
322
  // 1001 and following
323
2.00k
  char const *sNames[] = {"CPOS", "SLEN"};
324
6.01k
  for (int z = 0; z < 2; z++) {
325
4.01k
    auto it = entryMap.lower_bound(sNames[z]);
326
7.69k
    while (it != entryMap.end()) {
327
7.59k
      if (it->first != sNames[z])
328
3.91k
        break;
329
3.68k
      MWAWEntry const &entry = it++->second;
330
3.68k
      bool done=true;
331
3.68k
      switch (z) {
332
1.82k
      case 0:
333
1.82k
        done=readCPos(entry);
334
1.82k
        break;
335
1.85k
      case 1:
336
1.85k
        done=readSLen(entry);
337
1.85k
        break;
338
0
      default:
339
0
        done = false;
340
3.68k
      }
341
3.68k
      if (done || !entry.valid()) continue;
342
0
      readUnknownZone(entry);
343
0
    }
344
4.01k
  }
345
2.00k
  if (!m_textParser->createZones())
346
0
    return false;
347
2.00k
  return true;
348
2.00k
}
349
350
////////////////////////////////////////////////////////////
351
// read the print info
352
////////////////////////////////////////////////////////////
353
bool ZWrtParser::readPrintInfo(MWAWEntry const &entry)
354
1.58k
{
355
1.58k
  if (!entry.valid()) {
356
193
    MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the entry is bad\n"));
357
193
    return false;
358
193
  }
359
360
1.39k
  if (entry.id()!=128) {
361
75
    MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the entry id is odd\n"));
362
75
  }
363
1.39k
  long pos = entry.begin();
364
1.39k
  MWAWInputStreamPtr input = rsrcInput();
365
1.39k
  libmwaw::DebugFile &ascFile = rsrcAscii();
366
1.39k
  libmwaw::DebugStream f;
367
1.39k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
368
1.39k
  entry.setParsed(true);
369
370
1.39k
  std::vector<ZWField> fields;
371
1.39k
  if (!getFieldList(entry, fields)) {
372
0
    MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: can not get fields list\n"));
373
0
    f << "###";
374
0
    ascFile.addPos(pos-4);
375
0
    ascFile.addNote(f.str().c_str());
376
0
    return false;
377
0
  }
378
379
1.39k
  size_t numFields = fields.size();
380
1.39k
  if (numFields < 6) {
381
117
    MWAW_DEBUG_MSG(("ZWrtParser::readPrintInfo: the fields list seems very short\n"));
382
117
  }
383
1.39k
  bool boolVal;
384
1.39k
  float floatVal;
385
1.39k
  int intVal;
386
1.39k
  std::string strVal;
387
1.39k
  int margins[4]= {0,0,0,0};
388
1.39k
  bool marginsOk=true;
389
91.6k
  for (size_t ff = 0; ff < numFields; ff++) {
390
90.2k
    ZWField const &field = fields[ff];
391
90.2k
    bool done = false;
392
90.2k
    switch (ff) {
393
1.39k
    case 0: // T
394
2.70k
    case 1: // B
395
4.00k
    case 2: // L
396
5.30k
    case 3: // R
397
5.30k
      done = field.getInt(input, intVal);
398
5.30k
      if (!done) {
399
452
        marginsOk = false;
400
452
        break;
401
452
      }
402
4.85k
      margins[ff]=intVal;
403
4.85k
      break;
404
1.29k
    case 4: // 2,-2,-4
405
1.29k
      done = field.getInt(input, intVal);
406
1.29k
      if (!done||!intVal)
407
1.20k
        break;
408
82
      f << "autoResize=" << intVal << ",";
409
82
      break;
410
1.27k
    case 5: //1.2
411
1.27k
      done = field.getFloat(input, floatVal);
412
1.27k
      if (!done)
413
124
        break;
414
1.15k
      f << "lineSpacing=" << floatVal << ",";
415
1.15k
      break;
416
1.23k
    case 6:
417
2.47k
    case 7: // always set
418
3.67k
    case 8: // always set
419
3.67k
      done = field.getBool(input, boolVal);
420
3.67k
      if (!done)
421
448
        break;
422
3.22k
      if (!boolVal)
423
157
        continue;
424
3.06k
      switch (ff) { // checkme: does not seems to works in all case...
425
1.12k
      case 6:
426
1.12k
        f << "sectionAddNewPage,";
427
1.12k
        break;
428
1.11k
      case 7:
429
1.11k
        f << "useHeader,";
430
1.11k
        break;
431
830
      case 8:
432
830
        f << "useFooter,";
433
830
        break;
434
0
      default:
435
0
        f << "#f" << ff << "Set,";
436
0
        break;
437
3.06k
      }
438
3.06k
      break;
439
78.7k
    default:
440
78.7k
      break;
441
90.2k
    }
442
90.0k
    if (done)
443
10.2k
      continue;
444
79.8k
    if (fields[ff].getDebugString(input, strVal))
445
79.8k
      f << "#f" << ff << "=\"" << strVal << "\",";
446
0
    else
447
0
      f << "#f" << ff << ",";
448
79.8k
  }
449
1.39k
  if (marginsOk) {
450
1.16k
    getPageSpan().setMarginTop(double(margins[0])/72.0);
451
1.16k
    getPageSpan().setMarginBottom(double(margins[1])/72.0);
452
1.16k
    getPageSpan().setMarginLeft(double(margins[2])/72.0);
453
1.16k
    getPageSpan().setMarginRight(double(margins[3])/72.0);
454
1.16k
  }
455
1.39k
  f << "margins=(" << margins[2] << "x" << margins[0] << "<->" << margins[3] << "x" << margins[1] << "),";
456
1.39k
  ascFile.addPos(pos-4);
457
1.39k
  ascFile.addNote(f.str().c_str());
458
1.39k
  return true;
459
1.39k
}
460
461
// read the print info xml data
462
bool ZWrtParser::readCPRT(MWAWEntry const &entry)
463
1.54k
{
464
1.54k
  if (entry.length() < 0x10) {
465
377
    MWAW_DEBUG_MSG(("ZWrtParser::readCPRT: data seems to short\n"));
466
377
    return false;
467
377
  }
468
469
1.17k
  MWAWInputStreamPtr input = rsrcInput();
470
1.17k
  long pos = entry.begin();
471
1.17k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
472
#ifdef DEBUG_WITH_FILES
473
  libmwaw::DebugFile &ascFile = rsrcAscii();
474
  librevenge::RVNGBinaryData file;
475
  input->readDataBlock(entry.length(), file);
476
477
  static int volatile cprtName = 0;
478
  libmwaw::DebugStream f;
479
  f << "CPRT" << ++cprtName << ".plist";
480
  libmwaw::Debug::dumpFile(file, f.str().c_str());
481
482
  ascFile.addPos(pos-4);
483
  ascFile.addNote(f.str().c_str());
484
  ascFile.skipZone(entry.begin(),entry.end()-1);
485
#endif
486
1.17k
  return true;
487
1.54k
}
488
489
////////////////////////////////////////////////////////////
490
// read the bar state/windows pos, ...
491
////////////////////////////////////////////////////////////
492
bool ZWrtParser::readBarState(MWAWEntry const &entry)
493
1.86k
{
494
1.86k
  if (!entry.valid()) {
495
83
    MWAW_DEBUG_MSG(("ZWrtParser::readBarState: the entry is bad\n"));
496
83
    return false;
497
83
  }
498
499
1.77k
  if (entry.id()!=128) {
500
133
    MWAW_DEBUG_MSG(("ZWrtParser::readBarState: the entry id is odd\n"));
501
133
  }
502
1.77k
  long pos = entry.begin();
503
1.77k
  MWAWInputStreamPtr input = rsrcInput();
504
1.77k
  libmwaw::DebugFile &ascFile = rsrcAscii();
505
1.77k
  libmwaw::DebugStream f;
506
1.77k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
507
1.77k
  entry.setParsed(true);
508
509
1.77k
  std::vector<ZWField> fields;
510
1.77k
  if (!getFieldList(entry, fields) || !fields.size()) {
511
0
    MWAW_DEBUG_MSG(("ZWrtParser::readBarState: can not get fields list\n"));
512
0
    f << "###";
513
0
    ascFile.addPos(pos-4);
514
0
    ascFile.addNote(f.str().c_str());
515
0
    return false;
516
0
  }
517
1.77k
  std::string res("");
518
1.77k
  if (fields[0].getString(input, res))
519
1.77k
    f << "set=" << res << ",";
520
0
  else
521
0
    f << "#set,";
522
1.77k
  size_t numFields = fields.size();
523
1.77k
  if (numFields > 1) {
524
608
    MWAW_DEBUG_MSG(("ZWrtParser::readBarState: find extra fields\n"));
525
608
  }
526
15.1k
  for (size_t ff = 1; ff < numFields; ff++) {
527
13.3k
    if (fields[ff].getDebugString(input, res))
528
13.3k
      f << "#f" << ff << "=\"" << res << "\",";
529
0
    else
530
0
      f << "#f" << ff << ",";
531
13.3k
  }
532
533
1.77k
  ascFile.addPos(pos-4);
534
1.77k
  ascFile.addNote(f.str().c_str());
535
1.77k
  return true;
536
1.77k
}
537
538
bool ZWrtParser::readHTMLPref(MWAWEntry const &entry)
539
1.54k
{
540
1.54k
  if (!entry.valid()) {
541
218
    MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the entry is bad\n"));
542
218
    return false;
543
218
  }
544
545
1.32k
  if (entry.id()!=128) {
546
208
    MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the entry id is odd\n"));
547
208
  }
548
1.32k
  long pos = entry.begin();
549
1.32k
  MWAWInputStreamPtr input = rsrcInput();
550
1.32k
  libmwaw::DebugFile &ascFile = rsrcAscii();
551
1.32k
  libmwaw::DebugStream f;
552
1.32k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
553
1.32k
  entry.setParsed(true);
554
555
1.32k
  std::vector<ZWField> fields;
556
1.32k
  if (!getFieldList(entry, fields)) {
557
0
    MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: can not get fields list\n"));
558
0
    f << "###";
559
0
    ascFile.addPos(pos-4);
560
0
    ascFile.addNote(f.str().c_str());
561
0
    return false;
562
0
  }
563
564
1.32k
  size_t numFields = fields.size();
565
1.32k
  if (numFields < 4) {
566
321
    MWAW_DEBUG_MSG(("ZWrtParser::readHTMLPref: the fields list seems very short\n"));
567
321
  }
568
1.32k
  std::string strVal;
569
1.32k
  bool boolVal;
570
44.8k
  for (size_t ff = 0; ff < numFields; ff++) {
571
43.5k
    ZWField const &field = fields[ff];
572
43.5k
    bool done = false;
573
43.5k
    switch (ff) {
574
1.32k
    case 0:
575
2.51k
    case 1:
576
3.53k
    case 2: // always true?
577
4.53k
    case 3: // true if name?
578
4.53k
      done = field.getBool(input, boolVal);
579
4.53k
      if (!done || !boolVal)
580
2.77k
        break;
581
1.76k
      f << "f" << ff << "Set,";
582
1.76k
      break;
583
985
    case 4: // find one time sidebar
584
985
      done = field.getString(input, strVal);
585
985
      if (!done||!strVal.length())
586
667
        break;
587
318
      f << "name=" << strVal << ",";
588
318
      break;
589
38.0k
    default:
590
38.0k
      break;
591
43.5k
    }
592
43.5k
    if (done)
593
4.88k
      continue;
594
38.6k
    if (fields[ff].getDebugString(input, strVal))
595
38.6k
      f << "#f" << ff << "=\"" << strVal << "\",";
596
0
    else
597
0
      f << "#f" << ff << ",";
598
38.6k
  }
599
1.32k
  ascFile.addPos(pos-4);
600
1.32k
  ascFile.addNote(f.str().c_str());
601
1.32k
  return true;
602
1.32k
}
603
604
bool ZWrtParser::readSectionRange(MWAWEntry const &entry)
605
2.00k
{
606
2.00k
  long pos = entry.begin();
607
2.00k
  if (pos <= 0) {
608
0
    MWAW_DEBUG_MSG(("ZWrtParser::readSectionRange: the entry is bad\n"));
609
0
    return false;
610
0
  }
611
612
2.00k
  MWAWInputStreamPtr input = rsrcInput();
613
2.00k
  libmwaw::DebugFile &ascFile = rsrcAscii();
614
2.00k
  libmwaw::DebugStream f;
615
2.00k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
616
2.00k
  entry.setParsed(true);
617
618
2.00k
  if (entry.length() <= 0) {
619
1.45k
    ascFile.addPos(pos-4);
620
1.45k
    ascFile.addNote(f.str().c_str());
621
1.45k
    return true;
622
1.45k
  }
623
548
  input->seek(pos, librevenge::RVNG_SEEK_SET);
624
548
  pos -= 4;
625
548
  std::string name("");
626
548
  int num=0;
627
58.3k
  while (!input->isEnd()) {
628
58.3k
    bool done=input->tell()>=entry.end();
629
58.3k
    char c = done ? char(0xa) : char(input->readULong(1));
630
58.3k
    if (c==0) {
631
424
      MWAW_DEBUG_MSG(("ZWrtParser::readSectionRange: find a 0 char\n"));
632
424
      name +="##[0]";
633
424
      continue;
634
424
    }
635
57.9k
    if (c!=0xa) {
636
55.8k
      name += c;
637
55.8k
      continue;
638
55.8k
    }
639
640
2.11k
    f << name;
641
2.11k
    ascFile.addPos(pos);
642
2.11k
    ascFile.addNote(f.str().c_str());
643
2.11k
    pos = input->tell();
644
2.11k
    name = "";
645
2.11k
    f.str("");
646
2.11k
    f << entry.type() << "-" << ++num << ":";
647
2.11k
    if (done)
648
548
      break;
649
2.11k
  }
650
548
  if (name.length()) {
651
0
    f << name;
652
0
    ascFile.addPos(pos);
653
0
    ascFile.addNote(f.str().c_str());
654
0
  }
655
548
  return true;
656
2.00k
}
657
658
bool ZWrtParser::readWindowPos(MWAWEntry const &entry)
659
1.87k
{
660
1.87k
  if (!entry.valid()) {
661
511
    MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the entry is bad\n"));
662
511
    return false;
663
511
  }
664
665
1.36k
  if (entry.id()!=128) {
666
157
    MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the entry id is odd\n"));
667
157
  }
668
1.36k
  long pos = entry.begin();
669
1.36k
  MWAWInputStreamPtr input = rsrcInput();
670
1.36k
  libmwaw::DebugFile &ascFile = rsrcAscii();
671
1.36k
  libmwaw::DebugStream f;
672
1.36k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
673
1.36k
  entry.setParsed(true);
674
675
1.36k
  std::vector<ZWField> fields;
676
1.36k
  if (!getFieldList(entry, fields)) {
677
0
    MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: can not get fields list\n"));
678
0
    f << "###";
679
0
    ascFile.addPos(pos-4);
680
0
    ascFile.addNote(f.str().c_str());
681
0
    return false;
682
0
  }
683
684
1.36k
  size_t numFields = fields.size();
685
1.36k
  if (numFields < 6) {
686
340
    MWAW_DEBUG_MSG(("ZWrtParser::readWindowPos: the fields list seems very short\n"));
687
340
  }
688
1.36k
  std::string strVal;
689
1.36k
  int intVal;
690
1.36k
  int dim[4]= {0,0,0,0};
691
68.1k
  for (size_t ff = 0; ff < numFields; ff++) {
692
66.7k
    ZWField const &field = fields[ff];
693
66.7k
    bool done = false;
694
66.7k
    switch (ff) {
695
1.36k
    case 0:
696
2.59k
    case 1:
697
3.81k
    case 2:
698
5.02k
    case 3:
699
5.02k
      done = field.getInt(input, intVal);
700
5.02k
      if (!done)
701
224
        break;
702
4.80k
      dim[ff]=intVal;
703
4.80k
      break;
704
1.18k
    case 4: // 137|139|144
705
2.21k
    case 5: // 0|3|9|12 ( actual section ?)
706
2.21k
      done = field.getInt(input, intVal);
707
2.21k
      if (!done||!intVal)
708
1.17k
        break;
709
1.04k
      f << "f" << ff << "=" << intVal << ",";
710
1.04k
      break;
711
59.5k
    default:
712
59.5k
      break;
713
66.7k
    }
714
66.7k
    if (done)
715
6.71k
      continue;
716
60.0k
    if (fields[ff].getDebugString(input, strVal))
717
60.0k
      f << "#f" << ff << "=\"" << strVal << "\",";
718
0
    else
719
0
      f << "#f" << ff << ",";
720
60.0k
  }
721
1.36k
  f << "pos=(" << dim[0] << "x" << dim[1] << "<->" << dim[2] << "x" << dim[3] << "),";
722
1.36k
  ascFile.addPos(pos-4);
723
1.36k
  ascFile.addNote(f.str().c_str());
724
1.36k
  return true;
725
1.36k
}
726
727
////////////////////////////////////////////////////////////
728
// read a section zone ...
729
////////////////////////////////////////////////////////////
730
731
// read a cursor position in a section ?
732
bool ZWrtParser::readCPos(MWAWEntry const &entry)
733
1.82k
{
734
1.82k
  if (!entry.valid()) {
735
149
    MWAW_DEBUG_MSG(("ZWrtParser::readCPos: the entry is bad\n"));
736
149
    return false;
737
149
  }
738
739
1.67k
  long pos = entry.begin();
740
1.67k
  MWAWInputStreamPtr input = rsrcInput();
741
1.67k
  libmwaw::DebugFile &ascFile = rsrcAscii();
742
1.67k
  libmwaw::DebugStream f;
743
1.67k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
744
1.67k
  entry.setParsed(true);
745
746
1.67k
  std::vector<ZWField> fields;
747
1.67k
  if (!getFieldList(entry, fields) || !fields.size()) {
748
0
    MWAW_DEBUG_MSG(("ZWrtParser::readCPos: can not get fields list\n"));
749
0
    f << "###";
750
0
    ascFile.addPos(pos-4);
751
0
    ascFile.addNote(f.str().c_str());
752
0
    return false;
753
0
  }
754
1.67k
  int intVal;
755
1.67k
  size_t ff=0;
756
1.67k
  if (fields[ff++].getInt(input, intVal)) {
757
1.00k
    if (intVal)
758
993
      f << "cPos=" << intVal << ",";
759
1.00k
  }
760
676
  else {
761
676
    MWAW_DEBUG_MSG(("ZWrtParser::readCPos: can not read cursor pos\n"));
762
676
    ff = 0;
763
676
  }
764
1.67k
  size_t numFields = fields.size();
765
1.67k
  if (numFields > 1) {
766
264
    MWAW_DEBUG_MSG(("ZWrtParser::readCPos: find extra fields\n"));
767
264
  }
768
1.67k
  std::string res;
769
19.4k
  for (; ff < numFields; ff++) {
770
17.7k
    if (fields[ff].getDebugString(input, res))
771
17.7k
      f << "#f" << ff << "=\"" << res << "\",";
772
0
    else
773
0
      f << "#f" << ff << ",";
774
17.7k
  }
775
776
1.67k
  ascFile.addPos(pos-4);
777
1.67k
  ascFile.addNote(f.str().c_str());
778
1.67k
  return true;
779
1.67k
}
780
781
// read a cursor position in a section ?
782
bool ZWrtParser::readSLen(MWAWEntry const &entry)
783
1.85k
{
784
1.85k
  if (!entry.valid()) {
785
57
    MWAW_DEBUG_MSG(("ZWrtParser::readSLen: the entry is bad\n"));
786
57
    return false;
787
57
  }
788
789
1.80k
  long pos = entry.begin();
790
1.80k
  MWAWInputStreamPtr input = rsrcInput();
791
1.80k
  libmwaw::DebugFile &ascFile = rsrcAscii();
792
1.80k
  libmwaw::DebugStream f;
793
1.80k
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
794
1.80k
  entry.setParsed(true);
795
796
1.80k
  std::vector<ZWField> fields;
797
1.80k
  if (!getFieldList(entry, fields) || !fields.size()) {
798
0
    MWAW_DEBUG_MSG(("ZWrtParser::readSLen: can not get fields list\n"));
799
0
    f << "###";
800
0
    ascFile.addPos(pos-4);
801
0
    ascFile.addNote(f.str().c_str());
802
0
    return false;
803
0
  }
804
1.80k
  int intVal;
805
1.80k
  size_t ff=0;
806
1.80k
  if (fields[ff++].getInt(input, intVal)) {
807
1.17k
    if (intVal)
808
104
      f << "len?=" << intVal << ",";
809
1.17k
  }
810
622
  else {
811
622
    MWAW_DEBUG_MSG(("ZWrtParser::readSLen: can not read cursor pos\n"));
812
622
    ff = 0;
813
622
  }
814
1.80k
  size_t numFields = fields.size();
815
1.80k
  if (numFields > 1) {
816
617
    MWAW_DEBUG_MSG(("ZWrtParser::readSLen: find extra fields\n"));
817
617
  }
818
1.80k
  std::string res;
819
76.2k
  for (; ff < numFields; ff++) {
820
74.4k
    if (fields[ff].getDebugString(input, res))
821
74.4k
      f << "#f" << ff << "=\"" << res << "\",";
822
0
    else
823
0
      f << "#f" << ff << ",";
824
74.4k
  }
825
826
1.80k
  ascFile.addPos(pos-4);
827
1.80k
  ascFile.addNote(f.str().c_str());
828
1.80k
  return true;
829
1.80k
}
830
831
////////////////////////////////////////////////////////////
832
// read a generic zone ...
833
////////////////////////////////////////////////////////////
834
bool ZWrtParser::readUnknownZone(MWAWEntry const &entry)
835
32
{
836
32
  if (entry.begin() <= 0) {
837
0
    MWAW_DEBUG_MSG(("ZWrtParser::readUnknownZone: the entry is bad\n"));
838
0
    return false;
839
0
  }
840
841
32
  MWAWInputStreamPtr input = rsrcInput();
842
32
  libmwaw::DebugFile &ascFile = rsrcAscii();
843
32
  long pos = entry.begin();
844
845
32
  libmwaw::DebugStream f;
846
32
  f << "Entries(" << entry.type() << ")[" << entry << "]:";
847
32
  entry.setParsed(true);
848
849
32
  std::vector<ZWField> fields;
850
32
  if (!getFieldList(entry, fields)) {
851
0
    MWAW_DEBUG_MSG(("ZWrtParser::readUnknownZone: can not get fields list\n"));
852
0
    f << "###";
853
0
    ascFile.addPos(pos-4);
854
0
    ascFile.addNote(f.str().c_str());
855
0
    return false;
856
0
  }
857
32
  std::string res("");
858
32
  size_t numFields = fields.size();
859
189
  for (size_t ff = 0; ff < numFields; ff++) {
860
157
    if (fields[ff].getDebugString(input, res))
861
157
      f << "f" << ff << "=\"" << res << "\",";
862
0
    else
863
0
      f << "#f" << ff << ",";
864
157
  }
865
866
32
  ascFile.addPos(pos-4);
867
32
  ascFile.addNote(f.str().c_str());
868
32
  return true;
869
32
}
870
871
////////////////////////////////////////////////////////////
872
//
873
// Low level
874
//
875
////////////////////////////////////////////////////////////
876
877
////////////////////////////////////////////////////////////
878
// read the header
879
////////////////////////////////////////////////////////////
880
bool ZWrtParser::checkHeader(MWAWHeader *header, bool strict)
881
6.37k
{
882
6.37k
  *m_state = ZWrtParserInternal::State();
883
6.37k
  if (!getRSRCParser())
884
68
    return false;
885
  // check if the RANG section exists
886
6.30k
  MWAWEntry entry = getRSRCParser()->getEntry("RANG", 128);
887
6.30k
  if (entry.begin()<=0) { // length can be 0, so ...
888
164
    MWAW_DEBUG_MSG(("ZWrtParser::checkHeader: can not find the RANG[128] resource\n"));
889
164
    return false;
890
164
  }
891
6.13k
  if (getInput()->hasDataFork() && getInput()->size()>0) {
892
0
    MWAW_DEBUG_MSG(("ZWrtParser::checkHeader: find some data fork\n"));
893
0
    if (strict)
894
0
      return false;
895
0
  }
896
6.13k
  if (header)
897
2.12k
    header->reset(MWAWDocument::MWAW_T_ZWRITE, 1);
898
899
6.13k
  return true;
900
6.13k
}
901
902
////////////////////////////////////////////////////////////
903
// read a list of field
904
////////////////////////////////////////////////////////////
905
bool ZWrtParser::getFieldList(MWAWEntry const &entry, std::vector<ZWField> &list)
906
13.7k
{
907
13.7k
  list.resize(0);
908
13.7k
  MWAWInputStreamPtr input = rsrcInput();
909
13.7k
  long pos=entry.begin();
910
13.7k
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
911
6.18M
  while (!input->isEnd()) {
912
6.18M
    long actPos=input->tell();
913
6.18M
    long done = actPos>=entry.end();
914
6.18M
    char c= done ? '\t' : char(input->readULong(1));
915
6.18M
    if (c=='\t') {
916
586k
      ZWField field;
917
586k
      field.m_pos.setBegin(pos);
918
586k
      field.m_pos.setEnd(actPos);
919
586k
      pos = actPos+1;
920
586k
      list.push_back(field);
921
586k
      if (done)
922
13.7k
        return true;
923
572k
      continue;
924
586k
    }
925
6.18M
  }
926
0
  return true;
927
13.7k
}
928
929
////////////////////////////////////////////////////////////
930
// field function
931
////////////////////////////////////////////////////////////
932
bool ZWField::getString(MWAWInputStreamPtr &input, std::string &str) const
933
60.2k
{
934
60.2k
  str="";
935
60.2k
  if (!m_pos.valid())
936
1.81k
    return true;
937
58.4k
  input->seek(m_pos.begin(), librevenge::RVNG_SEEK_SET);
938
1.22M
  while (!input->isEnd() && input->tell()!=m_pos.end()) {
939
1.17M
    auto c=char(input->readULong(1));
940
1.17M
    if (c==0) {
941
389k
      MWAW_DEBUG_MSG(("ZWField::getString::readFieldString: find a zero entry\n"));
942
389k
      str += "##[0]";
943
389k
      continue;
944
389k
    }
945
781k
    str += c;
946
781k
  }
947
58.4k
  return true;
948
60.2k
}
949
950
bool ZWField::getDebugString(MWAWInputStreamPtr &input, std::string &str) const
951
534k
{
952
534k
  str="";
953
534k
  if (!m_pos.valid())
954
313k
    return true;
955
220k
  input->seek(m_pos.begin(), librevenge::RVNG_SEEK_SET);
956
220k
  std::stringstream ss;
957
5.35M
  while (!input->isEnd() && input->tell()!=m_pos.end()) {
958
5.13M
    auto c=char(input->readULong(1));
959
5.13M
    if (static_cast<unsigned char>(c)<=0x1f && c!= 0x9)
960
570k
      ss << "##[" << std::hex << int(c) << std::dec << "]";
961
4.56M
    else
962
4.56M
      ss << c;
963
5.13M
  }
964
220k
  str = ss.str();
965
220k
  return true;
966
534k
}
967
968
bool ZWField::getBool(MWAWInputStreamPtr &input, bool &val) const
969
22.4k
{
970
22.4k
  val = false;
971
22.4k
  if (m_pos.length()==0 && m_pos.begin()>0)
972
573
    return true;
973
21.8k
  std::string str;
974
21.8k
  if (!getString(input,str) || str.length() != 1) {
975
3.09k
    MWAW_DEBUG_MSG(("ZWField::getBool: can not read field\n"));
976
3.09k
    return false;
977
3.09k
  }
978
18.7k
  if (str[0]=='T')
979
6.31k
    val = true;
980
12.4k
  else if (str[0]=='F')
981
11.5k
    val = false;
982
920
  else {
983
920
    MWAW_DEBUG_MSG(("ZWField::getBool: find unexpected char %x\n", static_cast<unsigned int>(str[0])));
984
920
    return false;
985
920
  }
986
17.8k
  return true;
987
18.7k
}
988
989
bool ZWField::getInt(MWAWInputStreamPtr &input, int &val) const
990
27.4k
{
991
27.4k
  val = 0;
992
27.4k
  std::string str;
993
27.4k
  if (!getString(input,str) || str.length() == 0) {
994
180
    MWAW_DEBUG_MSG(("ZWField::getInt: can not read field\n"));
995
180
    return false;
996
180
  }
997
27.2k
  int sign = 1;
998
27.2k
  size_t numChar = str.length();
999
27.2k
  size_t p = 0;
1000
27.2k
  if (str[0]=='-') {
1001
535
    sign = -1;
1002
535
    p++;
1003
535
  }
1004
74.0k
  while (p < numChar) {
1005
51.2k
    char c = str[p++];
1006
51.2k
    if (c>='0' && c <= '9') {
1007
46.8k
      val = 10*val+(c-'0');
1008
46.8k
      continue;
1009
46.8k
    }
1010
4.47k
    MWAW_DEBUG_MSG(("ZWField::getInt: find unexpected char %x\n", static_cast<unsigned int>(c)));
1011
4.47k
    val *= sign;
1012
4.47k
    return false;
1013
51.2k
  }
1014
22.7k
  val *= sign;
1015
22.7k
  return true;
1016
27.2k
}
1017
1018
bool ZWField::getFloat(MWAWInputStreamPtr &input, float &val) const
1019
1.27k
{
1020
1.27k
  val = 0;
1021
1.27k
  std::string str;
1022
1.27k
  if (!getString(input,str) || str.length() == 0) {
1023
12
    MWAW_DEBUG_MSG(("ZWField::getFloat: can not read field\n"));
1024
12
    return false;
1025
12
  }
1026
1.26k
  std::stringstream ss;
1027
1.26k
  ss << str;
1028
1.26k
  ss >> val;
1029
1.26k
  return !(!ss);
1030
1.27k
}
1031
1032
bool ZWField::getIntList(MWAWInputStreamPtr &input, std::vector<int> &list) const
1033
2.84k
{
1034
2.84k
  list.resize(0);
1035
2.84k
  std::string str;
1036
2.84k
  if (!getString(input,str) || str.length() == 0) {
1037
1
    MWAW_DEBUG_MSG(("ZWField::getIntList: can not read field\n"));
1038
1
    return false;
1039
1
  }
1040
2.84k
  int sign = 1, val=0;
1041
2.84k
  size_t numChar = str.length();
1042
2.84k
  size_t p = 0;
1043
20.9k
  while (p <= numChar) {
1044
20.9k
    if (p==numChar) {
1045
2.35k
      list.push_back(sign *val);
1046
2.35k
      break;
1047
2.35k
    }
1048
18.5k
    char c = str[p++];
1049
18.5k
    if (c==',') {
1050
4.80k
      list.push_back(sign *val);
1051
4.80k
      val = 0;
1052
4.80k
      sign = 1;
1053
4.80k
      continue;
1054
4.80k
    }
1055
13.7k
    if (c=='-') {
1056
100
      if (val != 0 || sign != 1) {
1057
59
        MWAW_DEBUG_MSG(("ZWField::getIntList: find a int inside a word\n"));
1058
59
        return list.size();
1059
59
      }
1060
41
      sign = -1;
1061
41
    }
1062
13.7k
    if (c>='0' && c <= '9') {
1063
13.2k
      val = 10*val+(c-'0');
1064
13.2k
      continue;
1065
13.2k
    }
1066
431
    MWAW_DEBUG_MSG(("ZWField::getIntList: find unexpected char %x\n", static_cast<unsigned int>(c)));
1067
431
    return list.size();
1068
13.7k
  }
1069
2.35k
  return true;
1070
2.84k
}
1071
1072
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: