Coverage Report

Created: 2026-03-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/ActaParser.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 "MWAWList.hxx"
46
#include "MWAWParagraph.hxx"
47
#include "MWAWPosition.hxx"
48
#include "MWAWPrinter.hxx"
49
#include "MWAWRSRCParser.hxx"
50
#include "MWAWSubDocument.hxx"
51
52
#include "ActaText.hxx"
53
54
#include "ActaParser.hxx"
55
56
/** Internal: the structures of a ActaParser */
57
namespace ActaParserInternal
58
{
59
////////////////////////////////////////
60
//! Internal: class used to store a list type in ActaParser
61
struct Label {
62
  //! constructor
63
  explicit Label(int type=-1)
64
45.1k
    : m_type(type) { }
65
  //! operator<<
66
  friend std::ostream &operator<<(std::ostream &o, Label const &lbl)
67
0
  {
68
0
    switch (lbl.m_type) {
69
0
    case 0:
70
0
      o << "noLabel,";
71
0
      break;
72
0
    case 2:
73
0
      o << "checkbox,";
74
0
      break;
75
0
    case 0xb:
76
0
      o << "decimal,"; // 1.0,
77
0
      break;
78
0
    case 0xc:
79
0
      o << "I A...,";
80
0
      break;
81
0
    case 0xe:
82
0
      o << "custom,";
83
0
      break;
84
0
    default:
85
0
      o << "#labelType=" << lbl.m_type << ",";
86
0
      break;
87
0
    }
88
0
    return o;
89
0
  }
90
  //! operator==
91
  bool operator==(Label const &lbl) const
92
1.59k
  {
93
1.59k
    return m_type==lbl.m_type;
94
1.59k
  }
95
  //! operator=!
96
  bool operator!=(Label const &lbl) const
97
1.59k
  {
98
1.59k
    return !operator==(lbl);
99
1.59k
  }
100
  //! the label type
101
  int m_type;
102
};
103
104
////////////////////////////////////////
105
//! Internal: class used to store the printing preferences in ActaParser
106
struct Printing {
107
  //! constructor
108
  Printing()
109
44.0k
    : m_font()
110
44.0k
  {
111
44.0k
    for (int &flag : m_flags)
112
88.1k
      flag=0;
113
44.0k
  }
114
  //! returns true if the header is empty
115
  bool isEmpty() const
116
6.27k
  {
117
6.27k
    return (m_flags[1]&7)==0;
118
6.27k
  }
119
  //! operator==
120
  bool operator==(Printing const &print) const
121
0
  {
122
0
    if (m_font != print.m_font)
123
0
      return false;
124
0
    for (int i=0; i<2; i++) {
125
0
      if (m_flags[i]!=print.m_flags[i])
126
0
        return false;
127
0
    }
128
0
    return true;
129
0
  }
130
  //! operator=!
131
  bool operator!=(Printing const &print) const
132
0
  {
133
0
    return !operator==(print);
134
0
  }
135
  //! operator<<
136
  friend std::ostream &operator<<(std::ostream &o, Printing const &print)
137
0
  {
138
0
    if (print.m_flags[0]==1)
139
0
      o << "useFooter,";
140
0
    else if (print.m_flags[0])
141
0
      o << "#fl0=" << print.m_flags[0] << ",";
142
0
    int flag = print.m_flags[1];
143
0
    if (flag&1)
144
0
      o << "title,";
145
0
    if (flag&2)
146
0
      o << "date,";
147
0
    if (flag&4)
148
0
      o << "pagenumber,";
149
0
    flag &= 0xFFF8;
150
0
    if (flag)
151
0
      o << "#flags=" << std::hex << flag << std::dec << ",";
152
0
    return o;
153
0
  }
154
  //! the font
155
  MWAWFont m_font;
156
  //! the flags
157
  int m_flags[2];
158
};
159
160
////////////////////////////////////////
161
//! Internal: class used to store the optional preferences in ActaParser
162
struct Option {
163
  //! constructor
164
  explicit Option(int flags=0)
165
1.86k
    : m_flags(flags) { }
166
  //! operator<<
167
  friend std::ostream &operator<<(std::ostream &o, Option const &opt)
168
0
  {
169
0
    int flag = opt.m_flags;
170
0
    if (flag&0x1000)
171
0
      o << "speaker[dial],";
172
0
    if (flag&0x4)
173
0
      o << "smart['\"],";
174
0
    if (flag&0x8)
175
0
      o << "open[startup],";
176
0
    // flag&0x10: always ?
177
0
    if (flag&0x20)
178
0
      o << "nolabel[picture],";
179
0
    if (flag&0x40)
180
0
      o << "noframe[current],";
181
0
    if (flag&0x80)
182
0
      o << "nolabel[clipboard],";
183
0
184
0
    flag &= 0xEF13;
185
0
    if (flag) // find also flag&(10|400|4000|8000)
186
0
      o << "option[flags]=" << std::hex << flag << std::dec << ",";
187
0
    return o;
188
0
  }
189
  //! the flags
190
  int m_flags;
191
};
192
193
////////////////////////////////////////
194
//! Internal: the state of a ActaParser
195
struct State {
196
  //! constructor
197
  State()
198
43.5k
    : m_printerPreferences()
199
43.5k
    , m_title("")
200
43.5k
    , m_label()
201
43.5k
    , m_stringLabel("")
202
43.5k
    , m_actPage(0)
203
43.5k
    , m_numPages(0)
204
43.5k
    , m_headerHeight(0)
205
43.5k
    , m_footerHeight(0)
206
43.5k
  {
207
43.5k
  }
208
209
  //! the printer preferences
210
  Printing m_printerPreferences;
211
  //! the title (if defined)
212
  std::string m_title;
213
  //! the list type
214
  Label m_label;
215
  //! the custom label (if defined)
216
  std::string m_stringLabel;
217
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
218
219
  int m_headerHeight /** the header height if known */,
220
      m_footerHeight /** the footer height if known */;
221
};
222
223
////////////////////////////////////////
224
//! Internal: the subdocument of a ActaParser
225
class SubDocument final : public MWAWSubDocument
226
{
227
public:
228
  SubDocument(ActaParser &pars, MWAWInputStreamPtr const &input) :
229
2
    MWAWSubDocument(&pars, input, MWAWEntry()) {}
230
231
  //! destructor
232
0
  ~SubDocument() final {}
233
234
  //! operator!=
235
  bool operator!=(MWAWSubDocument const &doc) const final
236
0
  {
237
0
    if (MWAWSubDocument::operator!=(doc)) return true;
238
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
239
0
    if (!sDoc) return true;
240
0
    return false;
241
0
  }
242
243
  //! the parser function
244
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
245
246
protected:
247
};
248
249
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
250
2
{
251
2
  if (!listener.get()) {
252
0
    MWAW_DEBUG_MSG(("ActaParserInternal::SubDocument::parse: no listener\n"));
253
0
    return;
254
0
  }
255
2
  auto *parser=dynamic_cast<ActaParser *>(m_parser);
256
2
  if (!parser) {
257
0
    MWAW_DEBUG_MSG(("ActaParserInternal::SubDocument::parse: can not find main parser\n"));
258
0
    return;
259
0
  }
260
2
  parser->sendHeaderFooter();
261
2
}
262
}
263
264
265
////////////////////////////////////////////////////////////
266
// constructor/destructor, ...
267
////////////////////////////////////////////////////////////
268
ActaParser::ActaParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
269
18.3k
  : MWAWTextParser(input, rsrcParser, header)
270
18.3k
  , m_state()
271
18.3k
  , m_textParser()
272
18.3k
{
273
18.3k
  init();
274
18.3k
}
275
276
ActaParser::~ActaParser()
277
18.3k
{
278
18.3k
}
279
280
void ActaParser::init()
281
18.3k
{
282
18.3k
  resetTextListener();
283
18.3k
  setAsciiName("main-1");
284
285
18.3k
  m_state.reset(new ActaParserInternal::State);
286
287
  // reduce the margin (in case, the page is not defined)
288
18.3k
  getPageSpan().setMargins(0.1);
289
290
18.3k
  m_textParser.reset(new ActaText(*this));
291
18.3k
}
292
293
MWAWInputStreamPtr ActaParser::rsrcInput()
294
1.08k
{
295
1.08k
  return getRSRCParser()->getInput();
296
1.08k
}
297
298
libmwaw::DebugFile &ActaParser::rsrcAscii()
299
1.08k
{
300
1.08k
  return getRSRCParser()->ascii();
301
1.08k
}
302
303
////////////////////////////////////////////////////////////
304
// position and height
305
////////////////////////////////////////////////////////////
306
MWAWVec2f ActaParser::getPageLeftTop() const
307
0
{
308
0
  return MWAWVec2f(float(getPageSpan().getMarginLeft()),
309
0
                   float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
310
0
}
311
312
////////////////////////////////////////////////////////////
313
// interface with the text parser
314
////////////////////////////////////////////////////////////
315
316
std::shared_ptr<MWAWList> ActaParser::getMainList()
317
6.27k
{
318
6.27k
  MWAWListLevel level;
319
6.27k
  level.m_labelAfterSpace=0.05;
320
6.27k
  std::vector<MWAWListLevel> levels;
321
6.27k
  switch (m_state->m_label.m_type) {
322
188
  case 0: // none
323
188
    level.m_type=MWAWListLevel::NONE;
324
188
    levels.resize(10, level);
325
188
    break;
326
5
  case 2: // checkbox
327
5
    level.m_type=MWAWListLevel::BULLET;
328
5
    libmwaw::appendUnicode(0x2610, level.m_bullet);
329
5
    levels.resize(10, level);
330
5
    break;
331
0
  case 0xb: // 1.0 1.1 1.1.1 1.1.1.1 1.1.1.1.1 ...
332
0
    level.m_suffix = ".";
333
0
    level.m_type=MWAWListLevel::DECIMAL;
334
0
    for (int i=0; i < 10; i++) {
335
0
      level.m_numBeforeLabels=i;
336
0
      levels.push_back(level);
337
0
    }
338
0
    break;
339
0
  case 0xc: // I. A. 1. a. i. [(1). (a). ]*
340
0
    level.m_suffix = ".";
341
0
    level.m_type=MWAWListLevel::UPPER_ROMAN;
342
0
    levels.push_back(level);
343
0
    level.m_type=MWAWListLevel::UPPER_ALPHA;
344
0
    levels.push_back(level);
345
0
    level.m_type=MWAWListLevel::DECIMAL;
346
0
    levels.push_back(level);
347
0
    level.m_type=MWAWListLevel::LOWER_ALPHA;
348
0
    levels.push_back(level);
349
0
    level.m_type=MWAWListLevel::LOWER_ROMAN;
350
0
    levels.push_back(level);
351
0
    level.m_prefix = "(";
352
0
    level.m_suffix = ").";
353
0
    for (int i=0; i < 4; i++) {
354
0
      level.m_type=MWAWListLevel::DECIMAL;
355
0
      levels.push_back(level);
356
0
      level.m_type=MWAWListLevel::LOWER_ALPHA;
357
0
      levels.push_back(level);
358
0
    }
359
0
    break;
360
6.08k
  default: // ok, switch to custom or by default bullet
361
6.08k
  case 0xe: { //custom
362
6.08k
    level.m_type=MWAWListLevel::BULLET;
363
6.08k
    libmwaw::appendUnicode(0x2022, level.m_bullet);
364
6.08k
    auto fontConvert=getFontConverter();
365
6.08k
    if (!fontConvert) {
366
0
      MWAW_DEBUG_MSG(("ActaParser::getMainList: can not find the listener\n"));
367
0
    }
368
6.08k
    else {
369
25.1k
      for (size_t i=0; i<m_state->m_stringLabel.size(); ++i) { // checkme
370
19.1k
        int unicode=fontConvert->unicode(3, static_cast<unsigned char>(m_state->m_stringLabel[1]));
371
19.1k
        level.m_bullet="";
372
19.1k
        libmwaw::appendUnicode((unicode > 0) ? uint32_t(unicode):0x2022, level.m_bullet);
373
19.1k
        levels.push_back(level);
374
19.1k
      }
375
6.08k
    }
376
62.1k
    while (levels.size() < 10)
377
56.1k
      levels.push_back(level);
378
6.08k
    break;
379
6.08k
  }
380
6.27k
  }
381
6.27k
  std::shared_ptr<MWAWList> list;
382
6.27k
  MWAWListManagerPtr listManager=getParserState()->m_listManager;
383
6.27k
  if (!listManager) {
384
0
    MWAW_DEBUG_MSG(("ActaParser::getMainList: can not find the list manager\n"));
385
0
    return list;
386
0
  }
387
388
83.4k
  for (size_t s=0; s < levels.size(); s++) {
389
77.1k
    list = listManager->getNewList(list, int(s+1), levels[s]);
390
77.1k
    if (!list) break;
391
77.1k
  }
392
6.27k
  return list;
393
6.27k
}
394
////////////////////////////////////////////////////////////
395
// new page
396
////////////////////////////////////////////////////////////
397
void ActaParser::newPage(int number)
398
10.3k
{
399
10.3k
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
400
0
    return;
401
402
22.6k
  while (m_state->m_actPage < number) {
403
12.3k
    m_state->m_actPage++;
404
12.3k
    if (!getTextListener() || m_state->m_actPage == 1)
405
1.96k
      continue;
406
10.3k
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
407
10.3k
  }
408
10.3k
}
409
410
////////////////////////////////////////////////////////////
411
// the parser
412
////////////////////////////////////////////////////////////
413
void ActaParser::parse(librevenge::RVNGTextInterface *docInterface)
414
6.80k
{
415
6.80k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
416
6.80k
  bool ok = false;
417
6.80k
  try {
418
    // create the asciiFile
419
6.80k
    ascii().setStream(getInput());
420
6.80k
    ascii().open(asciiName());
421
422
6.80k
    checkHeader(nullptr);
423
6.80k
    ok = createZones();
424
6.80k
    if (ok) {
425
6.27k
      createDocument(docInterface);
426
6.27k
      m_textParser->sendMainText();
427
6.27k
    }
428
6.80k
    ascii().reset();
429
6.80k
  }
430
6.80k
  catch (...) {
431
0
    MWAW_DEBUG_MSG(("ActaParser::parse: exception catched when parsing\n"));
432
0
    ok = false;
433
0
  }
434
435
6.80k
  resetTextListener();
436
6.80k
  if (!ok) throw(libmwaw::ParseException());
437
6.80k
}
438
439
////////////////////////////////////////////////////////////
440
// create the document
441
////////////////////////////////////////////////////////////
442
void ActaParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
443
6.27k
{
444
6.27k
  if (!documentInterface) return;
445
6.27k
  if (getTextListener()) {
446
0
    MWAW_DEBUG_MSG(("ActaParser::createDocument: listener already exist\n"));
447
0
    return;
448
0
  }
449
450
  // update the page
451
6.27k
  m_state->m_actPage = 0;
452
453
  // create the page list
454
6.27k
  int numPages = 1;
455
6.27k
  if (m_textParser->numPages() > numPages)
456
1.96k
    numPages = m_textParser->numPages();
457
6.27k
  m_state->m_numPages = numPages;
458
459
6.27k
  MWAWPageSpan ps(getPageSpan());
460
6.27k
  ps.setPageSpan(m_state->m_numPages+1);
461
6.27k
  if (!m_state->m_printerPreferences.isEmpty()) {
462
2
    MWAWHeaderFooter hF(m_state->m_printerPreferences.m_flags[0]!=1 ?
463
2
                        MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER,
464
2
                        MWAWHeaderFooter::ALL);
465
2
    hF.m_subDocument.reset(new ActaParserInternal::SubDocument(*this, getInput()));
466
2
    ps.setHeaderFooter(hF);
467
2
  }
468
6.27k
  std::vector<MWAWPageSpan> pageList(1,ps);
469
6.27k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
470
6.27k
  setTextListener(listen);
471
6.27k
  listen->startDocument();
472
6.27k
}
473
474
void ActaParser::sendHeaderFooter()
475
2
{
476
2
  MWAWTextListenerPtr listener=getTextListener();
477
2
  if (!listener) {
478
0
    MWAW_DEBUG_MSG(("ActaParser::sendHeaderFooter: can not find the listener\n"));
479
0
    return;
480
0
  }
481
2
  auto const &print=m_state->m_printerPreferences;
482
2
  MWAWParagraph para;
483
2
  para.m_justify=MWAWParagraph::JustificationCenter;
484
2
  listener->setParagraph(para);
485
2
  listener->setFont(print.m_font);
486
2
  bool printDone=false;
487
8
  for (int i=0, wh=1; i < 3; i++, wh*=2) {
488
6
    if ((print.m_flags[1]&wh)==0)
489
1
      continue;
490
5
    if (printDone)
491
3
      listener->insertChar(' ');
492
5
    switch (i) {
493
2
    case 0:
494
2
      if (!m_state->m_title.length()) {
495
1
        listener->insertField(MWAWField(MWAWField::Title));
496
1
        break;
497
1
      }
498
1
      for (auto c : m_state->m_title)
499
4
        listener->insertCharacter(static_cast<unsigned char>(c));
500
1
      break;
501
2
    case 1: {
502
2
      MWAWField field(MWAWField::Date);
503
2
      field.m_DTFormat="%b %d, %Y";
504
2
      listener->insertField(field);
505
2
      break;
506
2
    }
507
1
    case 2:
508
1
      listener->insertField(MWAWField(MWAWField::PageNumber));
509
1
      break;
510
0
    default:
511
0
      MWAW_DEBUG_MSG(("ActaParser::sendHeaderFooter: unexpected step\n"));
512
0
      break;
513
5
    }
514
5
    printDone=true;
515
5
  }
516
2
  if (!printDone)
517
0
    listener->insertChar(' ');
518
2
}
519
520
////////////////////////////////////////////////////////////
521
//
522
// Intermediate level
523
//
524
////////////////////////////////////////////////////////////
525
bool ActaParser::createZones()
526
6.80k
{
527
6.80k
  MWAWInputStreamPtr input = getInput();
528
6.80k
  readRSRCZones();
529
6.80k
  if (version()>=3) {
530
1.79k
    input->setReadInverted(true);
531
1.79k
    if (!readEndDataV3()) {
532
201
      ascii().addPos(input->tell());
533
201
      ascii().addNote("Entries(Loose)");
534
201
    }
535
1.79k
    input->setReadInverted(false);
536
1.79k
  }
537
6.80k
  return m_textParser->createZones();
538
6.80k
}
539
540
bool ActaParser::readRSRCZones()
541
6.80k
{
542
6.80k
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
543
6.80k
  if (!rsrcParser)
544
5.96k
    return true;
545
840
  if (version() < 3) { // never seens so, better ignore
546
1
    MWAW_DEBUG_MSG(("ActaParser::readRSRCZones: find a resource fork in v1-v2!!!\n"));
547
1
    return false;
548
1
  }
549
550
551
839
  auto const &entryMap = rsrcParser->getEntriesMap();
552
553
  // STR:0 -> title name, STR:1 custom label
554
839
  auto it = entryMap.lower_bound("STR ");
555
1.65k
  while (it != entryMap.end()) {
556
1.46k
    if (it->first != "STR ")
557
649
      break;
558
815
    MWAWEntry const &entry = it++->second;
559
815
    entry.setParsed(true);
560
815
    std::string str("");
561
815
    if (!rsrcParser->parseSTR(entry,str) || str.length()==0)
562
687
      continue;
563
128
    switch (entry.id()) {
564
10
    case 0:
565
10
      m_state->m_title=str;
566
10
      break;
567
30
    case 1:
568
30
      m_state->m_stringLabel=str;
569
30
      break;
570
88
    default:
571
88
      MWAW_DEBUG_MSG(("ActaParser::readRSRCZones: find unexpected STR:%d\n", entry.id()));
572
88
      break;
573
128
    }
574
128
  }
575
  // the 0 zone
576
839
  char const *zNames[] = {"PSET", "WSIZ", "LABL", "QOPT", "QHDR"};
577
5.03k
  for (int z = 0; z < 5; z++) {
578
4.19k
    it = entryMap.lower_bound(zNames[z]);
579
7.48k
    while (it != entryMap.end()) {
580
6.60k
      if (it->first != zNames[z])
581
3.31k
        break;
582
3.28k
      MWAWEntry const &entry = it++->second;
583
3.28k
      switch (z) {
584
466
      case 0:
585
466
        readPrintInfo(entry);
586
466
        break;
587
662
      case 1:
588
662
        readWindowPos(entry);
589
662
        break;
590
767
      case 2:
591
767
        readLabel(entry);
592
767
        break;
593
511
      case 3:
594
511
        readOption(entry);
595
511
        break;
596
883
      case 4:
597
883
        readHFProperties(entry);
598
883
        break;
599
0
      default:
600
0
        break;
601
3.28k
      }
602
3.28k
    }
603
4.19k
  }
604
839
  return true;
605
839
}
606
607
bool ActaParser::readEndDataV3()
608
1.79k
{
609
1.79k
  if (version()<3)
610
0
    return true;
611
1.79k
  MWAWInputStreamPtr input = getInput();
612
1.79k
  libmwaw::DebugStream f;
613
1.79k
  input->seek(-8, librevenge::RVNG_SEEK_END);
614
1.79k
  ascii().addPos(input->tell());
615
1.79k
  auto pos=static_cast<long>(input->readULong(4));
616
1.79k
  if (pos < 18 || !input->checkPosition(pos)) {
617
201
    MWAW_DEBUG_MSG(("ActaParser::readEndDataV3: oops begin of ressource is bad\n"));
618
201
    ascii().addNote("###");
619
201
    return false;
620
201
  }
621
1.59k
  ascii().addNote("_");
622
623
1.59k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
624
625
1.59k
  f << "Entries(QOpt):";
626
1.59k
  ActaParserInternal::Label lbl(static_cast<int>(input->readLong(1)));
627
1.59k
  f << lbl << ",";
628
1.59k
  if (m_state->m_label!=lbl) {
629
1.38k
    if (m_state->m_label.m_type) {
630
1.36k
      MWAW_DEBUG_MSG(("ActaParser::readEndDataV3: oops the label seems set and different\n"));
631
1.36k
    }
632
21
    else
633
21
      m_state->m_label = lbl;
634
1.38k
  }
635
1.59k
  auto val=static_cast<int>(input->readLong(1));
636
1.59k
  if (val != 1) // always 1
637
848
    f << "f0=" << val << ",";
638
1.59k
  ActaParserInternal::Option opt(static_cast<int>(input->readULong(2)));
639
1.59k
  f << opt;
640
  // string: name, followed by abbreviation
641
4.69k
  for (int i = 0; i < 2; i++) {
642
3.15k
    long fPos=input->tell();
643
3.15k
    auto fSz = static_cast<int>(input->readULong(1));
644
3.15k
    if (!input->checkPosition(fPos+fSz+1)) {
645
58
      MWAW_DEBUG_MSG(("ActaText::readEndDataV3: can not read following string\n"));
646
58
      f << "###";
647
58
      ascii().addPos(pos);
648
58
      ascii().addNote(f.str().c_str());
649
58
      return true;
650
58
    }
651
3.10k
    if (!fSz) continue;
652
1.68k
    std::string str("");
653
45.3k
    for (int s=0; s < fSz; s++)
654
43.6k
      str+=static_cast<char>(input->readULong(1));
655
1.68k
    if (!str.length())
656
0
      continue;
657
1.68k
    f << "str" << i << "=" << str << ",";
658
1.68k
    std::string &which=(i==0) ? m_state->m_title : m_state->m_stringLabel;
659
1.68k
    if (which.length()) {
660
30
      if (which != str) {
661
15
        MWAW_DEBUG_MSG(("ActaText::readEndDataV3: find a different string\n"));
662
15
        f << "###";
663
15
      }
664
30
      continue;
665
30
    }
666
1.65k
    which = str;
667
1.65k
  }
668
1.54k
  val=static_cast<int>(input->readLong(1));
669
1.54k
  if (val) // always 0 or a another string
670
535
    f << "f1=" << val << ",";
671
672
  // from here unknown: maybe related to the printer definition...
673
1.54k
  float dim[2];
674
1.54k
  for (float &i : dim)  // very unsure...
675
3.08k
    i = float(input->readULong(2))/256.f;
676
1.54k
  f << "dim?=" << dim[1] << "x" << dim[0] << ",";
677
1.54k
  ascii().addPos(pos);
678
1.54k
  ascii().addNote(f.str().c_str());
679
680
1.54k
  pos = input->tell();
681
1.54k
  f.str("");
682
1.54k
  f << "Entries(Loose):";
683
1.54k
  auto type = static_cast<int>(input->readULong(1));
684
1.54k
  f << "type?=" << std::hex << type << ",";
685
1.54k
  ascii().addPos(pos);
686
1.54k
  ascii().addNote("Entries(Loose)");
687
688
1.54k
  if (type!=255 || !input->checkPosition(pos+200))
689
1.16k
    return true;
690
691
379
  input->seek(pos+198, librevenge::RVNG_SEEK_SET);
692
379
  pos = input->tell();
693
379
  auto N=static_cast<int>(input->readLong(2));
694
379
  if (N<0 || !input->checkPosition(pos+2+34*N))
695
60
    return true;
696
319
  f.str("");
697
319
  f << "Entries(Font):N=" << N << ",";
698
319
  ascii().addPos(pos);
699
319
  ascii().addNote(f.str().c_str());
700
32.1k
  for (int i= 0; i < N; i++) {
701
31.8k
    pos=input->tell();
702
31.8k
    f.str("");
703
31.8k
    f << "Font-" << i << ":";
704
31.8k
    std::string str("");
705
404k
    while (input->tell()<pos+32) {
706
395k
      auto c=static_cast<char>(input->readULong(1));
707
395k
      if (!c) break;
708
372k
      str+=c;
709
372k
    }
710
31.8k
    if (str.length())
711
21.0k
      f << str << ",";
712
31.8k
    input->seek(pos+32, librevenge::RVNG_SEEK_SET);
713
95.4k
    for (int j = 0; j < 2; j++) {
714
63.6k
      val = static_cast<int>(input->readLong(1));
715
63.6k
      if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
716
63.6k
    }
717
31.8k
    ascii().addPos(pos);
718
31.8k
    ascii().addNote(f.str().c_str());
719
31.8k
  }
720
721
319
  pos = input->tell();
722
319
  ascii().addPos(pos);
723
319
  ascii().addNote("Entries(Loose)[II]");
724
319
  return true;
725
379
}
726
727
////////////////////////////////////////////////////////////
728
// read the print info
729
////////////////////////////////////////////////////////////
730
bool ActaParser::readPrintInfo(MWAWEntry const &entry)
731
466
{
732
466
  if (!entry.valid() || entry.length() != 120) {
733
351
    MWAW_DEBUG_MSG(("ActaParser::readPrintInfo: the entry is bad\n"));
734
351
    return false;
735
351
  }
736
737
115
  long pos = entry.begin();
738
115
  MWAWInputStreamPtr input = rsrcInput();
739
115
  libmwaw::DebugFile &ascFile = rsrcAscii();
740
115
  libmwaw::DebugStream f;
741
742
115
  input->seek(pos, librevenge::RVNG_SEEK_SET);
743
115
  libmwaw::PrinterInfo info;
744
115
  if (!info.read(input)) return false;
745
54
  f << "Entries(PrintInfo):"<< info;
746
54
  entry.setParsed(true);
747
748
54
  MWAWVec2i paperSize = info.paper().size();
749
54
  MWAWVec2i pageSize = info.page().size();
750
54
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
751
54
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
752
753
  // define margin from print info
754
54
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
755
54
  MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
756
757
  // move margin left | top
758
54
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
759
54
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
760
54
  lTopMargin -= MWAWVec2i(decalX, decalY);
761
54
  rBotMargin += MWAWVec2i(decalX, decalY);
762
763
  // decrease right | bottom
764
54
  int rightMarg = rBotMargin.x() -10;
765
54
  if (rightMarg < 0) rightMarg=0;
766
54
  int botMarg = rBotMargin.y() -50;
767
54
  if (botMarg < 0) botMarg=0;
768
769
54
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
770
54
  getPageSpan().setMarginBottom(botMarg/72.0);
771
54
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
772
54
  getPageSpan().setMarginRight(rightMarg/72.0);
773
54
  getPageSpan().setFormLength(paperSize.y()/72.);
774
54
  getPageSpan().setFormWidth(paperSize.x()/72.);
775
776
54
  ascFile.addPos(pos-4);
777
54
  ascFile.addNote(f.str().c_str());
778
54
  return true;
779
54
}
780
781
////////////////////////////////////////////////////////////
782
// read the windows positon info
783
////////////////////////////////////////////////////////////
784
bool ActaParser::readWindowPos(MWAWEntry const &entry)
785
662
{
786
662
  if (!entry.valid() || entry.length() != 8) {
787
547
    MWAW_DEBUG_MSG(("ActaParser::readWindowPos: the entry is bad\n"));
788
547
    return false;
789
547
  }
790
791
115
  long pos = entry.begin();
792
115
  MWAWInputStreamPtr input = rsrcInput();
793
115
  libmwaw::DebugFile &ascFile = rsrcAscii();
794
115
  libmwaw::DebugStream f;
795
796
115
  input->seek(pos, librevenge::RVNG_SEEK_SET);
797
115
  f << "Entries(WindowPos):";
798
115
  entry.setParsed(true);
799
115
  int dim[4];
800
115
  for (int &i : dim)
801
460
    i = static_cast<int>(input->readLong(2));
802
115
  f << "pos=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ",";
803
115
  ascFile.addPos(pos-4);
804
115
  ascFile.addNote(f.str().c_str());
805
115
  return true;
806
662
}
807
808
////////////////////////////////////////////////////////////
809
// small resource fork
810
////////////////////////////////////////////////////////////
811
812
// label kind
813
bool ActaParser::readLabel(MWAWEntry const &entry)
814
767
{
815
767
  if (!entry.valid() || entry.length() != 2) {
816
465
    MWAW_DEBUG_MSG(("ActaParser::readLabel: the entry is bad\n"));
817
465
    return false;
818
465
  }
819
820
302
  long pos = entry.begin();
821
302
  MWAWInputStreamPtr input = rsrcInput();
822
302
  libmwaw::DebugFile &ascFile = rsrcAscii();
823
302
  libmwaw::DebugStream f;
824
825
302
  input->seek(pos, librevenge::RVNG_SEEK_SET);
826
302
  f << "Entries(Label):";
827
302
  entry.setParsed(true);
828
302
  m_state->m_label.m_type=static_cast<int>(input->readLong(2));
829
302
  f << m_state->m_label;
830
302
  ascFile.addPos(pos-4);
831
302
  ascFile.addNote(f.str().c_str());
832
302
  return true;
833
767
}
834
835
// header/footer properties
836
bool ActaParser::readHFProperties(MWAWEntry const &entry)
837
883
{
838
883
  if (!entry.valid() || entry.length() != 20) {
839
598
    MWAW_DEBUG_MSG(("ActaParser::readHFProperties: the entry is bad\n"));
840
598
    return false;
841
598
  }
842
843
285
  long pos = entry.begin();
844
285
  MWAWInputStreamPtr input = rsrcInput();
845
285
  libmwaw::DebugFile &ascFile = rsrcAscii();
846
285
  libmwaw::DebugStream f;
847
848
285
  input->seek(pos, librevenge::RVNG_SEEK_SET);
849
285
  f << "Entries(QHDR):";
850
285
  entry.setParsed(true);
851
855
  for (int st = 0; st < 2; st++) {
852
570
    if (st==0)
853
285
      f << "headerFooter=[";
854
285
    else
855
285
      f << "unknown=[";
856
570
    ActaParserInternal::Printing print;
857
570
    print.m_font.setId(static_cast<int>(input->readLong(2)));
858
570
    print.m_font.setSize(static_cast<float>(input->readLong(2)));
859
570
    auto flag=static_cast<int>(input->readLong(2));
860
570
    uint32_t flags = 0;
861
570
    if (flag&0x1) flags |= MWAWFont::boldBit;
862
570
    if (flag&0x2) flags |= MWAWFont::italicBit;
863
570
    if (flag&0x4) print.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
864
570
    if (flag&0x8) flags |= MWAWFont::embossBit;
865
570
    if (flag&0x10) flags |= MWAWFont::shadowBit;
866
570
    print.m_font.setFlags(flags);
867
#ifdef DEBUG
868
    f << "font=[" << print.m_font.getDebugString(getFontConverter()) << "],";
869
#endif
870
570
    flag &= 0xE0;
871
570
    if (flag)
872
2
      f << "#font[flags]=" << std::hex << flags << std::dec << ",";
873
570
    for (int &i : print.m_flags)
874
1.14k
      i = static_cast<int>(input->readULong(2));
875
570
    f << print << "],";
876
570
    if (st==0)
877
285
      m_state->m_printerPreferences = print;
878
570
  }
879
880
285
  ascFile.addPos(pos-4);
881
285
  ascFile.addNote(f.str().c_str());
882
285
  return true;
883
883
}
884
885
// Option : small modificator change
886
bool ActaParser::readOption(MWAWEntry const &entry)
887
511
{
888
511
  if (!entry.valid() || entry.length() != 2) {
889
246
    MWAW_DEBUG_MSG(("ActaParser::readOption: the entry is bad\n"));
890
246
    return false;
891
246
  }
892
893
265
  long pos = entry.begin();
894
265
  MWAWInputStreamPtr input = rsrcInput();
895
265
  libmwaw::DebugFile &ascFile = rsrcAscii();
896
265
  libmwaw::DebugStream f;
897
898
265
  input->seek(pos, librevenge::RVNG_SEEK_SET);
899
265
  f << "Entries(Option):";
900
265
  entry.setParsed(true);
901
265
  ActaParserInternal::Option opt(static_cast<int>(input->readULong(2)));
902
265
  f << opt;
903
265
  ascFile.addPos(pos-4);
904
265
  ascFile.addNote(f.str().c_str());
905
265
  return true;
906
511
}
907
////////////////////////////////////////////////////////////
908
//
909
// Low level
910
//
911
////////////////////////////////////////////////////////////
912
913
////////////////////////////////////////////////////////////
914
// read the header
915
////////////////////////////////////////////////////////////
916
bool ActaParser::checkHeader(MWAWHeader *header, bool strict)
917
25.1k
{
918
25.1k
  *m_state = ActaParserInternal::State();
919
25.1k
  MWAWInputStreamPtr input = getInput();
920
25.1k
  if (!input || !input->hasDataFork() || !input->checkPosition(22))
921
253
    return false;
922
923
24.9k
  libmwaw::DebugStream f;
924
24.9k
  f << "FileHeader:";
925
926
  // first check end of file
927
24.9k
  input->seek(-4,librevenge::RVNG_SEEK_END);
928
24.9k
  int last[2];
929
24.9k
  for (int &i : last)
930
49.8k
    i=static_cast<int>(input->readLong(2));
931
24.9k
  int vers=-1;
932
24.9k
  if (last[0]==0x4E4C && last[1]==0x544F)
933
7.14k
    vers=3;
934
17.7k
  else if (last[1]==0)
935
17.5k
    vers=1;
936
24.9k
  if (vers<=0)
937
172
    return false;
938
24.7k
  setVersion(vers);
939
940
  // ok, now check the beginning of the file
941
24.7k
  int val;
942
24.7k
  input->seek(0, librevenge::RVNG_SEEK_SET);
943
24.7k
  if (vers==3) {
944
7.14k
    val=static_cast<int>(input->readULong(2));
945
7.14k
    if (val!=3) {
946
2.94k
      if (strict) return false;
947
2.08k
      if (val < 1 || val > 4)
948
98
        return false;
949
1.98k
      f << "#vers=" << val << ",";
950
1.98k
      MWAW_DEBUG_MSG(("ActaParser::checkHeader: find unexpected version: %d\n", val));
951
1.98k
    }
952
7.14k
  }
953
23.7k
  val = static_cast<int>(input->readULong(2)); // depth ( first topic must have depth=1)
954
23.7k
  if (val != 1)
955
138
    return false;
956
23.6k
  val = static_cast<int>(input->readULong(2)); // type
957
23.6k
  if (val != 1 && val !=2)
958
207
    return false;
959
960
  // check that the first text size is valid
961
23.4k
  input->seek(vers==1 ? 18 : 20, librevenge::RVNG_SEEK_SET);
962
23.4k
  auto sz=static_cast<long>(input->readULong(4));
963
23.4k
  if (!input->checkPosition(input->tell()+sz))
964
2.03k
    return false;
965
966
21.3k
  if (header)
967
7.79k
    header->reset(MWAWDocument::MWAW_T_ACTA, vers);
968
21.3k
  if (vers >= 3) {
969
5.78k
    ascii().addPos(0);
970
5.78k
    ascii().addNote(f.str().c_str());
971
5.78k
  }
972
21.3k
  return true;
973
23.4k
}
974
975
976
977
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: