Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/LightWayTxtParser.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 "LightWayTxtGraph.hxx"
51
#include "LightWayTxtText.hxx"
52
53
#include "LightWayTxtParser.hxx"
54
55
/** Internal: the structures of a LightWayTxtParser */
56
namespace LightWayTxtParserInternal
57
{
58
////////////////////////////////////////
59
//! Internal: the state of a LightWayTxtParser
60
struct State {
61
  //! constructor
62
  State()
63
3.62k
    : m_isApplication(false)
64
3.62k
    , m_actPage(0)
65
3.62k
    , m_numPages(0)
66
3.62k
    , m_numCol(1)
67
3.62k
    , m_colSep(0)
68
3.62k
    , m_headerHeight(0)
69
3.62k
    , m_footerHeight(0)
70
3.62k
  {
71
3.62k
  }
72
73
  /** true if we are parsing a application document */
74
  bool m_isApplication;
75
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
76
77
  int m_numCol /** the number of columns */,
78
      m_colSep /** the columns separator width in point */;
79
  int m_headerHeight /** the header height if known */,
80
      m_footerHeight /** the footer height if known */;
81
};
82
83
////////////////////////////////////////
84
//! Internal: the subdocument of a LightWayTxtParser
85
class SubDocument final : public MWAWSubDocument
86
{
87
public:
88
  SubDocument(LightWayTxtParser &pars, MWAWInputStreamPtr const &input, bool header)
89
0
    : MWAWSubDocument(&pars, input, MWAWEntry())
90
0
    , m_isHeader(header)
91
0
  {
92
0
  }
93
94
  //! destructor
95
0
  ~SubDocument() final {}
96
97
  //! operator!=
98
  bool operator!=(MWAWSubDocument const &doc) const final
99
0
  {
100
0
    if (MWAWSubDocument::operator!=(doc)) return true;
101
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
102
0
    if (!sDoc) return true;
103
0
    if (m_isHeader != sDoc->m_isHeader) return true;
104
0
    return false;
105
0
  }
106
107
  //! the parser function
108
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
109
110
protected:
111
  //! true if we need to send the parser
112
  int m_isHeader;
113
};
114
115
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
116
0
{
117
0
  if (!listener.get()) {
118
0
    MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no listener\n"));
119
0
    return;
120
0
  }
121
0
  auto *parser=dynamic_cast<LightWayTxtParser *>(m_parser);
122
0
  if (!parser) {
123
0
    MWAW_DEBUG_MSG(("LightWayTxtParserInternal::SubDocument::parse: no parser\n"));
124
0
    return;
125
0
  }
126
127
0
  parser->sendHeaderFooter(m_isHeader);
128
0
}
129
}
130
131
132
////////////////////////////////////////////////////////////
133
// constructor/destructor, ...
134
////////////////////////////////////////////////////////////
135
LightWayTxtParser::LightWayTxtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
136
1.59k
  : MWAWTextParser(input, rsrcParser, header)
137
1.59k
  , m_state()
138
1.59k
  , m_pageSpanSet(false)
139
1.59k
  , m_graphParser()
140
1.59k
  , m_textParser()
141
1.59k
{
142
1.59k
  init();
143
1.59k
}
144
145
LightWayTxtParser::~LightWayTxtParser()
146
1.59k
{
147
1.59k
}
148
149
void LightWayTxtParser::init()
150
1.59k
{
151
1.59k
  resetTextListener();
152
1.59k
  setAsciiName("main-1");
153
154
1.59k
  m_state.reset(new LightWayTxtParserInternal::State);
155
156
  // reduce the margin (in case, the page is not defined)
157
1.59k
  getPageSpan().setMargins(0.1);
158
159
1.59k
  m_graphParser.reset(new LightWayTxtGraph(*this));
160
1.59k
  m_textParser.reset(new LightWayTxtText(*this));
161
1.59k
}
162
163
MWAWInputStreamPtr LightWayTxtParser::rsrcInput()
164
1.15k
{
165
1.15k
  return getRSRCParser()->getInput();
166
1.15k
}
167
168
libmwaw::DebugFile &LightWayTxtParser::rsrcAscii()
169
1.15k
{
170
1.15k
  return getRSRCParser()->ascii();
171
1.15k
}
172
173
bool LightWayTxtParser::textInDataFork() const
174
432
{
175
432
  return !m_state->m_isApplication;
176
432
}
177
178
////////////////////////////////////////////////////////////
179
// position and height
180
////////////////////////////////////////////////////////////
181
MWAWVec2f LightWayTxtParser::getPageLeftTop() const
182
0
{
183
0
  return MWAWVec2f(float(getPageSpan().getMarginLeft()),
184
0
                   float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
185
0
}
186
187
////////////////////////////////////////////////////////////
188
// interface with the text parser
189
////////////////////////////////////////////////////////////
190
bool LightWayTxtParser::getColumnInfo(int &numCols, int &colSep) const
191
432
{
192
432
  if (m_state->m_numCol < 1) {
193
162
    numCols = 1;
194
162
    colSep = 0;
195
162
    return false;
196
162
  }
197
270
  numCols = m_state->m_numCol;
198
270
  colSep = m_state->m_colSep;
199
270
  return true;
200
432
}
201
202
bool LightWayTxtParser::sendHeaderFooter(bool header)
203
0
{
204
0
  MWAWInputStreamPtr input = getInput();
205
0
  MWAWInputStreamPtr rsrc = rsrcInput();
206
0
  long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0;
207
0
  m_textParser->sendHeaderFooter(header);
208
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
209
0
  if (rsrc)
210
0
    rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
211
0
  return true;
212
0
}
213
214
////////////////////////////////////////////////////////////
215
// interface with the graph parser
216
////////////////////////////////////////////////////////////
217
void LightWayTxtParser::sendGraphic(int graphId)
218
0
{
219
0
  MWAWInputStreamPtr input = getInput();
220
0
  MWAWInputStreamPtr rsrc = rsrcInput();
221
0
  long pos = input->tell(), rsrcPos = rsrc ? rsrc->tell() : 0;
222
0
  m_graphParser->send(graphId);
223
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
224
0
  if (rsrc)
225
0
    rsrc->seek(rsrcPos, librevenge::RVNG_SEEK_SET);
226
0
}
227
228
////////////////////////////////////////////////////////////
229
// new page
230
////////////////////////////////////////////////////////////
231
void LightWayTxtParser::newPage(int number)
232
0
{
233
0
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
234
0
    return;
235
236
0
  while (m_state->m_actPage < number) {
237
0
    m_state->m_actPage++;
238
0
    if (!getTextListener() || m_state->m_actPage == 1)
239
0
      continue;
240
0
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
241
0
  }
242
0
}
243
244
////////////////////////////////////////////////////////////
245
// the parser
246
////////////////////////////////////////////////////////////
247
void LightWayTxtParser::parse(librevenge::RVNGTextInterface *docInterface)
248
432
{
249
432
  if (!getInput().get() || !getRSRCParser() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
250
432
  bool ok = false;
251
432
  try {
252
    // create the asciiFile
253
432
    ascii().setStream(getInput());
254
432
    ascii().open(asciiName());
255
432
    checkHeader(nullptr);
256
432
    ok = createZones();
257
432
    if (ok) {
258
432
      createDocument(docInterface);
259
432
      m_graphParser->sendPageGraphics();
260
432
      m_textParser->sendMainText();
261
#ifdef DEBUG
262
      m_graphParser->flushExtra();
263
      m_textParser->flushExtra();
264
#endif
265
432
    }
266
432
    ascii().reset();
267
432
  }
268
432
  catch (...) {
269
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::parse: exception catched when parsing\n"));
270
0
    ok = false;
271
0
  }
272
273
432
  resetTextListener();
274
432
  if (!ok) throw(libmwaw::ParseException());
275
432
}
276
277
////////////////////////////////////////////////////////////
278
// create the document
279
////////////////////////////////////////////////////////////
280
void LightWayTxtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
281
432
{
282
432
  if (!documentInterface) return;
283
432
  if (getTextListener()) {
284
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::createDocument: listener already exist\n"));
285
0
    return;
286
0
  }
287
288
  // update the page
289
432
  m_state->m_actPage = 0;
290
291
  // create the page list
292
432
  int numPages = 1;
293
432
  if (m_graphParser->numPages() > numPages)
294
0
    numPages = m_graphParser->numPages();
295
432
  if (m_textParser->numPages() > numPages)
296
0
    numPages = m_textParser->numPages();
297
432
  m_state->m_numPages = numPages;
298
299
432
  MWAWPageSpan ps(getPageSpan());
300
432
  if (m_textParser->hasHeaderFooter(true)) {
301
0
    MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
302
0
    header.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), true));
303
0
    ps.setHeaderFooter(header);
304
0
  }
305
432
  if (m_textParser->hasHeaderFooter(false)) {
306
0
    MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
307
0
    footer.m_subDocument.reset(new LightWayTxtParserInternal::SubDocument(*this, getInput(), false));
308
0
    ps.setHeaderFooter(footer);
309
0
  }
310
432
  ps.setPageSpan(m_state->m_numPages+1);
311
432
  std::vector<MWAWPageSpan> pageList(1,ps);
312
432
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
313
432
  setTextListener(listen);
314
432
  listen->startDocument();
315
432
}
316
317
318
////////////////////////////////////////////////////////////
319
//
320
// Intermediate level
321
//
322
////////////////////////////////////////////////////////////
323
bool LightWayTxtParser::createZones()
324
432
{
325
432
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
326
432
  if (!rsrcParser) {
327
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::createZones: can not find the entry map\n"));
328
0
    return false;
329
0
  }
330
432
  auto const &entryMap = rsrcParser->getEntriesMap();
331
332
  // the different zones
333
432
  auto it = entryMap.lower_bound("LWSR");
334
864
  while (it != entryMap.end()) {
335
852
    if (it->first != "LWSR")
336
420
      break;
337
338
432
    MWAWEntry const &entry = it++->second;
339
432
    switch (entry.id()) {
340
432
    case 1000:
341
432
      readDocument(entry);
342
432
      break;
343
0
    case 1001:
344
0
      readPrintInfo(entry);
345
0
      break;
346
0
    case 1002: // a list of int ?
347
0
      readLWSR2(entry);
348
0
      break;
349
0
    case 1003:
350
0
      readDocInfo(entry);
351
0
      break;
352
0
    case 1007:
353
0
      readTOCPage(entry);
354
0
      break;
355
0
    default:
356
0
      break;
357
432
    }
358
432
  }
359
432
  it = entryMap.lower_bound("MPSR");
360
820
  while (it != entryMap.end()) {
361
734
    if (it->first != "MPSR")
362
346
      break;
363
364
388
    MWAWEntry const &entry = it++->second;
365
388
    switch (entry.id()) {
366
346
    case 1005: // a constant block which contains a default font?
367
346
      readMPSR5(entry);
368
346
      break;
369
4
    case 1007:
370
4
      readTOC(entry);
371
4
      break;
372
38
    default:
373
38
      break;
374
388
    }
375
388
  }
376
432
  if (!m_textParser->createZones())
377
0
    return false;
378
432
  m_graphParser->createZones();
379
432
  return true;
380
432
}
381
382
////////////////////////////////////////////////////////////
383
// read the doc/print info
384
////////////////////////////////////////////////////////////
385
bool LightWayTxtParser::readDocInfo(MWAWEntry const &entry)
386
0
{
387
0
  if (entry.id() != 1003)
388
0
    return false;
389
0
  if (!entry.valid() || (entry.length()%0x40)) {
390
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readDocInfo: the entry seems bad\n"));
391
0
    return false;
392
0
  }
393
0
  MWAWInputStreamPtr input = rsrcInput();
394
0
  libmwaw::DebugFile &ascFile = rsrcAscii();
395
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
396
0
  entry.setParsed(true);
397
398
0
  auto N=int(entry.length()/0x40);
399
0
  libmwaw::DebugStream f;
400
0
  for (int n = 0; n < N; n++) {
401
0
    long pos = input->tell();
402
0
    f.str("");
403
0
    if (n==0)
404
0
      f << "Entries(DocInfo):";
405
0
    else
406
0
      f << "DocInfo-" << n << ":";
407
408
0
    auto fl=int(input->readULong(1)); // 0|28
409
0
    if (fl) f << "fl0=" << fl << ",";
410
0
    long val=int(input->readULong(1)); // a small number less than 12
411
0
    if (val) f << "f0=" << val << ",";
412
0
    val = input->readLong(2); // 0|3|4|c
413
0
    if (val) f << "f1=" << val << ",";
414
0
    int dim[2];
415
0
    for (auto &d : dim) d = int(input->readLong(2));
416
0
    f << "dim=" << dim[0] << "x" << dim[1] << ",";
417
0
    int margins[4];
418
0
    f << "margins=[";
419
0
    for (auto &margin : margins) {
420
0
      margin = int(input->readLong(2));
421
0
      f << margin << ",";
422
0
    }
423
0
    f << "],";
424
0
    for (int i = 0; i < 6; i++) { // f2=0|1c, f3=7|9|f, f4=f6=f7=0|e, f5=0|e|54|78
425
0
      val = input->readLong(2);
426
0
      if (val) f << "f" << i+2 << "=" << val << ",";
427
0
    }
428
0
    for (int i = 0; i < 6; i++) { // f1=0|1, f2=1, f3=0|1, f4=0|1, f5=0, f6=1
429
0
      val = static_cast<int>(input->readULong(1));
430
0
      if (val) f << "fl" << i+1 << "=" << val << ",";
431
0
    }
432
0
    for (int i = 0; i < 5; i++) { // g0=0|18, g1=0|14, g4=0|..|6
433
0
      val = input->readLong(2);
434
0
      if (val) f << "g" << i << "=" << val << ",";
435
0
    }
436
0
    f << "col?=[" << std::hex;
437
0
    for (int i = 0; i <3; i++)
438
0
      f << input->readULong(2) << ",";
439
0
    f << "]," << std::dec;
440
0
    for (int i = 0; i < 6; i++) { // fl1=0|1, fl2=0|1, fl4=0|1, fl5=0|1
441
0
      val = static_cast<int>(input->readULong(1));
442
0
      if (val) f << "fl" << i << "(2)=" << val << ",";
443
0
    }
444
0
    for (int i = 0; i < 4; i++) { // alway 0?
445
0
      val = input->readLong(2);
446
0
      if (val) f << "h" << i << "=" << val << ",";
447
0
    }
448
449
0
    ascFile.addPos(n==0 ? pos-4 : pos);
450
0
    ascFile.addNote(f.str().c_str());
451
0
    input->seek(pos+0x40, librevenge::RVNG_SEEK_SET);
452
0
  }
453
0
  return true;
454
0
}
455
456
bool LightWayTxtParser::readPrintInfo(MWAWEntry const &entry)
457
0
{
458
0
  if (!entry.valid() || entry.length() < 0x78) {
459
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry is bad\n"));
460
0
    return false;
461
0
  }
462
0
  if (entry.id() != 1001) {
463
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readPrintInfo: the entry id %d is odd\n", entry.id()));
464
0
  }
465
0
  entry.setParsed(true);
466
0
  MWAWInputStreamPtr input = rsrcInput();
467
0
  long pos = entry.begin();
468
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
469
470
0
  libmwaw::DebugStream f;
471
  // print info
472
0
  libmwaw::PrinterInfo info;
473
0
  if (!info.read(input)) return false;
474
0
  if (entry.id() != 1001)
475
0
    f << "Entries(PrintInfo)[#" << entry.id() << "]:" << info;
476
0
  else
477
0
    f << "Entries(PrintInfo):" << info;
478
0
  if (entry.length() != 0x78)
479
0
    f << "###size=" << entry.length() << ",";
480
0
  rsrcAscii().addPos(pos-4);
481
0
  rsrcAscii().addNote(f.str().c_str());
482
0
  if (m_pageSpanSet)
483
0
    return true;
484
485
0
  MWAWVec2i paperSize = info.paper().size();
486
0
  MWAWVec2i pageSize = info.page().size();
487
0
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
488
0
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
489
490
  // define margin from print info
491
0
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
492
0
  MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
493
494
  // move margin left | top
495
0
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
496
0
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
497
0
  lTopMargin -= MWAWVec2i(decalX, decalY);
498
0
  rBotMargin += MWAWVec2i(decalX, decalY);
499
500
  // decrease right | bottom
501
0
  int rightMarg = rBotMargin.x() -10;
502
0
  if (rightMarg < 0) rightMarg=0;
503
0
  int botMarg = rBotMargin.y() -50;
504
0
  if (botMarg < 0) botMarg=0;
505
506
0
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
507
0
  getPageSpan().setMarginBottom(botMarg/72.0);
508
0
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
509
0
  getPageSpan().setMarginRight(rightMarg/72.0);
510
0
  getPageSpan().setFormLength(paperSize.y()/72.);
511
0
  getPageSpan().setFormWidth(paperSize.x()/72.);
512
513
0
  return true;
514
0
}
515
516
////////////////////////////////////////////////////////////
517
// read the TOC data
518
////////////////////////////////////////////////////////////
519
bool LightWayTxtParser::readTOCPage(MWAWEntry const &entry)
520
0
{
521
0
  if (entry.id() != 1007)
522
0
    return false;
523
0
  if (!entry.valid() || entry.length()<0x24) {
524
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the entry is bad\n"));
525
0
    return false;
526
0
  }
527
0
  MWAWInputStreamPtr input = rsrcInput();
528
0
  libmwaw::DebugFile &ascFile = rsrcAscii();
529
0
  long pos = entry.begin();
530
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
531
532
0
  libmwaw::DebugStream f;
533
0
  f << "Entries(TOCpage)[" << entry.id() << "]:";
534
0
  entry.setParsed(true);
535
0
  int dim[4];
536
0
  for (auto &d : dim) d = static_cast<int>(input->readLong(4));
537
0
  f << "dim?=" << dim[0] << "x" << dim[1]
538
0
    << "<->"  << dim[2] << "x" << dim[3] << ",";
539
0
  for (int i = 0; i < 9; i++) { // f5=1|2|21, f8=256
540
0
    auto val = static_cast<int>(input->readLong(2));
541
0
    if (val) f << "f" << i << "=" << val << ",";
542
0
  }
543
0
  auto N = static_cast<int>(input->readLong(2));
544
0
  f << "N=" << N << ",";
545
0
  if (input->tell()+N>entry.end()) {
546
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readTOCPage: the page seems bead\n"));
547
0
    f << "###";
548
0
    ascFile.addPos(pos-4);
549
0
    ascFile.addNote(f.str().c_str());
550
0
    return false;
551
0
  }
552
0
  f << "pages=[";
553
0
  for (int i = 0; i < N; i++)
554
0
    f << static_cast<int>(input->readULong(1)) << ",";
555
0
  f << "],";
556
0
  ascFile.addPos(pos-4);
557
0
  ascFile.addNote(f.str().c_str());
558
0
  return true;
559
0
}
560
561
bool LightWayTxtParser::readTOC(MWAWEntry const &entry)
562
4
{
563
4
  if (entry.id() != 1007)
564
0
    return false;
565
4
  if (!entry.valid() || entry.length()<2) {
566
4
    MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the entry is bad\n"));
567
4
    return false;
568
4
  }
569
0
  MWAWInputStreamPtr input = rsrcInput();
570
0
  libmwaw::DebugFile &ascFile = rsrcAscii();
571
0
  long pos = entry.begin();
572
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
573
574
0
  libmwaw::DebugStream f;
575
0
  f << "Entries(TOCdata)[" << entry.id() << "]:";
576
0
  entry.setParsed(true);
577
0
  auto N=static_cast<int>(input->readULong(2));
578
0
  f << "N=" << N << ",";
579
0
  if (long(N*9+2) > entry.length()) {
580
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: the number of entry seems bad\n"));
581
0
    f << "###";
582
0
    ascFile.addPos(pos-4);
583
0
    ascFile.addNote(f.str().c_str());
584
0
    return false;
585
0
  }
586
0
  ascFile.addPos(pos-4);
587
0
  ascFile.addNote(f.str().c_str());
588
589
0
  bool ok = true;
590
0
  for (int i = 0; i < N; i++) {
591
0
    pos = input->tell();
592
0
    if (pos+9 > entry.end()) {
593
0
      ok = false;
594
0
      break;
595
0
    }
596
0
    f.str("");
597
0
    f << "TOCdata-" << i << ":";
598
0
    long cPos[2];
599
0
    for (auto &c : cPos) c = long(input->readULong(4));
600
0
    f << "cpos?=" << cPos[0] << "<->" << cPos[1] << ",";
601
0
    auto nC = static_cast<int>(input->readULong(1));
602
0
    if (pos+9+nC > entry.end()) {
603
0
      ok = false;
604
0
      break;
605
0
    }
606
0
    std::string name("");
607
0
    for (int c = 0; c < nC; c++)
608
0
      name += char(input->readULong(1));
609
0
    f << name;
610
0
    ascFile.addPos(pos);
611
0
    ascFile.addNote(f.str().c_str());
612
0
    f.str("");
613
0
    f << "[TOC" << i << "]";
614
0
    ascii().addPos(cPos[0]);
615
0
    ascii().addNote(f.str().c_str());
616
0
  }
617
0
  if (!ok) {
618
0
    f << "###";
619
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readTOC: can not read end\n"));
620
0
    ascFile.addPos(pos);
621
0
    ascFile.addNote(f.str().c_str());
622
0
  }
623
0
  return true;
624
0
}
625
626
////////////////////////////////////////////////////////////
627
// read the main document information data then unknown data
628
////////////////////////////////////////////////////////////
629
bool LightWayTxtParser::readDocument(MWAWEntry const &entry)
630
432
{
631
432
  if (entry.id() != 1000)
632
0
    return false;
633
432
  if (!entry.valid() || entry.length()<0x28) {
634
11
    MWAW_DEBUG_MSG(("LightWayTxtParser::readDocument: the entry seems bad\n"));
635
11
    return false;
636
11
  }
637
421
  MWAWInputStreamPtr input = rsrcInput();
638
421
  libmwaw::DebugFile &ascFile = rsrcAscii();
639
421
  long pos = entry.begin();
640
421
  input->seek(pos, librevenge::RVNG_SEEK_SET);
641
642
421
  libmwaw::DebugStream f;
643
421
  f << "Entries(Document):";
644
421
  entry.setParsed(true);
645
421
  long val;
646
1.68k
  for (int i=0; i<3; i++) { // fl1=0|2|6, fl2=0|80
647
1.26k
    val = long(input->readULong(1));
648
1.26k
    if (val) f << "fl" << i << std::hex << "=" << val << std::dec << ",";
649
1.26k
  }
650
1.26k
  for (int i=0; i<2; i++) { // f0=0|1, f1=0|1
651
842
    val = long(input->readLong(2));
652
842
    if (val) f << "f" << i << "=" << val << ",";
653
842
  }
654
1.68k
  for (int i=0; i<3; i++) { // fl3=0|1, fl4=0|1, fl5=1
655
1.26k
    val = long(input->readULong(1));
656
1.26k
    if (val) f << "fl" << i+3 << "=" << val << ",";
657
1.26k
  }
658
421
  int pageDim[2];
659
842
  for (auto &d : pageDim) d = static_cast<int>(input->readLong(2));
660
421
  f << "dim=" << pageDim[1] << "x" << pageDim[0] << ",";
661
421
  int dim[4];
662
842
  for (int s=0; s<2; s++) {
663
3.36k
    for (auto &d: dim) d = static_cast<int>(input->readULong(2));
664
842
    f << "pos" << s << "=" << dim[1] << "x" << dim[0]
665
842
      << "<->" << dim[3] << "x" << dim[2] << ",";
666
842
    if (s==1) break;
667
668
421
    int margins[4]= {dim[0], dim[1], pageDim[0]-dim[2], pageDim[1]-dim[3]};
669
421
    if (margins[2] > 0 && 2*(margins[0]+margins[2]) < pageDim[0] &&
670
156
        margins[3] > 0 && 2*(margins[1]+margins[3]) < pageDim[1]) {
671
148
      getPageSpan().setMarginTop(double(margins[0])/72.0);
672
148
      getPageSpan().setMarginBottom(double(margins[2])/72.0);
673
148
      getPageSpan().setMarginLeft(double(margins[1])/72.0);
674
148
      getPageSpan().setMarginRight(double(margins[3])/72.0);
675
148
      getPageSpan().setFormLength(double(pageDim[0])/72.);
676
148
      getPageSpan().setFormWidth(double(pageDim[1])/72.);
677
148
      m_pageSpanSet = true;
678
148
    }
679
421
  }
680
421
  m_state->m_numCol = static_cast<int>(input->readLong(2));
681
421
  if (m_state->m_numCol > 1) f << "numCols=" << m_state->m_numCol << ",";
682
421
  m_state->m_colSep = static_cast<int>(input->readLong(2));
683
421
  if (m_state->m_colSep) f << "colSep=" << m_state->m_colSep << ",";
684
685
1.68k
  for (int i=0; i<3; i++) { // gl0=3|3fff|4000|9001, gl1=3|4000|9001,gl2=d[12]|f[12]|1d2
686
1.26k
    val = long(input->readULong(2));
687
1.26k
    if (val) f << "gl" << i << "=" << std::hex << val << std::dec << ",";
688
1.26k
  }
689
421
  ascFile.addPos(pos-4);
690
421
  ascFile.addNote(f.str().c_str());
691
421
  if (entry.length()==0x28)
692
238
    return true;
693
183
  m_textParser->readDocumentHF(entry);
694
183
  return true;
695
421
}
696
697
bool LightWayTxtParser::readLWSR2(MWAWEntry const &entry)
698
0
{
699
0
  if (entry.id() != 1002)
700
0
    return false;
701
0
  if (!entry.valid() || entry.length()%4) {
702
0
    MWAW_DEBUG_MSG(("LightWayTxtParser::readLWSR2: the entry seems bad\n"));
703
0
    return false;
704
0
  }
705
0
  auto N = int(entry.length()/4);
706
0
  MWAWInputStreamPtr input = rsrcInput();
707
0
  libmwaw::DebugFile &ascFile = rsrcAscii();
708
0
  long pos = entry.begin();
709
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
710
711
0
  libmwaw::DebugStream f;
712
0
  f << "Entries(LWSR2):";
713
0
  entry.setParsed(true);
714
0
  f << "pos?=[" << std::hex;
715
0
  for (int i = 0; i < N; i++)
716
0
    f << input->readLong(4) << ",";
717
0
  f << std::dec << "],";
718
0
  ascFile.addPos(pos-4);
719
0
  ascFile.addNote(f.str().c_str());
720
0
  return true;
721
0
}
722
723
bool LightWayTxtParser::readMPSR5(MWAWEntry const &entry)
724
346
{
725
346
  if (entry.id() != 1005)
726
0
    return false;
727
346
  if (!entry.valid() || entry.length() != 0x48) {
728
61
    MWAW_DEBUG_MSG(("LightWayTxtParser::readMPSR5: the entry is bad\n"));
729
61
    return false;
730
61
  }
731
285
  MWAWInputStreamPtr input = rsrcInput();
732
285
  libmwaw::DebugFile &ascFile = rsrcAscii();
733
285
  long pos = entry.begin();
734
285
  input->seek(pos, librevenge::RVNG_SEEK_SET);
735
736
285
  libmwaw::DebugStream f;
737
285
  f << "Entries(MPSR5):";
738
285
  entry.setParsed(true);
739
285
  long val = input->readLong(2); // a|c
740
285
  if (val)
741
285
    f << "f0=" << val << ",";
742
285
  std::string name("");
743
2.81k
  for (int i = 0; i < 32; i++) {
744
2.78k
    auto c = char(input->readULong(1));
745
2.78k
    if (!c)
746
253
      break;
747
2.53k
    name += c;
748
2.53k
  }
749
285
  f << "defFont?=\"" << name << "\",";
750
285
  input->seek(pos+34, librevenge::RVNG_SEEK_SET);
751
855
  for (int i = 0; i < 2; i++) { // f1=3|4|6, f2=4
752
570
    val = input->readLong(2);
753
570
    if (val)
754
488
      f << "f" << i+1 << "=" << val << ",";
755
570
  }
756
285
  int dim[4];
757
855
  for (int s=0; s<2; s++) {
758
2.28k
    for (auto &d : dim) d = static_cast<int>(input->readLong(2));
759
570
    f << "pos" << s << "=" << dim[1] << "x" << dim[0]
760
570
      << "<->" << dim[3] << "x" << dim[2] << ",";
761
570
  }
762
285
  val = long(input->readULong(4)); // a very big number
763
285
  if (val)
764
285
    f << "unkn=" << std::hex << val << std::dec << ",";
765
285
  long sel[2]; // checkme
766
285
  for (long &i : sel)
767
570
    i = input->readLong(4);
768
285
  if (sel[0]==sel[1])
769
197
    f << "sel?=" << std::hex << sel[0] << std::dec << ",";
770
88
  else
771
88
    f << "sel?=" << std::hex << sel[0] << "x" << sel[1] << std::dec << ",";
772
855
  for (int i = 0; i < 2; i++) { // g1=0|6
773
570
    val = input->readLong(2);
774
570
    if (val)
775
162
      f << "g" << i << "=" << val << ",";
776
570
  }
777
855
  for (int i = 0; i < 2; i++) { // fl0=0|1, fl1=0|1
778
570
    val = long(input->readULong(1));
779
570
    if (val)
780
121
      f << "fl" << i << "=" << val << ",";
781
570
  }
782
783
285
  ascFile.addPos(pos-4);
784
285
  ascFile.addNote(f.str().c_str());
785
285
  return true;
786
346
}
787
788
////////////////////////////////////////////////////////////
789
//
790
// Low level
791
//
792
////////////////////////////////////////////////////////////
793
794
////////////////////////////////////////////////////////////
795
// read the header
796
////////////////////////////////////////////////////////////
797
bool LightWayTxtParser::checkHeader(MWAWHeader *header, bool /*strict*/)
798
2.02k
{
799
2.02k
  *m_state = LightWayTxtParserInternal::State();
800
2.02k
  MWAWInputStreamPtr input = getInput();
801
2.02k
  if (!input || !getRSRCParser())
802
112
    return false;
803
1.91k
  std::string type, creator;
804
1.91k
  if (input->getFinderInfo(type, creator) && type == "APPL")
805
0
    m_state->m_isApplication=true;
806
1.91k
  MWAWEntry entry;
807
1.91k
  if (!m_state->m_isApplication) {
808
1.91k
    if (!input->hasDataFork())
809
47
      return false;
810
1.91k
  }
811
0
  else {
812
0
    entry = getRSRCParser()->getEntry("TEXT", 128);
813
0
    if (!entry.valid())
814
0
      return false;
815
0
  }
816
  // check if the LWSR string exists
817
1.86k
  entry = getRSRCParser()->getEntry("LWSR", 1000);
818
1.86k
  if (!entry.valid()) {
819
511
    MWAW_DEBUG_MSG(("LightWayTxtParser::checkHeader: can not find the LWSR[1000] resource, not a Mac File!!!\n"));
820
511
    return false;
821
511
  }
822
1.35k
  if (header)
823
492
    header->reset(MWAWDocument::MWAW_T_LIGHTWAYTEXT, 1);
824
825
1.35k
  return true;
826
1.86k
}
827
828
829
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: