Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/NisusWrtText.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 <map>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWTextListener.hxx"
43
#include "MWAWDebug.hxx"
44
#include "MWAWFont.hxx"
45
#include "MWAWFontConverter.hxx"
46
#include "MWAWPageSpan.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWRSRCParser.hxx"
50
#include "MWAWSection.hxx"
51
#include "MWAWSubDocument.hxx"
52
53
#include "NisusWrtParser.hxx"
54
#include "NisusWrtStruct.hxx"
55
56
#include "NisusWrtText.hxx"
57
58
/** Internal: the structures of a NisusWrtText */
59
namespace NisusWrtTextInternal
60
{
61
/** Internal: the fonts and many other data*/
62
struct Font {
63
  //! the constructor
64
  Font()
65
62.5k
    : m_font(-1, -1)
66
62.5k
    , m_pictureId(0)
67
62.5k
    , m_pictureWidth(0)
68
62.5k
    , m_markId(-1)
69
62.5k
    , m_variableId(0)
70
62.5k
    , m_format(0)
71
62.5k
    , m_format2(0)
72
62.5k
    , m_extra("")
73
62.5k
  {
74
62.5k
  }
75
  bool isVariable() const
76
89.3k
  {
77
89.3k
    return (m_format2&0x20)==0x20;
78
89.3k
  }
79
80
  //! operator<<
81
  friend std::ostream &operator<<(std::ostream &o, Font const &font);
82
83
  //! the font
84
  MWAWFont m_font;
85
  //! the picture id ( if this is for a picture )
86
  int m_pictureId;
87
  //! the picture width
88
  int m_pictureWidth;
89
  //! a mark id
90
  int m_markId;
91
  //! the variable id : in fact cst[unkn] + v_id
92
  int m_variableId;
93
  //! the main format ...
94
  int m_format;
95
  //! a series of flags
96
  int m_format2;
97
  //! two picture dim ( orig && file ?)
98
  MWAWBox2i m_pictureDim[2];
99
  //! extra data
100
  std::string m_extra;
101
};
102
103
104
std::ostream &operator<<(std::ostream &o, Font const &font)
105
0
{
106
0
  if (font.m_pictureId) o << "pictId=" << font.m_pictureId << ",";
107
0
  if (font.m_pictureWidth) o << "pictW=" << font.m_pictureWidth << ",";
108
0
  if (font.m_markId >= 0) o << "markId=" << font.m_markId << ",";
109
0
  if (font.m_variableId > 0) o << "variableId=" << font.m_variableId << ",";
110
0
  if (font.m_format2&0x4) o << "index,";
111
0
  if (font.m_format2&0x8) o << "TOC,";
112
0
  if (font.m_format2&0x10) o << "samePage,";
113
0
  if (font.m_format2&0x20) o << "variable,";
114
0
  if (font.m_format2&0x40) o << "hyphenate,";
115
0
  if (font.m_format2&0x83)
116
0
    o << "#format2=" << std::hex << (font.m_format2 &0x83) << std::dec << ",";
117
118
0
  if (font.m_format & 1) o << "noSpell,";
119
0
  if (font.m_format & 0x10) o << "sameLine,";
120
0
  if (font.m_format & 0x40) o << "endOfPage,"; // checkme
121
0
  if (font.m_format & 0xA6)
122
0
    o << "#fl=" << std::hex << (font.m_format & 0xA6) << std::dec << ",";
123
0
  if (font.m_pictureDim[0].size()[0] || font.m_pictureDim[0].size()[1])
124
0
    o << "pictDim=" << font.m_pictureDim[0] << ",";
125
0
  if (font.m_pictureDim[0] != font.m_pictureDim[1] &&
126
0
      (font.m_pictureDim[1].size()[0] || font.m_pictureDim[1].size()[1]))
127
0
    o << "pictDim[crop]=" << font.m_pictureDim[1] << ",";
128
0
  if (font.m_extra.length())
129
0
    o << font.m_extra << ",";
130
0
  return o;
131
0
}
132
133
/** Internal: class to store the paragraph properties */
134
struct Paragraph final : public MWAWParagraph {
135
  //! Constructor
136
  Paragraph()
137
29.2k
    : MWAWParagraph()
138
29.2k
    , m_name("")
139
29.2k
  {
140
29.2k
  }
141
70.1k
  Paragraph(Paragraph const &) = default;
142
  //! destructor
143
  ~Paragraph() final;
144
  //! operator<<
145
  friend std::ostream &operator<<(std::ostream &o, Paragraph const &ind)
146
0
  {
147
0
    o << static_cast<MWAWParagraph const &>(ind);
148
0
    if (ind.m_name.length()) o << "name=" << ind.m_name << ",";
149
0
    return o;
150
0
  }
151
  //! the paragraph name
152
  std::string m_name;
153
};
154
155
Paragraph::~Paragraph()
156
99.3k
{
157
99.3k
}
158
159
/** Internal structure: use to store a header */
160
struct HeaderFooter {
161
  //! Constructor
162
  HeaderFooter()
163
0
    : m_type(MWAWHeaderFooter::HEADER)
164
0
    , m_occurrence(MWAWHeaderFooter::NEVER)
165
0
    , m_page(0)
166
0
    , m_textParagraph(-1)
167
0
    , m_unknown(0)
168
0
    , m_parsed(false)
169
0
    , m_extra("")
170
0
  {
171
0
    for (auto &id : m_paragraph) id = -1;
172
0
  }
173
  //! operator<<
174
  friend std::ostream &operator<<(std::ostream &o, HeaderFooter const &hf);
175
  //! the header type
176
  MWAWHeaderFooter::Type m_type;
177
  //! the header occurrence
178
  MWAWHeaderFooter::Occurrence m_occurrence;
179
  //! the page
180
  int m_page;
181
  //! the paragraph position in the header zone (first and last)
182
  long m_paragraph[2];
183
  //! the text position
184
  long m_textParagraph;
185
  //! a unknown value
186
  int m_unknown;
187
  //! a flag to know if the footnote is parsed
188
  mutable bool m_parsed;
189
  //! some extra debuging information
190
  std::string m_extra;
191
};
192
193
std::ostream &operator<<(std::ostream &o, HeaderFooter const &hf)
194
0
{
195
0
  if (hf.m_type==MWAWHeaderFooter::HEADER) o << "header,";
196
0
  else o << "footer,";
197
0
  switch (hf.m_occurrence) {
198
0
  case MWAWHeaderFooter::NEVER:
199
0
    o << "never,";
200
0
    break;
201
0
  case MWAWHeaderFooter::ODD:
202
0
    o << "odd,";
203
0
    break;
204
0
  case MWAWHeaderFooter::EVEN:
205
0
    o << "even,";
206
0
    break;
207
0
  case MWAWHeaderFooter::ALL:
208
0
    o << "all,";
209
0
    break;
210
#if !defined(__clang__)
211
  default:
212
    o << "#occurrence=" << int(hf.m_occurrence) << ",";
213
    break;
214
#endif
215
0
  }
216
0
  o << "pos=" << hf.m_paragraph[0] << "<->" << hf.m_paragraph[1] << ",";
217
0
  o << "pos[def]=" << hf.m_textParagraph << ",";
218
0
  if (hf.m_unknown) o << "unkn=" << std::hex << hf.m_unknown << std::dec << ",";
219
0
  o << hf.m_extra;
220
0
  return o;
221
0
}
222
223
/** Internal structure: use to store a footnote */
224
struct Footnote {
225
  //! Constructor
226
  Footnote()
227
0
    : m_number(0)
228
0
    , m_textPosition()
229
0
    , m_textLabel("")
230
0
    , m_noteLabel("")
231
0
    , m_parsed(false)
232
0
    , m_extra("")
233
0
  {
234
0
    for (auto &id : m_paragraph) id = -1;
235
0
  }
236
237
  //! returns a label corresponding to a note ( or nothing if we can use numbering note)
238
  std::string getTextLabel(int actId) const
239
0
  {
240
0
    if (m_textLabel.length() == 0 || m_textLabel=="1")
241
0
      return std::string("");
242
0
    std::stringstream s;
243
0
    for (char c : m_textLabel) {
244
0
      if (c=='1')
245
0
        s << actId;
246
0
      else
247
0
        s << c;
248
0
    }
249
0
    return s.str();
250
0
  }
251
252
  //! operator<<
253
  friend std::ostream &operator<<(std::ostream &o, Footnote const &ft);
254
  //! the note number
255
  int m_number;
256
  //! the paragraph position in the footnote zone (first and last)
257
  int m_paragraph[2];
258
  //! the text position
259
  NisusWrtStruct::Position m_textPosition;
260
  //! the label in the text
261
  std::string m_textLabel;
262
  //! the label in the note
263
  std::string m_noteLabel;
264
  //! a flag to know if the footnote is parsed
265
  mutable bool m_parsed;
266
  //! some extra debuging information
267
  std::string m_extra;
268
};
269
270
std::ostream &operator<<(std::ostream &o, Footnote const &ft)
271
0
{
272
0
  o << "pos=" << ft.m_textPosition << ",";
273
0
  if (ft.m_paragraph[1] > ft.m_paragraph[0])
274
0
    o << "paragraph[inNote]=" << ft.m_paragraph[0] << "<->" << ft.m_paragraph[1] << ",";
275
0
  if (ft.m_number) o << "number=" << ft.m_number << ",";
276
0
  if (ft.m_textLabel.length())
277
0
    o << "textLabel=\"" << ft.m_textLabel << "\",";
278
0
  if (ft.m_noteLabel.length())
279
0
    o << "noteLabel=\"" << ft.m_noteLabel << "\",";
280
0
  if (ft.m_extra.length())
281
0
    o << ft.m_extra;
282
0
  return o;
283
0
}
284
285
//! Internal: the picture data ( PICD )
286
struct PicturePara {
287
  //! constructor
288
  PicturePara()
289
97.1k
    : m_id(-1)
290
97.1k
    , m_paragraph(-1)
291
97.1k
    , m_position()
292
97.1k
  {
293
97.1k
  }
294
  //! operator<<
295
  friend std::ostream &operator<<(std::ostream &o, PicturePara const &pict);
296
  //! the picture id
297
  int m_id;
298
  //! the paragraph position
299
  int m_paragraph;
300
  //! the position
301
  MWAWBox2i m_position;
302
};
303
304
std::ostream &operator<<(std::ostream &o, PicturePara const &pict)
305
0
{
306
0
  if (pict.m_id > 0) o << "pictId=" << pict.m_id << ",";
307
0
  if (pict.m_paragraph >= 0) o << "paragraph=" << pict.m_paragraph << ",";
308
0
  if (pict.m_position.size()[0] || pict.m_position.size()[1])
309
0
    o << "pos=" << pict.m_position << ",";
310
0
  return o;
311
0
}
312
313
/** different types
314
 *
315
 * - Format: font properties
316
 * - Ruler: new ruler
317
 */
318
enum PLCType { P_Format=0, P_Ruler, P_Footnote, P_HeaderFooter, P_PicturePara, P_Unknown};
319
320
/** Internal: class to store the PLC: Pointer List Content ? */
321
struct DataPLC {
322
  DataPLC()
323
7.75k
    : m_type(P_Format)
324
7.75k
    , m_id(-1)
325
7.75k
    , m_extra("")
326
7.75k
  {
327
7.75k
  }
328
  //! operator<<
329
  friend std::ostream &operator<<(std::ostream &o, DataPLC const &plc);
330
  //! PLC type
331
  PLCType m_type;
332
  //! the id
333
  int m_id;
334
  //! an extra data to store message ( if needed )
335
  std::string m_extra;
336
};
337
//! operator<< for DataPLC
338
std::ostream &operator<<(std::ostream &o, DataPLC const &plc)
339
0
{
340
0
  switch (plc.m_type) {
341
0
  case P_Format:
342
0
    o << "F";
343
0
    break;
344
0
  case P_Ruler:
345
0
    o << "R";
346
0
    break;
347
0
  case P_Footnote:
348
0
    o << "Fn";
349
0
    break;
350
0
  case P_HeaderFooter:
351
0
    o << "HF";
352
0
    break;
353
0
  case P_PicturePara:
354
0
    o << "Pict";
355
0
    break;
356
0
  case P_Unknown:
357
#if !defined(__clang__)
358
  default:
359
#endif
360
0
    o << "#type=" << int(plc.m_type) << ",";
361
0
  }
362
0
  if (plc.m_id >= 0) o << plc.m_id << ",";
363
0
  else o << "_";
364
0
  if (plc.m_extra.length()) o << plc.m_extra;
365
0
  return o;
366
0
}
367
368
//! internal structure used to store zone data
369
struct Zone {
370
  typedef std::multimap<NisusWrtStruct::Position, DataPLC, NisusWrtStruct::Position::Compare> PLCMap;
371
372
  //! constructor
373
  Zone()
374
27.4k
    : m_entry()
375
27.4k
    , m_paragraphList()
376
27.4k
    , m_pictureParaList()
377
27.4k
    , m_plcMap()
378
27.4k
  {
379
27.4k
  }
380
  //! the position of text in the rsrc file
381
  MWAWEntry m_entry;
382
  //! the list of paragraph
383
  std::vector<Paragraph> m_paragraphList;
384
  //! the list of paragraph
385
  std::vector<PicturePara> m_pictureParaList;
386
387
  //! the map pos -> format id
388
  PLCMap m_plcMap;
389
};
390
391
////////////////////////////////////////
392
//! Internal: the state of a NisusWrtText
393
struct State {
394
  //! constructor
395
  State()
396
9.15k
    : m_version(-1)
397
9.15k
    , m_fontList()
398
9.15k
    , m_footnoteList()
399
9.15k
    , m_numPages(-1)
400
9.15k
    , m_actualPage(0)
401
9.15k
    , m_hfList()
402
9.15k
    , m_headersId()
403
9.15k
    , m_footersId()
404
9.15k
  {
405
9.15k
  }
406
407
  //! the file version
408
  mutable int m_version;
409
410
  /** the font list */
411
  std::vector<Font> m_fontList;
412
  /** the list of footnote */
413
  std::vector<Footnote> m_footnoteList;
414
  /** the main zones : Main, Footnote, HeaderFooter */
415
  Zone m_zones[3];
416
417
  int m_numPages /* the number of pages */, m_actualPage /* the actual page */;
418
  /** the list of header footer */
419
  std::vector<HeaderFooter> m_hfList;
420
  /** the list of header id which corresponds to each page */
421
  std::vector<int> m_headersId;
422
  /** the list of footer id which corresponds to each page */
423
  std::vector<int> m_footersId;
424
};
425
426
////////////////////////////////////////
427
//! Internal: the subdocument of a NisusWrtText
428
class SubDocument final : public MWAWSubDocument
429
{
430
public:
431
  SubDocument(NisusWrtText &pars, MWAWInputStreamPtr const &input, int id, libmwaw::SubDocumentType type)
432
0
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
433
0
    , m_textParser(&pars)
434
0
    , m_id(id)
435
0
    , m_type(type)
436
0
  {
437
0
  }
438
439
  //! destructor
440
0
  ~SubDocument() final {}
441
442
  //! operator!=
443
  bool operator!=(MWAWSubDocument const &doc) const final;
444
445
  //! the parser function
446
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
447
448
protected:
449
  /** the text parser */
450
  NisusWrtText *m_textParser;
451
  //! the subdocument id
452
  int m_id;
453
  //! the subdocument type
454
  libmwaw::SubDocumentType m_type;
455
private:
456
  SubDocument(SubDocument const &orig) = delete;
457
  SubDocument &operator=(SubDocument const &orig) = delete;
458
};
459
460
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
461
0
{
462
0
  if (!listener.get()) {
463
0
    MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: no listener\n"));
464
0
    return;
465
0
  }
466
0
  if (!m_textParser) {
467
0
    MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: no parser\n"));
468
0
    return;
469
0
  }
470
0
  long pos = m_input->tell();
471
0
  if (m_type == libmwaw::DOC_NOTE)
472
0
    m_textParser->sendFootnote(m_id);
473
0
  else if (m_type == libmwaw::DOC_HEADER_FOOTER)
474
0
    m_textParser->sendHeaderFooter(m_id);
475
0
  else {
476
0
    MWAW_DEBUG_MSG(("NisusWrtTextInternal::SubDocument::parse: oops do not know how to send this kind of document\n"));
477
0
    return;
478
0
  }
479
0
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
480
0
}
481
482
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
483
0
{
484
0
  if (MWAWSubDocument::operator!=(doc)) return true;
485
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
486
0
  if (!sDoc) return true;
487
0
  if (m_textParser != sDoc->m_textParser) return true;
488
0
  if (m_id != sDoc->m_id) return true;
489
0
  if (m_type != sDoc->m_type) return true;
490
0
  return false;
491
0
}
492
}
493
494
////////////////////////////////////////////////////////////
495
// constructor/destructor, ...
496
////////////////////////////////////////////////////////////
497
NisusWrtText::NisusWrtText(NisusWrtParser &parser)
498
9.15k
  : m_parserState(parser.getParserState())
499
9.15k
  , m_state(new NisusWrtTextInternal::State)
500
9.15k
  , m_mainParser(&parser)
501
9.15k
{
502
9.15k
}
503
504
NisusWrtText::~NisusWrtText()
505
9.15k
{
506
9.15k
}
507
508
int NisusWrtText::version() const
509
0
{
510
0
  if (m_state->m_version < 0)
511
0
    m_state->m_version = m_parserState->m_version;
512
0
  return m_state->m_version;
513
0
}
514
515
int NisusWrtText::numPages() const
516
4.19k
{
517
4.19k
  if (m_state->m_numPages >= 0)
518
4.19k
    return m_state->m_numPages;
519
0
  const_cast<NisusWrtText *>(this)->computePositions();
520
0
  return m_state->m_numPages;
521
4.19k
}
522
523
std::shared_ptr<MWAWSubDocument> NisusWrtText::getHeader(int page, int &numSimilar)
524
1.00M
{
525
1.00M
  numSimilar=1;
526
1.00M
  std::shared_ptr<MWAWSubDocument> res;
527
1.00M
  auto numHeaders = int(m_state->m_headersId.size());
528
1.00M
  if (page < 1 || page-1 >= numHeaders) {
529
1.00M
    if (m_state->m_numPages>page)
530
0
      numSimilar=m_state->m_numPages-page+1;
531
1.00M
    return res;
532
1.00M
  }
533
3.98k
  int hId = m_state->m_headersId[size_t(page-1)];
534
3.98k
  if (hId >= 0)
535
0
    res.reset(new NisusWrtTextInternal::SubDocument(*this, m_mainParser->rsrcInput(), hId, libmwaw::DOC_HEADER_FOOTER));
536
4.71k
  while (page < numHeaders && m_state->m_headersId[size_t(page)]==hId) {
537
727
    page++;
538
727
    numSimilar++;
539
727
  }
540
3.98k
  return res;
541
1.00M
}
542
543
std::shared_ptr<MWAWSubDocument> NisusWrtText::getFooter(int page, int &numSimilar)
544
1.00M
{
545
1.00M
  numSimilar=1;
546
1.00M
  std::shared_ptr<MWAWSubDocument> res;
547
1.00M
  auto numFooters = int(m_state->m_footersId.size());
548
1.00M
  if (page < 1 || page-1 >= numFooters) {
549
1.00M
    if (m_state->m_numPages>page)
550
0
      numSimilar=m_state->m_numPages-page+1;
551
1.00M
    return res;
552
1.00M
  }
553
3.98k
  int fId = m_state->m_footersId[size_t(page-1)];
554
3.98k
  if (fId >= 0)
555
0
    res.reset(new NisusWrtTextInternal::SubDocument(*this, m_mainParser->rsrcInput(), fId, libmwaw::DOC_HEADER_FOOTER));
556
4.71k
  while (page < numFooters && m_state->m_footersId[size_t(page)]==fId) {
557
727
    page++;
558
727
    numSimilar++;
559
727
  }
560
561
3.98k
  return res;
562
1.00M
}
563
564
void NisusWrtText::computePositions()
565
3.98k
{
566
  // first compute the number of page and the number of paragraph by pages
567
3.98k
  int nPages = 1;
568
3.98k
  MWAWInputStreamPtr input = m_mainParser->getInput();
569
3.98k
  input->seek(0, librevenge::RVNG_SEEK_SET);
570
3.98k
  int paragraph=0;
571
3.98k
  std::vector<int> firstParagraphInPage;
572
3.98k
  firstParagraphInPage.push_back(0);
573
2.80M
  while (!input->isEnd()) {
574
2.80M
    auto c = char(input->readULong(1));
575
2.80M
    if (c==0xd)
576
112k
      paragraph++;
577
2.69M
    else if (c==0xc) {
578
727
      nPages++;
579
727
      firstParagraphInPage.push_back(paragraph);
580
727
    }
581
2.80M
  }
582
3.98k
  m_state->m_actualPage = 1;
583
3.98k
  m_state->m_numPages = nPages;
584
585
  // update the main page zone
586
3.98k
  m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setBegin(0);
587
3.98k
  m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setEnd(input->tell());
588
3.98k
  m_state->m_zones[NisusWrtStruct::Z_Main].m_entry.setId(NisusWrtStruct::Z_Main);
589
  // compute the header/footer pages
590
3.98k
  int actPage = 1;
591
3.98k
  MWAWVec2i headerId(-1, -1), footerId(-1, -1);
592
3.98k
  m_state->m_headersId.resize(size_t(nPages), -1);
593
3.98k
  m_state->m_footersId.resize(size_t(nPages), -1);
594
3.98k
  for (size_t i = 0; i < m_state->m_hfList.size(); i++) {
595
0
    auto &hf = m_state->m_hfList[i];
596
0
    int page = 1;
597
0
    long textPos = hf.m_textParagraph;
598
0
    if (hf.m_type == MWAWHeaderFooter::FOOTER && textPos) textPos--;
599
0
    for (size_t j = 0; j < firstParagraphInPage.size(); j++) {
600
0
      if (textPos < firstParagraphInPage[j])
601
0
        break;
602
0
      page = int(j)+1;
603
0
    }
604
    //std::cerr << "find : page=" << page << " for hf" << int(i) << "\n";
605
0
    for (int p = actPage;  p < page; p++) {
606
0
      m_state->m_headersId[size_t(p)-1] = (p%2) ? headerId[0] : headerId[1];
607
0
      m_state->m_footersId[size_t(p)-1] = (p%2) ? footerId[0] : footerId[1];
608
0
    }
609
0
    actPage = hf.m_page = page;
610
0
    MWAWVec2i &wh = hf.m_type == MWAWHeaderFooter::HEADER ? headerId : footerId;
611
0
    switch (hf.m_occurrence) {
612
0
    case MWAWHeaderFooter::ODD:
613
0
      wh[0] = int(i);
614
0
      break;
615
0
    case MWAWHeaderFooter::EVEN:
616
0
      wh[1] = int(i);
617
0
      break;
618
0
    case MWAWHeaderFooter::ALL:
619
0
      wh[0] = wh[1] = int(i);
620
0
      break;
621
0
    case MWAWHeaderFooter::NEVER:
622
0
      wh[0] = wh[1] = -1;
623
0
      break;
624
#if !defined(__clang__)
625
    default:
626
      break;
627
#endif
628
0
    }
629
0
  }
630
8.70k
  for (int p = actPage;  p <= nPages; p++) {
631
4.71k
    m_state->m_headersId[size_t(p)-1] = (p%2) ? headerId[0] : headerId[1];
632
4.71k
    m_state->m_footersId[size_t(p)-1] = (p%2) ? footerId[0] : footerId[1];
633
4.71k
  }
634
3.98k
}
635
636
////////////////////////////////////////////////////////////
637
// Intermediate level
638
////////////////////////////////////////////////////////////
639
640
// find the different zones
641
bool NisusWrtText::createZones()
642
3.98k
{
643
3.98k
  if (!m_mainParser->getRSRCParser()) {
644
0
    MWAW_DEBUG_MSG(("NisusWrtText::createZones: can not find the entry map\n"));
645
0
    return false;
646
0
  }
647
3.98k
  auto const &entryMap = m_mainParser->getRSRCParser()->getEntriesMap();
648
649
  // footnote and headerFooter main zone
650
3.98k
  auto it = entryMap.lower_bound("HF  ");
651
3.98k
  while (it != entryMap.end()) {
652
3.98k
    if (it->first != "HF  ")
653
3.98k
      break;
654
0
    MWAWEntry const &entry = it++->second;
655
0
    readHeaderFooter(entry);
656
0
  }
657
3.98k
  it = entryMap.lower_bound("FOOT");
658
3.98k
  while (it != entryMap.end()) {
659
3.98k
    if (it->first != "FOOT")
660
3.98k
      break;
661
0
    MWAWEntry const &entry = it++->second;
662
0
    readFootnotes(entry);
663
0
  }
664
665
  // fonts
666
3.98k
  it = entryMap.lower_bound("FLST");
667
9.28k
  while (it != entryMap.end()) {
668
9.28k
    if (it->first != "FLST")
669
3.98k
      break;
670
5.29k
    MWAWEntry const &entry = it++->second;
671
5.29k
    readFontsList(entry);
672
5.29k
  }
673
3.98k
  it = entryMap.lower_bound("STYL");
674
8.38k
  while (it != entryMap.end()) {
675
8.38k
    if (it->first != "STYL")
676
3.98k
      break;
677
4.39k
    MWAWEntry const &entry = it++->second;
678
4.39k
    readFonts(entry);
679
4.39k
  }
680
3.98k
  it = entryMap.lower_bound("FTAB");
681
7.92k
  while (it != entryMap.end()) {
682
7.92k
    if (it->first != "FTAB")
683
3.98k
      break;
684
3.93k
    MWAWEntry const &entry = it++->second;
685
3.93k
    readFonts(entry);
686
3.93k
  }
687
688
  // the font change
689
3.98k
  char const *posFontNames[] = { "FRMT", "FFRM", "HFRM" };
690
15.9k
  for (int z = 0; z < 3; z++) {
691
11.9k
    it = entryMap.lower_bound(posFontNames[z]);
692
15.9k
    while (it != entryMap.end()) {
693
15.9k
      if (it->first != posFontNames[z])
694
11.9k
        break;
695
3.97k
      MWAWEntry const &entry = it++->second;
696
3.97k
      readPosToFont(entry, NisusWrtStruct::ZoneType(z));
697
3.97k
    }
698
11.9k
  }
699
700
  // the paragraph: in mainZone 1004 means style paragraph
701
3.98k
  char const *paragNames[] = { "RULE", "FRUL", "HRUL" };
702
15.9k
  for (int z = 0; z < 3; z++) {
703
11.9k
    it = entryMap.lower_bound(paragNames[z]);
704
17.1k
    while (it != entryMap.end()) {
705
17.1k
      if (it->first != paragNames[z])
706
11.9k
        break;
707
5.22k
      MWAWEntry const &entry = it++->second;
708
5.22k
      readParagraphs(entry, NisusWrtStruct::ZoneType(z));
709
5.22k
    }
710
11.9k
  }
711
  // the picture associated to the paragraph
712
3.98k
  char const *pictDNames[] = { "PICD", "FPIC", "HPIC" };
713
15.9k
  for (int z = 0; z < 3; z++) {
714
11.9k
    it = entryMap.lower_bound(pictDNames[z]);
715
15.9k
    while (it != entryMap.end()) {
716
15.9k
      if (it->first != pictDNames[z])
717
11.9k
        break;
718
4.03k
      MWAWEntry const &entry = it++->second;
719
4.03k
      readPICD(entry, NisusWrtStruct::ZoneType(z));
720
4.03k
    }
721
11.9k
  }
722
723
  // End of the style zone
724
725
  // style name ( can also contains some flags... )
726
3.98k
  it = entryMap.lower_bound("STNM");
727
7.02k
  while (it != entryMap.end()) {
728
7.02k
    if (it->first != "STNM")
729
3.98k
      break;
730
3.03k
    MWAWEntry const &entry = it++->second;
731
3.03k
    std::vector<std::string> list;
732
3.03k
    m_mainParser->readStringsList(entry, list, false);
733
3.03k
  }
734
  // style link to paragraph name
735
3.98k
  it = entryMap.lower_bound("STRL");
736
7.80k
  while (it != entryMap.end()) {
737
7.80k
    if (it->first != "STRL")
738
3.98k
      break;
739
3.81k
    MWAWEntry const &entry = it++->second;
740
3.81k
    std::vector<std::string> list;
741
3.81k
    m_mainParser->readStringsList(entry, list, false);
742
3.81k
  }
743
  // style next name
744
3.98k
  it = entryMap.lower_bound("STNX");
745
9.58k
  while (it != entryMap.end()) {
746
9.58k
    if (it->first != "STNX")
747
3.98k
      break;
748
5.59k
    MWAWEntry const &entry = it++->second;
749
5.59k
    std::vector<std::string> list;
750
5.59k
    m_mainParser->readStringsList(entry, list, false);
751
5.59k
  }
752
753
  // the text zone
754
3.98k
  char const *textNames[] = { "", "FNTX", "HFTX" };
755
11.9k
  for (int z = 1; z < 3; z++) {
756
7.97k
    it = entryMap.lower_bound(textNames[z]);
757
7.97k
    while (it != entryMap.end()) {
758
7.97k
      if (it->first != textNames[z])
759
7.97k
        break;
760
0
      m_state->m_zones[z].m_entry = it++->second;
761
0
      m_state->m_zones[z].m_entry.setId(z);
762
0
    }
763
7.97k
  }
764
  // now update the different data
765
3.98k
  computePositions();
766
3.98k
  return true;
767
3.98k
}
768
769
////////////////////////////////////////////////////////////
770
//     Fonts
771
////////////////////////////////////////////////////////////
772
773
// read a list of fonts
774
bool NisusWrtText::readFontsList(MWAWEntry const &entry)
775
5.29k
{
776
5.29k
  if (!entry.valid() && entry.length()!=0) {
777
1.79k
    MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: the entry is bad\n"));
778
1.79k
    return false;
779
1.79k
  }
780
3.49k
  entry.setParsed(true);
781
3.49k
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
782
3.49k
  if (!input || !input->checkPosition(entry.end())) {
783
0
    MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: the zone is too short\n"));
784
0
    return false;
785
0
  }
786
3.49k
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
787
3.49k
  long pos = entry.begin();
788
3.49k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
789
790
3.49k
  libmwaw::DebugStream f;
791
3.49k
  f << "Entries(FontNames)[" << entry.id() << "]:";
792
3.49k
  asciiFile.addPos(pos-4);
793
3.49k
  asciiFile.addNote(f.str().c_str());
794
795
3.49k
  int num=0;
796
140k
  while (!input->isEnd()) {
797
140k
    pos = input->tell();
798
140k
    if (pos == entry.end()) break;
799
139k
    if (pos+4 > entry.end()) {
800
219
      asciiFile.addPos(pos);
801
219
      asciiFile.addNote("FontNames###");
802
803
219
      MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: can not read flst\n"));
804
219
      return false;
805
219
    }
806
139k
    auto fId = static_cast<int>(input->readULong(2));
807
139k
    f.str("");
808
139k
    f << "FontNames" << num++ << ":fId=" << std::hex << fId << std::dec << ",";
809
139k
    auto pSz = static_cast<int>(input->readULong(1));
810
811
139k
    if (pSz+1+pos+2 > entry.end()) {
812
2.25k
      f << "###";
813
2.25k
      asciiFile.addPos(pos);
814
2.25k
      asciiFile.addNote(f.str().c_str());
815
816
2.25k
      MWAW_DEBUG_MSG(("NisusWrtText::readFontsList: can not read pSize\n"));
817
2.25k
      return false;
818
2.25k
    }
819
137k
    std::string name("");
820
1.00M
    for (int c=0; c < pSz; c++)
821
871k
      name += char(input->readULong(1));
822
137k
    m_parserState->m_fontConverter->setCorrespondance(fId, name);
823
137k
    f << name;
824
137k
    asciiFile.addPos(pos);
825
137k
    asciiFile.addNote(f.str().c_str());
826
137k
    if ((pSz%2)==0) input->seek(1,librevenge::RVNG_SEEK_CUR);
827
137k
  }
828
1.02k
  return true;
829
3.49k
}
830
831
// read the FTAB/STYL resource: a font format ?
832
bool NisusWrtText::readFonts(MWAWEntry const &entry)
833
8.33k
{
834
8.33k
  bool isStyle = entry.type()=="STYL";
835
8.33k
  int const fSize = isStyle ? 58 : 98;
836
8.33k
  std::string name(isStyle ? "Style" : "Fonts");
837
8.33k
  if ((!entry.valid()&&entry.length()) || (entry.length()%fSize)) {
838
5.27k
    MWAW_DEBUG_MSG(("NisusWrtText::readFonts: the entry is bad\n"));
839
5.27k
    return false;
840
5.27k
  }
841
3.06k
  entry.setParsed(true);
842
3.06k
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
843
3.06k
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
844
3.06k
  long pos = entry.begin();
845
3.06k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
846
847
3.06k
  auto numElt = int(entry.length()/fSize);
848
3.06k
  libmwaw::DebugStream f;
849
3.06k
  f << "Entries(" << name << ")[" << entry.id() << "]:N=" << numElt;
850
3.06k
  asciiFile.addPos(pos-4);
851
3.06k
  asciiFile.addNote(f.str().c_str());
852
853
3.06k
  long val;
854
61.6k
  for (int i = 0; i < numElt; i++) {
855
58.5k
    NisusWrtTextInternal::Font font;
856
58.5k
    pos = input->tell();
857
58.5k
    f.str("");
858
58.5k
    if (!isStyle)
859
55.5k
      font.m_pictureId = static_cast<int>(input->readLong(2));
860
861
58.5k
    if (font.m_pictureId) {
862
      // the two value seems to differ slightly for a picture
863
2.15k
      val = long(input->readULong(2));
864
2.15k
      if (val != 0xFF01) f << "#pictFlags0=" << std::hex << val << ",";
865
2.15k
      font.m_pictureWidth = static_cast<int>(input->readLong(2));
866
2.15k
    }
867
56.4k
    else {
868
56.4k
      val = long(input->readULong(2));
869
56.4k
      if (val != 0xFF00)
870
56.4k
        font.m_font.setId(int(val));
871
56.4k
      val = long(input->readULong(2));
872
56.4k
      if (val != 0xFF00)
873
56.4k
        font.m_font.setSize(float(val));
874
56.4k
    }
875
876
58.5k
    uint32_t flags=0;
877
58.5k
    auto flag = static_cast<int>(input->readULong(2));
878
879
58.5k
    if (flag&0x1) flags |= MWAWFont::boldBit;
880
58.5k
    if (flag&0x2) flags |= MWAWFont::italicBit;
881
58.5k
    if (flag&0x4) font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
882
58.5k
    if (flag&0x8) flags |= MWAWFont::embossBit;
883
58.5k
    if (flag&0x10) flags |= MWAWFont::shadowBit;
884
58.5k
    if (flag&0x20) font.m_font.setDeltaLetterSpacing(-1);
885
58.5k
    if (flag&0x40) font.m_font.setDeltaLetterSpacing(1);
886
58.5k
    if (flag &0xFF80)
887
647
      f << "#flags0=" << std::hex << (flag &0xFF80) << std::dec << ",";
888
58.5k
    flag = static_cast<int>(input->readULong(2));
889
58.5k
    if (flag & 1) {
890
2.01k
      font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
891
2.01k
      f << "underline[lower],";
892
2.01k
    }
893
58.5k
    if (flag & 2)  font.m_font.setUnderlineStyle(MWAWFont::Line::Dot);
894
58.5k
    if (flag & 4)  font.m_font.setUnderlineWordFlag(true);
895
58.5k
    if (flag & 0x8) font.m_font.set(MWAWFont::Script::super());
896
58.5k
    if (flag & 0x10) font.m_font.set(MWAWFont::Script::sub());
897
58.5k
    if (flag & 0x20) font.m_font.setStrikeOutStyle(MWAWFont::Line::Simple);
898
58.5k
    if (flag & 0x40) font.m_font.setOverlineStyle(MWAWFont::Line::Simple);
899
58.5k
    if (flag & 0x80) flags |= MWAWFont::smallCapsBit;
900
58.5k
    if (flag & 0x100) flags |= MWAWFont::uppercaseBit;
901
58.5k
    if (flag & 0x200) flags |= MWAWFont::boxedBit;
902
58.5k
    if (flag & 0x400) flags |= MWAWFont::hiddenBit;
903
58.5k
    if (flag & 0x1000) font.m_font.set(MWAWFont::Script(40,librevenge::RVNG_PERCENT,58));
904
58.5k
    if (flag & 0x2000) font.m_font.set(MWAWFont::Script(-40,librevenge::RVNG_PERCENT,58));
905
58.5k
    if (flag & 0x4000) flags |= MWAWFont::reverseVideoBit;
906
58.5k
    if (flag & 0x8800)
907
117
      f << "#flags1=" << std::hex << (flag & 0x8800) << std::dec << ",";
908
58.5k
    val = input->readLong(2);
909
58.5k
    if (val) f << "#f0=" << std::hex << val << ",";
910
58.5k
    font.m_format = static_cast<int>(input->readULong(1));
911
58.5k
    if (font.m_format & 8) {
912
1.70k
      font.m_format &= 0xF7;
913
1.70k
      flags |= MWAWFont::reverseWritingBit;
914
1.70k
    }
915
58.5k
    font.m_format2 = static_cast<int>(input->readULong(1));
916
58.5k
    font.m_font.setFlags(flags);
917
918
58.5k
    int color = 0;
919
    // now data differs
920
58.5k
    if (isStyle) {
921
3.01k
      val = static_cast<int>(input->readULong(2)); // find [0-3] here
922
3.01k
      if (val) f << "unkn0=" << val << ",";
923
21.1k
      for (int j = 0; j < 6; j++) { // find s0=67, s1=a728
924
18.0k
        val = static_cast<int>(input->readULong(2));
925
18.0k
        if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
926
18.0k
      }
927
3.01k
      color = static_cast<int>(input->readULong(2));
928
3.01k
    }
929
55.5k
    else {
930
55.5k
      color = static_cast<int>(input->readULong(2));
931
333k
      for (int j = 1; j < 6; j++) { // find always 0 here...
932
277k
        val = static_cast<int>(input->readULong(2));
933
277k
        if (val) f << "#f" << j << "=" << val << ",";
934
277k
      }
935
55.5k
      bool hasMark = false;
936
55.5k
      val = static_cast<int>(input->readULong(2));
937
55.5k
      if (val == 1) hasMark = true;
938
52.3k
      else if (val) f << "#hasMark=" << val << ",";
939
55.5k
      val = static_cast<int>(input->readULong(2));
940
55.5k
      if (hasMark) font.m_markId = int(val);
941
52.3k
      else if (val) f << "#markId=" << val << ",";
942
      // f0=0|1 and if f0=1 then f1 is a small number between 1 and 20
943
1.05M
      for (int j = 0; j < 18; j++) {
944
1.00M
        val = static_cast<int>(input->readULong(2));
945
1.00M
        if (val) f << "g" << j << "=" << val << ",";
946
1.00M
      }
947
55.5k
      float expand=float(input->readLong(4))/65536.f;
948
55.5k
      if (expand < 0 || expand > 0)
949
1.11k
        font.m_font.setDeltaLetterSpacing(expand);
950
      // 0, -1 or a small number related to the variable id : probably unknowncst+vId
951
55.5k
      font.m_variableId = static_cast<int>(input->readLong(4));
952
      // the remaining seems to be 0 excepted for picture
953
277k
      for (int j = 0; j < 4; j++) { // find 0,0,[0|d5|f5|f8|ba], big number
954
222k
        val = static_cast<int>(input->readULong(2));
955
222k
        if (val) f << "h" << j << "=" << std::hex << val << std::dec << ",";
956
222k
      }
957
      // two dim ?
958
111k
      for (auto &pictDim : font.m_pictureDim) {
959
111k
        int dim[4];
960
444k
        for (auto &d : dim) d = static_cast<int>(input->readLong(2));
961
111k
        pictDim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]),MWAWVec2i(dim[3],dim[2]));
962
111k
      }
963
55.5k
    }
964
965
58.5k
    static const uint32_t colors[] =
966
58.5k
    { 0, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF, 0xFFFF00, 0xFFFFFF };
967
58.5k
    if (color >= 0 && color < 8)
968
57.2k
      font.m_font.setColor(MWAWColor(colors[color]));
969
1.32k
    else if (color != 0xFF00)
970
1.29k
      f << "#color=" << color << ",";
971
58.5k
    font.m_extra = f.str();
972
58.5k
    if (!isStyle)
973
55.5k
      m_state->m_fontList.push_back(font);
974
975
58.5k
    f.str("");
976
58.5k
    f << name << i << ":" << font.m_font.getDebugString(m_parserState->m_fontConverter)
977
58.5k
      << font;
978
58.5k
    if (input->tell() != pos+fSize)
979
3.01k
      asciiFile.addDelimiter(input->tell(),'|');
980
58.5k
    asciiFile.addPos(pos);
981
58.5k
    asciiFile.addNote(f.str().c_str());
982
58.5k
    input->seek(pos+fSize, librevenge::RVNG_SEEK_SET);
983
58.5k
  }
984
3.06k
  return true;
985
8.33k
}
986
987
// read the FRMT resource: filepos -> fonts
988
bool NisusWrtText::readPosToFont(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
989
3.97k
{
990
3.97k
  if (!entry.valid() || (entry.length()%10)) {
991
2.05k
    MWAW_DEBUG_MSG(("NisusWrtText::readPosToFont: the entry is bad\n"));
992
2.05k
    return false;
993
2.05k
  }
994
1.92k
  if (zoneId >= 3) {
995
0
    MWAW_DEBUG_MSG(("NisusWrtText::readPosToFont: find unexpected zoneId: %d\n", zoneId));
996
0
    return false;
997
0
  }
998
1.92k
  NisusWrtTextInternal::Zone &zone = m_state->m_zones[zoneId];
999
1.92k
  entry.setParsed(true);
1000
1.92k
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1001
1.92k
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1002
1.92k
  long pos = entry.begin();
1003
1.92k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1004
1005
1.92k
  auto numElt = int(entry.length()/10);
1006
1.92k
  libmwaw::DebugStream f;
1007
1.92k
  f << "Entries(PosToFont)[" << zoneId << "]:N=" << numElt;
1008
1.92k
  asciiFile.addPos(pos-4);
1009
1.92k
  asciiFile.addNote(f.str().c_str());
1010
1011
1.92k
  NisusWrtStruct::Position position;
1012
1.92k
  NisusWrtTextInternal::DataPLC plc;
1013
1.92k
  plc.m_type = NisusWrtTextInternal::P_Format;
1014
127k
  for (int i = 0; i < numElt; i++) {
1015
125k
    pos = input->tell();
1016
125k
    f.str("");
1017
125k
    f << "PosToFont" << i << "[" << zoneId << "]:";
1018
125k
    position.m_paragraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1019
125k
    position.m_word = static_cast<int>(input->readULong(2));
1020
125k
    position.m_char = static_cast<int>(input->readULong(2));
1021
125k
    f << "pos=" << position << ",";
1022
125k
    auto id = static_cast<int>(input->readLong(2));
1023
125k
    f << "F" << id << ",";
1024
125k
    plc.m_id = id;
1025
125k
    zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(position, plc));
1026
125k
    asciiFile.addPos(pos);
1027
125k
    asciiFile.addNote(f.str().c_str());
1028
125k
    input->seek(pos+10, librevenge::RVNG_SEEK_SET);
1029
125k
  }
1030
1.92k
  return true;
1031
1.92k
}
1032
1033
////////////////////////////////////////////////////////////
1034
// the paragraphs
1035
////////////////////////////////////////////////////////////
1036
1037
// send the paragraph to the listener
1038
void NisusWrtText::setProperty(NisusWrtTextInternal::Paragraph const &para, int width)
1039
26.5k
{
1040
26.5k
  if (!m_parserState->m_textListener) return;
1041
26.5k
  double origRMargin = para.m_margins[2].get();
1042
26.5k
  double rMargin=double(width)/72.-origRMargin;
1043
26.5k
  if (rMargin < 0.0) rMargin = 0;
1044
26.5k
  const_cast<NisusWrtTextInternal::Paragraph &>(para).m_margins[2] = rMargin;
1045
26.5k
  m_parserState->m_textListener->setParagraph(para);
1046
26.5k
  const_cast<NisusWrtTextInternal::Paragraph &>(para).m_margins[2] = origRMargin;
1047
26.5k
}
1048
1049
// read the RULE resource: a list of rulers
1050
bool NisusWrtText::readParagraphs(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
1051
5.22k
{
1052
5.22k
  if (!entry.valid() && entry.length() != 0) {
1053
1.54k
    MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: the entry is bad\n"));
1054
1.54k
    return false;
1055
1.54k
  }
1056
3.67k
  if (zoneId >= 3) {
1057
0
    MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find unexpected zoneId: %d\n", zoneId));
1058
0
    return false;
1059
0
  }
1060
3.67k
  auto &zone = m_state->m_zones[zoneId];
1061
1062
3.67k
  entry.setParsed(true);
1063
3.67k
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1064
3.67k
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1065
3.67k
  long pos = entry.begin();
1066
3.67k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1067
1068
3.67k
  auto numElt = int(entry.length()/98);
1069
3.67k
  libmwaw::DebugStream f, f2;
1070
3.67k
  f << "Entries(RULE)[" << entry.type() << entry.id() << "]";
1071
3.67k
  if (entry.id()==1004) f << "[Styl]";
1072
3.67k
  else if (entry.id() != 1003) {
1073
664
    MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find unexpected entryId: %d\n", entry.id()));
1074
664
    f << "###";
1075
664
  }
1076
3.67k
  f << ":N=" << numElt;
1077
3.67k
  asciiFile.addPos(pos-4);
1078
3.67k
  asciiFile.addNote(f.str().c_str());
1079
1080
3.67k
  NisusWrtTextInternal::DataPLC plc;
1081
3.67k
  plc.m_type = NisusWrtTextInternal::P_Ruler;
1082
1083
3.67k
  long val;
1084
32.9k
  while (input->tell() != entry.end()) {
1085
32.5k
    int num = (entry.id() == 1003) ? static_cast<int>(zone.m_paragraphList.size()) : -1;
1086
32.5k
    pos = input->tell();
1087
32.5k
    f.str("");
1088
32.5k
    if (pos+8 > entry.end() || input->isEnd()) {
1089
79
      f << "RULE" << num << "[" << zoneId << "]:###";
1090
79
      asciiFile.addPos(pos);
1091
79
      asciiFile.addNote(f.str().c_str());
1092
1093
79
      MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read end of zone\n"));
1094
79
      return false;
1095
79
    }
1096
1097
32.4k
    auto nPara = long(input->readULong(4));
1098
32.4k
    if (nPara == 0x7FFFFFFF) {
1099
1.23k
      input->seek(-4, librevenge::RVNG_SEEK_CUR);
1100
1.23k
      break;
1101
1.23k
    }
1102
31.2k
    NisusWrtStruct::Position textPosition;
1103
31.2k
    textPosition.m_paragraph = static_cast<int>(nPara);  // checkme or ???? + para
1104
1105
31.2k
    auto sz = long(input->readULong(4));
1106
31.2k
    if (sz < 0x42 || pos+sz > entry.end()) {
1107
1.96k
      f << "RULE" << num << "[" << zoneId << "]:###";
1108
1.96k
      asciiFile.addPos(pos);
1109
1.96k
      asciiFile.addNote(f.str().c_str());
1110
1111
1.96k
      MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the size zone\n"));
1112
1.96k
      return false;
1113
1.96k
    }
1114
29.2k
    NisusWrtTextInternal::Paragraph para;
1115
1116
29.2k
    para.setInterline(double(input->readLong(4))/65536., librevenge::RVNG_POINT, MWAWParagraph::AtLeast);
1117
29.2k
    para.m_spacings[1] = double(input->readLong(4))/65536./72.;
1118
29.2k
    auto wh = int(input->readLong(2));
1119
29.2k
    switch (wh) {
1120
24.7k
    case 0:
1121
24.7k
      break; // left
1122
1.32k
    case 1:
1123
1.32k
      para.m_justify = MWAWParagraph::JustificationCenter;
1124
1.32k
      break;
1125
1.66k
    case 2:
1126
1.66k
      para.m_justify = MWAWParagraph::JustificationRight;
1127
1.66k
      break;
1128
1.29k
    case 3:
1129
1.29k
      para.m_justify = MWAWParagraph::JustificationFull;
1130
1.29k
      break;
1131
193
    default:
1132
193
      f << "#align=" << wh << ",";
1133
193
      break;
1134
29.2k
    }
1135
29.2k
    val = input->readLong(2);
1136
29.2k
    if (val) f << "#f0=" << val << ",";
1137
1138
29.2k
    para.m_marginsUnit = librevenge::RVNG_INCH;
1139
29.2k
    para.m_margins[0] = double(input->readLong(4))/65536./72.;
1140
29.2k
    para.m_margins[1] = double(input->readLong(4))/65536./72.;
1141
29.2k
    para.m_margins[2] = double(input->readLong(4))/65536./72.;
1142
29.2k
    para.m_margins[0] =para.m_margins[0].get()-para.m_margins[1].get();
1143
29.2k
    wh = int(input->readULong(1));
1144
29.2k
    switch (wh) {
1145
25.0k
    case 0: // at least
1146
25.0k
      break;
1147
1.27k
    case 1:
1148
1.27k
      para.m_spacingsInterlineType = MWAWParagraph::Fixed;
1149
1.27k
      break;
1150
2.41k
    case 2:
1151
2.41k
      para.m_spacingsInterlineUnit = librevenge::RVNG_PERCENT;
1152
2.41k
      para.m_spacingsInterlineType = MWAWParagraph::Fixed;
1153
      // before spacing is also in %, try to correct it
1154
2.41k
      para.m_spacings[1] = para.m_spacings[1].get()*12.0;
1155
2.41k
      break;
1156
461
    default: // unknown, so...
1157
461
      f << "#interline=" << (val&0xFC) << ",";
1158
461
      para.setInterline(1.0, librevenge::RVNG_PERCENT);
1159
461
      break;
1160
29.2k
    }
1161
29.2k
    val = input->readLong(1);
1162
29.2k
    if (val) f << "#f1=" << val << ",";
1163
438k
    for (int i = 0; i < 14; i++) {
1164
409k
      val = input->readLong(2);
1165
409k
      if (val) f << "g" << i << "=" << val << ",";
1166
409k
    }
1167
29.2k
    input->seek(pos+0x3E, librevenge::RVNG_SEEK_SET);
1168
29.2k
    long numTabs = input->readLong(2);
1169
29.2k
    bool ok = true;
1170
29.2k
    if (0x40+8*numTabs+2 > sz) {
1171
280
      f << "###";
1172
280
      MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the string\n"));
1173
280
      ok = false;
1174
280
      numTabs = 0;
1175
280
    }
1176
58.1k
    for (long i = 0; i < numTabs; i++) {
1177
28.8k
      long tabPos = input->tell();
1178
28.8k
      MWAWTabStop tab;
1179
1180
28.8k
      f2.str("");
1181
28.8k
      tab.m_position = double(input->readLong(4))/72./65536.; // from left pos
1182
28.8k
      val = long(input->readULong(1));
1183
28.8k
      switch (val) {
1184
12.8k
      case 1:
1185
12.8k
        break;
1186
3.93k
      case 2:
1187
3.93k
        tab.m_alignment = MWAWTabStop::CENTER;
1188
3.93k
        break;
1189
3.93k
      case 3:
1190
3.93k
        tab.m_alignment = MWAWTabStop::RIGHT;
1191
3.93k
        break;
1192
3.92k
      case 4:
1193
3.92k
        tab.m_alignment = MWAWTabStop::DECIMAL;
1194
3.92k
        break;
1195
3.91k
      case 6: // a little old, look simillar to full justification
1196
3.91k
        f2 << "justify,";
1197
3.91k
        break;
1198
307
      default:
1199
307
        f2 << "#type=" << val << ",";
1200
307
        break;
1201
28.8k
      }
1202
28.8k
      auto leader=static_cast<unsigned char>(input->readULong(1));
1203
28.8k
      if (leader) {
1204
7.71k
        int unicode= m_parserState->m_fontConverter->unicode(3, leader);
1205
7.71k
        if (unicode==-1)
1206
72
          tab.m_leaderCharacter =static_cast<unsigned short>(leader);
1207
7.64k
        else
1208
7.64k
          tab.m_leaderCharacter =static_cast<unsigned short>(unicode);
1209
7.71k
      }
1210
28.8k
      val = long(input->readLong(2)); // unused ?
1211
28.8k
      if (val) f2 << "#unkn0=" << val << ",";
1212
28.8k
      para.m_tabs->push_back(tab);
1213
28.8k
      if (f2.str().length())
1214
0
        f << "tab" << i << "=[" << f2.str() << "],";
1215
28.8k
      input->seek(tabPos+8, librevenge::RVNG_SEEK_SET);
1216
28.8k
    }
1217
1218
    // ruler name
1219
29.2k
    long pSz = ok ? long(input->readULong(1)) : 0;
1220
29.2k
    if (pSz) {
1221
174
      if (input->tell()+pSz != pos+sz && input->tell()+pSz+1 != pos+sz) {
1222
171
        f << "name###";
1223
171
        MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: can not read the ruler name\n"));
1224
171
        asciiFile.addDelimiter(input->tell()-1,'#');
1225
171
      }
1226
3
      else {
1227
3
        std::string str("");
1228
6
        for (long i = 0; i < pSz; i++)
1229
3
          str += char(input->readULong(1));
1230
3
        para.m_name = str;
1231
3
      }
1232
174
    }
1233
29.2k
    plc.m_id = num;
1234
29.2k
    para.m_extra=f.str();
1235
29.2k
    if (entry.id() == 1003) {
1236
28.5k
      zone.m_paragraphList.push_back(para);
1237
28.5k
      zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(textPosition, plc));
1238
28.5k
    }
1239
1240
29.2k
    f.str("");
1241
29.2k
    f << "RULE" << num << "[" << zoneId << "]:";
1242
29.2k
    f << "paragraph=" << nPara << "," << para;
1243
1244
29.2k
    asciiFile.addPos(pos);
1245
29.2k
    asciiFile.addNote(f.str().c_str());
1246
29.2k
    input->seek(pos+sz, librevenge::RVNG_SEEK_SET);
1247
29.2k
  }
1248
1.63k
  pos = input->tell();
1249
1.63k
  f.str("");
1250
1.63k
  f << "RULE[" << zoneId << "](II):";
1251
1.63k
  if (pos+66 != entry.end() || input->readULong(4) != 0x7FFFFFFF) {
1252
404
    f << "###";
1253
404
    asciiFile.addPos(pos);
1254
404
    asciiFile.addNote(f.str().c_str());
1255
1256
404
    MWAW_DEBUG_MSG(("NisusWrtText::readParagraphs: find odd end\n"));
1257
404
    return true;
1258
404
  }
1259
39.4k
  for (int i = 0; i < 31; i++) { // only find 0 expected f12=0|100
1260
38.2k
    val = long(input->readLong(2));
1261
38.2k
    if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1262
38.2k
  }
1263
1.23k
  asciiFile.addPos(pos);
1264
1.23k
  asciiFile.addNote(f.str().c_str());
1265
1266
1.23k
  return true;
1267
1.63k
}
1268
1269
////////////////////////////////////////////////////////////
1270
//     the zones header
1271
////////////////////////////////////////////////////////////
1272
1273
// read the header/footer main entry
1274
bool NisusWrtText::readHeaderFooter(MWAWEntry const &entry)
1275
0
{
1276
0
  if (!entry.valid() || (entry.length()%32)) {
1277
0
    MWAW_DEBUG_MSG(("NisusWrtText::readHeaderFooter: the entry is bad\n"));
1278
0
    return false;
1279
0
  }
1280
0
  auto &zone = m_state->m_zones[NisusWrtStruct::Z_HeaderFooter];
1281
0
  entry.setParsed(true);
1282
0
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1283
0
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1284
0
  long pos = entry.begin();
1285
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1286
1287
0
  auto numElt = int(entry.length()/32);
1288
0
  libmwaw::DebugStream f;
1289
0
  f << "Entries(HeaderFooter)[" << entry.id() << "]:N=" << numElt;
1290
0
  asciiFile.addPos(pos-4);
1291
0
  asciiFile.addNote(f.str().c_str());
1292
1293
0
  NisusWrtTextInternal::DataPLC plc;
1294
0
  plc.m_type = NisusWrtTextInternal::P_HeaderFooter;
1295
0
  long val;
1296
0
  long lastPara = 0;
1297
0
  for (int i = 0; i < numElt; i++) {
1298
0
    pos = input->tell();
1299
0
    f.str("");
1300
0
    NisusWrtTextInternal::HeaderFooter hf;
1301
0
    hf.m_textParagraph = input->readLong(4);
1302
0
    hf.m_paragraph[0] = lastPara;
1303
0
    hf.m_paragraph[1] = lastPara = input->readLong(4);
1304
0
    auto what = static_cast<int>(input->readULong(2));
1305
0
    switch ((what>>2)&0x3) {
1306
0
    case 1:
1307
0
      hf.m_type = MWAWHeaderFooter::HEADER;
1308
0
      break;
1309
0
    case 2:
1310
0
      hf.m_type = MWAWHeaderFooter::FOOTER;
1311
0
      break;
1312
0
    default:
1313
0
      f << "#what=" << ((what>>2)&0x3);
1314
0
      break;
1315
0
    }
1316
0
    switch (what&0x3) {
1317
0
    case 1:
1318
0
      hf.m_occurrence = MWAWHeaderFooter::ODD;
1319
0
      break;
1320
0
    case 2:
1321
0
      hf.m_occurrence = MWAWHeaderFooter::EVEN;
1322
0
      break;
1323
0
    case 3:
1324
0
      hf.m_occurrence = MWAWHeaderFooter::ALL;
1325
0
      break;
1326
0
    default:
1327
0
      f << "[#page],";
1328
0
      break;
1329
0
    }
1330
0
    if (what&0xFFF0) f << "#flags=" << std::hex << (what&0xFFF0) << ",";
1331
    // find 0|0x10|0x18|0x20|0x36|0x3a|0x40|0x4c|0x66 here
1332
0
    hf.m_unknown = static_cast<int>(input->readLong(2));
1333
0
    for (int j = 0; j < 10; j++) { // always 0 ?
1334
0
      val = long(input->readLong(2));
1335
0
      if (val) f << "g" << j << "=" << val << ",";
1336
0
    }
1337
0
    hf.m_extra = f.str();
1338
0
    f.str("");
1339
0
    f << "HeaderFooter" << i << ":" << hf;
1340
1341
0
    m_state->m_hfList.push_back(hf);
1342
0
    plc.m_id = i+1;
1343
0
    NisusWrtStruct::Position hfPosition;
1344
0
    hfPosition.m_paragraph=int(lastPara);
1345
0
    zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(hfPosition, plc));
1346
0
    asciiFile.addPos(pos);
1347
0
    asciiFile.addNote(f.str().c_str());
1348
0
    input->seek(pos+32, librevenge::RVNG_SEEK_SET);
1349
0
  }
1350
0
  return true;
1351
0
}
1352
1353
// read the footnote main entry
1354
bool NisusWrtText::readFootnotes(MWAWEntry const &entry)
1355
0
{
1356
0
  if (!entry.valid() || (entry.length()%36)) {
1357
0
    MWAW_DEBUG_MSG(("NisusWrtText::readFootnotes: the entry is bad\n"));
1358
0
    return false;
1359
0
  }
1360
0
  auto &mainZone = m_state->m_zones[NisusWrtStruct::Z_Main];
1361
0
  auto &zone = m_state->m_zones[NisusWrtStruct::Z_Footnote];
1362
0
  entry.setParsed(true);
1363
0
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1364
0
  libmwaw::DebugFile &asciiFile = m_mainParser->rsrcAscii();
1365
0
  long pos = entry.begin();
1366
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1367
1368
0
  auto numElt = int(entry.length()/36);
1369
0
  libmwaw::DebugStream f;
1370
0
  f << "Entries(Footnotes)[" << entry.id() << "]:N=" << numElt;
1371
0
  asciiFile.addPos(pos-4);
1372
0
  asciiFile.addNote(f.str().c_str());
1373
1374
0
  NisusWrtTextInternal::DataPLC plc;
1375
0
  plc.m_type = NisusWrtTextInternal::P_Footnote;
1376
0
  int lastParagraph = 0;
1377
0
  long val;
1378
0
  for (int i = 0; i < numElt; i++) {
1379
0
    pos = input->tell();
1380
0
    f.str("");
1381
0
    NisusWrtTextInternal::Footnote footnote;
1382
0
    footnote.m_textPosition.m_paragraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1383
0
    footnote.m_textPosition.m_word = static_cast<int>(input->readULong(2));
1384
0
    footnote.m_textPosition.m_char = static_cast<int>(input->readULong(2));
1385
0
    footnote.m_paragraph[0] = lastParagraph;
1386
0
    lastParagraph = static_cast<int>(input->readULong(4)); // checkme or ??? m_paragraph
1387
0
    footnote.m_paragraph[1] = lastParagraph;
1388
    // find f0=0|55|6f, f1=15|16|26|27|39|3a
1389
0
    for (int j = 0; j < 2; j++) {
1390
0
      val = input->readLong(2);
1391
0
      if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
1392
0
    }
1393
0
    footnote.m_number = static_cast<int>(input->readLong(2));
1394
0
    for (int j = 0; j < 3; j++) { // always 0 ?
1395
0
      val = input->readLong(2);
1396
0
      if (val) f << "g" << j << "=" << val << ",";
1397
0
    }
1398
0
    for (int wh = 0; wh < 2; wh++) {
1399
0
      input->seek(pos+24+wh*6, librevenge::RVNG_SEEK_SET);
1400
0
      std::string label("");
1401
0
      for (int c = 0; c < 6; c++) {
1402
0
        auto ch = char(input->readULong(1));
1403
0
        if (ch == 0)
1404
0
          break;
1405
0
        label += ch;
1406
0
      }
1407
0
      if (wh==0) footnote.m_noteLabel = label;
1408
0
      else footnote.m_textLabel = label;
1409
0
    }
1410
0
    footnote.m_extra = f.str();
1411
0
    f.str("");
1412
0
    f << "Footnotes" << i << ":" << footnote;
1413
1414
0
    m_state->m_footnoteList.push_back(footnote);
1415
0
    plc.m_id = i;
1416
0
    mainZone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(footnote.m_textPosition, plc));
1417
0
    NisusWrtStruct::Position notePosition;
1418
0
    notePosition.m_paragraph= footnote.m_paragraph[0];
1419
0
    zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(notePosition, plc));
1420
1421
0
    asciiFile.addPos(pos);
1422
0
    asciiFile.addNote(f.str().c_str());
1423
0
    input->seek(pos+36, librevenge::RVNG_SEEK_SET);
1424
0
  }
1425
0
  return true;
1426
0
}
1427
1428
// read the PICD zone ( a list of picture ? )
1429
bool NisusWrtText::readPICD(MWAWEntry const &entry, NisusWrtStruct::ZoneType zoneId)
1430
4.03k
{
1431
4.03k
  if ((!entry.valid()&&entry.length()) || (entry.length()%14)) {
1432
1.88k
    MWAW_DEBUG_MSG(("NisusWrtText::readPICD: the entry is bad\n"));
1433
1.88k
    return false;
1434
1.88k
  }
1435
2.15k
  if (zoneId >= 3) {
1436
0
    MWAW_DEBUG_MSG(("NisusWrtText::readPICD: find unexpected zoneId: %d\n", zoneId));
1437
0
    return false;
1438
0
  }
1439
2.15k
  auto &zone = m_state->m_zones[zoneId];
1440
2.15k
  entry.setParsed(true);
1441
2.15k
  MWAWInputStreamPtr input = m_mainParser->rsrcInput();
1442
2.15k
  libmwaw::DebugFile &ascFile = m_mainParser->rsrcAscii();
1443
2.15k
  long pos = entry.begin();
1444
2.15k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1445
1446
2.15k
  auto numElt = int(entry.length()/14);
1447
2.15k
  libmwaw::DebugStream f;
1448
2.15k
  f << "Entries(PICD)[" << zoneId << "]:N=" << numElt;
1449
2.15k
  ascFile.addPos(pos-4);
1450
2.15k
  ascFile.addNote(f.str().c_str());
1451
1452
2.15k
  NisusWrtTextInternal::DataPLC plc;
1453
2.15k
  plc.m_type = NisusWrtTextInternal::P_PicturePara;
1454
99.3k
  for (int i = 0; i < numElt; i++) {
1455
97.1k
    pos = input->tell();
1456
97.1k
    f.str("");
1457
97.1k
    NisusWrtTextInternal::PicturePara pict;
1458
97.1k
    pict.m_paragraph = static_cast<int>(input->readLong(4));
1459
97.1k
    int dim[4];
1460
97.1k
    for (int &j : dim)
1461
388k
      j = static_cast<int>(input->readLong(2));
1462
97.1k
    pict.m_position = MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1463
97.1k
    pict.m_id = static_cast<int>(input->readULong(2));
1464
97.1k
    zone.m_pictureParaList.push_back(pict);
1465
1466
97.1k
    NisusWrtStruct::Position pictPosition;
1467
97.1k
    pictPosition.m_paragraph= pict.m_paragraph;
1468
97.1k
    plc.m_id = i;
1469
97.1k
    zone.m_plcMap.insert(NisusWrtTextInternal::Zone::PLCMap::value_type(pictPosition, plc));
1470
1471
97.1k
    f << "PICD" << i << ":" << pict;
1472
97.1k
    ascFile.addPos(pos);
1473
97.1k
    ascFile.addNote(f.str().c_str());
1474
97.1k
    input->seek(pos+14, librevenge::RVNG_SEEK_SET);
1475
97.1k
  }
1476
2.15k
  return true;
1477
2.15k
}
1478
1479
////////////////////////////////////////////////////////////
1480
//
1481
// Low level
1482
//
1483
////////////////////////////////////////////////////////////
1484
1485
////////////////////////////////////////////////////////////
1486
long NisusWrtText::findFilePos(NisusWrtStruct::ZoneType zoneId, NisusWrtStruct::Position const &pos)
1487
0
{
1488
0
  if (zoneId >= 3) {
1489
0
    MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: find unexpected zoneId: %d\n", zoneId));
1490
0
    return -1;
1491
0
  }
1492
0
  auto &zone = m_state->m_zones[zoneId];
1493
0
  MWAWEntry entry = zone.m_entry;
1494
0
  if (!entry.valid()) {
1495
0
    MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: the entry is bad\n"));
1496
0
    return -1;
1497
0
  }
1498
1499
0
  bool isMain = zoneId == NisusWrtStruct::Z_Main;
1500
0
  MWAWInputStreamPtr input = isMain ?
1501
0
                             m_mainParser->getInput() : m_mainParser->rsrcInput();
1502
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1503
1504
0
  NisusWrtStruct::Position actPos;
1505
0
  for (long i = 0; i < entry.length(); i++) {
1506
0
    if (input->isEnd())
1507
0
      break;
1508
0
    if (pos == actPos)
1509
0
      return input->tell();
1510
0
    auto c = static_cast<unsigned char>(input->readULong(1));
1511
    // update the position
1512
0
    switch (c) {
1513
0
    case 0xd:
1514
0
      actPos.m_paragraph++;
1515
0
      actPos.m_word = actPos.m_char = 0;
1516
0
      break;
1517
0
    case '\t':
1518
0
    case ' ':
1519
0
      actPos.m_word++;
1520
0
      actPos.m_char = 0;
1521
0
      break;
1522
0
    default:
1523
0
      actPos.m_char++;
1524
0
      break;
1525
0
    }
1526
0
  }
1527
0
  if (pos == actPos)
1528
0
    return input->tell();
1529
0
  MWAW_DEBUG_MSG(("NisusWrtText::findFilePos: can not find the position\n"));
1530
0
  return -1;
1531
0
}
1532
1533
////////////////////////////////////////////////////////////
1534
bool NisusWrtText::sendHeaderFooter(int hfId)
1535
0
{
1536
0
  if (!m_parserState->m_textListener) {
1537
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not find the listener\n"));
1538
0
    return false;
1539
0
  }
1540
0
  if (hfId >= int(m_state->m_hfList.size())) {
1541
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not find the headerFooter list\n"));
1542
0
    return false;
1543
0
  }
1544
0
  if (hfId < 0)
1545
0
    return true;
1546
0
  auto const &hf = m_state->m_hfList[size_t(hfId)];
1547
0
  hf.m_parsed = true;
1548
1549
0
  MWAWEntry entry;
1550
0
  entry.setId(NisusWrtStruct::Z_HeaderFooter);
1551
0
  NisusWrtStruct::Position pos;
1552
0
  pos.m_paragraph = static_cast<int>(hf.m_paragraph[0]);
1553
0
  entry.setBegin(findFilePos(NisusWrtStruct::Z_HeaderFooter, pos));
1554
0
  pos.m_paragraph = static_cast<int>(hf.m_paragraph[1]);
1555
0
  entry.setEnd(findFilePos(NisusWrtStruct::Z_HeaderFooter, pos));
1556
0
  if (entry.begin() < 0 || entry.length() < 0) {
1557
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendHeaderFooter: can not compute the headerFooter entry\n"));
1558
0
    return false;
1559
0
  }
1560
0
  pos.m_paragraph = static_cast<int>(hf.m_paragraph[0]);
1561
0
  sendText(entry, pos);
1562
0
  return true;
1563
0
}
1564
1565
////////////////////////////////////////////////////////////
1566
bool NisusWrtText::sendFootnote(int footnoteId)
1567
0
{
1568
0
  if (!m_parserState->m_textListener) {
1569
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not find the listener\n"));
1570
0
    return false;
1571
0
  }
1572
0
  if (footnoteId >= int(m_state->m_footnoteList.size())) {
1573
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not find the footnote list\n"));
1574
0
    return false;
1575
0
  }
1576
0
  if (footnoteId < 0)
1577
0
    return true;
1578
0
  auto const &fnote = m_state->m_footnoteList[size_t(footnoteId)];
1579
0
  fnote.m_parsed = true;
1580
1581
0
  MWAWEntry entry;
1582
0
  entry.setId(NisusWrtStruct::Z_Footnote);
1583
0
  NisusWrtStruct::Position pos;
1584
0
  pos.m_paragraph = fnote.m_paragraph[0];
1585
0
  entry.setBegin(findFilePos(NisusWrtStruct::Z_Footnote, pos));
1586
0
  pos.m_paragraph = fnote.m_paragraph[1];
1587
0
  entry.setEnd(findFilePos(NisusWrtStruct::Z_Footnote, pos));
1588
0
  if (entry.begin() < 0 || entry.length() < 0) {
1589
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendFootnote: can not compute the footnote entry\n"));
1590
0
    return false;
1591
0
  }
1592
0
  pos.m_paragraph = fnote.m_paragraph[0];
1593
0
  sendText(entry, pos);
1594
0
  return true;
1595
0
}
1596
1597
////////////////////////////////////////////////////////////
1598
bool NisusWrtText::sendText(MWAWEntry const &entry, NisusWrtStruct::Position firstPos)
1599
3.98k
{
1600
3.98k
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
1601
3.98k
  if (!listener) {
1602
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the listener\n"));
1603
0
    return false;
1604
0
  }
1605
3.98k
  if (!entry.valid()) {
1606
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendText: the entry is bad\n"));
1607
0
    return false;
1608
0
  }
1609
1610
3.98k
  auto zoneId = static_cast<NisusWrtStruct::ZoneType>(entry.id());
1611
3.98k
  if (zoneId >= 3) {
1612
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendText: find unexpected zoneId: %d\n", zoneId));
1613
0
    return false;
1614
0
  }
1615
3.98k
  auto &zone = m_state->m_zones[zoneId];
1616
3.98k
  bool isMain = zoneId == NisusWrtStruct::Z_Main;
1617
3.98k
  auto width = int(72.0*m_mainParser->getPageWidth());
1618
3.98k
  if (isMain || zoneId == NisusWrtStruct::Z_Footnote) {
1619
3.98k
    float colSep = 0.5f;
1620
3.98k
    int nCol = 1;
1621
3.98k
    m_mainParser->getColumnInfo(nCol, colSep);
1622
3.98k
    if (nCol > 1)
1623
1
      width /= nCol;
1624
3.98k
    if (isMain && nCol > 1) {
1625
1
      if (listener->isSectionOpened())
1626
0
        listener->closeSection();
1627
1628
1
      MWAWSection sec;
1629
1
      sec.setColumns(nCol, double(width), librevenge::RVNG_POINT);
1630
1
      listener->openSection(sec);
1631
1
    }
1632
3.98k
  }
1633
3.98k
  MWAWInputStreamPtr input
1634
3.98k
    = isMain ? m_mainParser->getInput() : m_mainParser->rsrcInput();
1635
3.98k
  libmwaw::DebugFile &ascFile =
1636
3.98k
    isMain ? m_mainParser->ascii() : m_mainParser->rsrcAscii();
1637
3.98k
  long pos = entry.begin();
1638
3.98k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1639
1640
3.98k
  libmwaw::DebugStream f;
1641
3.98k
  f << "Entries(TEXT)[" << zoneId << "]:";
1642
3.98k
  std::string str("");
1643
3.98k
  NisusWrtStruct::Position actPos(firstPos);
1644
3.98k
  auto it = zone.m_plcMap.begin();
1645
17.0k
  while (it != zone.m_plcMap.end() && it->first.cmp(actPos) < 0)
1646
13.0k
    ++it;
1647
1648
3.98k
  NisusWrtTextInternal::Font actFont;
1649
3.98k
  actFont.m_font = MWAWFont(3,12);
1650
3.98k
  listener->setFont(actFont.m_font);
1651
3.98k
  NisusWrtStruct::FootnoteInfo ftInfo;
1652
3.98k
  m_mainParser->getFootnoteInfo(ftInfo);
1653
3.98k
  bool lastCharFootnote = false;
1654
3.98k
  int noteId = 0, numVar=0, actVar=-1;
1655
3.98k
  std::vector<int> varValues;
1656
3.98k
  std::map<int, int> fontIdToVarIdMap;
1657
2.80M
  for (long i = 0; i <= entry.length(); i++) {
1658
2.80M
    if (i==entry.length() && !lastCharFootnote)
1659
3.98k
      break;
1660
3.02M
    while (it != zone.m_plcMap.end() && it->first.cmp(actPos) <= 0) {
1661
223k
      auto const &plcPos = it->first;
1662
223k
      auto const &plc = it++->second;
1663
223k
      f << str;
1664
223k
      str="";
1665
223k
      if (plcPos.cmp(actPos) < 0) {
1666
13.2k
        MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops find unexpected position\n"));
1667
13.2k
        f << "###[" << plc << "]";
1668
13.2k
        continue;
1669
13.2k
      }
1670
210k
      f << "[" << plc << "]";
1671
210k
      switch (plc.m_type) {
1672
106k
      case NisusWrtTextInternal::P_Format: {
1673
106k
        if (plc.m_id < 0 || plc.m_id >= int(m_state->m_fontList.size())) {
1674
17.5k
          MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find the actual font\n"));
1675
17.5k
          f << "###";
1676
17.5k
          break;
1677
17.5k
        }
1678
89.3k
        auto const &font = m_state->m_fontList[size_t(plc.m_id)];
1679
89.3k
        actFont = font;
1680
89.3k
        if (font.m_pictureId <= 0)
1681
87.7k
          listener->setFont(font.m_font);
1682
89.3k
        if (!font.isVariable())
1683
86.4k
          break;
1684
2.94k
        if (fontIdToVarIdMap.find(plc.m_id) != fontIdToVarIdMap.end())
1685
1.33k
          actVar = fontIdToVarIdMap.find(plc.m_id)->second;
1686
1.61k
        else {
1687
1.61k
          actVar = numVar++;
1688
1.61k
          fontIdToVarIdMap[plc.m_id]=actVar;
1689
1.61k
        }
1690
2.94k
        break;
1691
89.3k
      }
1692
26.5k
      case NisusWrtTextInternal::P_Ruler: {
1693
26.5k
        if (plc.m_id < 0 || plc.m_id >= int(zone.m_paragraphList.size())) {
1694
0
          MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find the actual ruler\n"));
1695
0
          f << "###";
1696
0
          break;
1697
0
        }
1698
26.5k
        auto const &para = zone.m_paragraphList[size_t(plc.m_id)];
1699
26.5k
        setProperty(para, width);
1700
26.5k
        break;
1701
26.5k
      }
1702
0
      case NisusWrtTextInternal::P_Footnote: {
1703
0
        if (!isMain) break;
1704
0
        if (!lastCharFootnote) {
1705
0
          MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops do not find the footnote symbol\n"));
1706
0
          break;
1707
0
        }
1708
0
        if (plc.m_id < 0 || plc.m_id >= int(m_state->m_footnoteList.size())) {
1709
0
          MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the footnote\n"));
1710
0
          MWAWSubDocumentPtr subdoc(new NisusWrtTextInternal::SubDocument(*this, input, -1, libmwaw::DOC_NOTE));
1711
0
          listener->insertNote(MWAWNote(MWAWNote::FootNote), subdoc);
1712
0
          break;
1713
0
        }
1714
0
        MWAWSubDocumentPtr subdoc(new NisusWrtTextInternal::SubDocument(*this, input, plc.m_id, libmwaw::DOC_NOTE));
1715
0
        auto const &fnote = m_state->m_footnoteList[size_t(plc.m_id)];
1716
0
        noteId++;
1717
0
        if (fnote.m_number && noteId != fnote.m_number)
1718
0
          noteId = fnote.m_number;
1719
0
        MWAWNote note(ftInfo.endNotes() ? MWAWNote::EndNote : MWAWNote::FootNote);
1720
0
        note.m_number=noteId;
1721
0
        note.m_label=fnote.getTextLabel(noteId).c_str();
1722
0
        listener->insertNote(note, subdoc);
1723
0
        break;
1724
0
      }
1725
76.8k
      case NisusWrtTextInternal::P_PicturePara: {
1726
76.8k
        if (plc.m_id < 0 || plc.m_id >= int(zone.m_pictureParaList.size())) {
1727
0
          MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find the paragraph picture\n"));
1728
0
          break;
1729
0
        }
1730
76.8k
        auto &pict = zone.m_pictureParaList[size_t(plc.m_id)];
1731
76.8k
        MWAWPosition pictPos(MWAWVec2f(pict.m_position.min()), MWAWVec2f(pict.m_position.size()), librevenge::RVNG_POINT);
1732
76.8k
        pictPos.setRelativePosition(MWAWPosition::Paragraph);
1733
76.8k
        pictPos.m_wrapping = MWAWPosition::WBackground;
1734
76.8k
        m_mainParser->sendPicture(pict.m_id, pictPos);
1735
76.8k
        break;
1736
76.8k
      }
1737
0
      case NisusWrtTextInternal::P_HeaderFooter:
1738
0
        break;
1739
0
      case NisusWrtTextInternal::P_Unknown:
1740
#if !defined(__clang__)
1741
      default:
1742
#endif
1743
0
        MWAW_DEBUG_MSG(("NisusWrtText::sendText: oops can not find unknown plc type\n"));
1744
0
        f << "###";
1745
0
        break;
1746
210k
      }
1747
210k
    }
1748
1749
2.80M
    if (input->isEnd())
1750
0
      break;
1751
2.80M
    if (i==entry.length())
1752
0
      break;
1753
2.80M
    auto c = static_cast<unsigned char>(input->readULong(1));
1754
2.80M
    str+=char(c);
1755
2.80M
    if (c==0xd) {
1756
112k
      f << str;
1757
112k
      ascFile.addPos(pos);
1758
112k
      ascFile.addNote(f.str().c_str());
1759
1760
112k
      str = "";
1761
112k
      pos = input->tell();
1762
112k
      f.str("");
1763
112k
      f << "TEXT" << zoneId << ":";
1764
112k
    }
1765
1766
    // update the position
1767
2.80M
    switch (c) {
1768
112k
    case 0xd:
1769
112k
      actPos.m_paragraph++;
1770
112k
      actPos.m_word = actPos.m_char = 0;
1771
112k
      break;
1772
55.2k
    case '\t':
1773
411k
    case ' ':
1774
411k
      actPos.m_word++;
1775
411k
      actPos.m_char = 0;
1776
411k
      break;
1777
2.27M
    default:
1778
2.27M
      actPos.m_char++;
1779
2.27M
      break;
1780
2.80M
    }
1781
1782
    // send char
1783
2.80M
    lastCharFootnote = false;
1784
2.80M
    switch (c) {
1785
4.37k
    case 0x1: {
1786
4.37k
      if (actFont.m_pictureId <= 0) {
1787
3.37k
        MWAW_DEBUG_MSG(("NisusWrtText::sendText: can not find pictureId for char 1\n"));
1788
3.37k
        f << "#";
1789
3.37k
        break;
1790
3.37k
      }
1791
993
      MWAWPosition pictPos(MWAWVec2f(actFont.m_pictureDim[0].min()), MWAWVec2f(actFont.m_pictureDim[0].size()), librevenge::RVNG_POINT);
1792
993
      pictPos.setRelativePosition(MWAWPosition::CharBaseLine);
1793
993
      pictPos.setClippingPosition
1794
993
      (MWAWVec2f(actFont.m_pictureDim[1].min()-actFont.m_pictureDim[0].min()),
1795
993
       MWAWVec2f(actFont.m_pictureDim[0].max()-actFont.m_pictureDim[1].max()));
1796
993
      m_mainParser->sendPicture(actFont.m_pictureId, pictPos);
1797
993
      break;
1798
4.37k
    }
1799
161
    case 0x3: // checkme: find in some file ( but seems to do nothing )
1800
161
      break;
1801
55.2k
    case 0x9:
1802
55.2k
      listener->insertTab();
1803
55.2k
      break;
1804
73
    case 0xb:
1805
73
      listener->insertEOL(true);
1806
73
      break;
1807
727
    case 0xc:
1808
727
      if (!isMain) break;
1809
727
      m_mainParser->newPage(++m_state->m_actualPage);
1810
727
      if (ftInfo.resetNumberOnNewPage()) noteId = 0;
1811
727
      break;
1812
112k
    case 0xd:
1813
112k
      listener->insertEOL();
1814
112k
      break;
1815
284
    case 0xf: {
1816
284
      std::string format(m_mainParser->getDateFormat(zoneId, actVar));
1817
284
      MWAWField field(MWAWField::Date);
1818
284
      if (format.length())
1819
225
        field.m_DTFormat = format;
1820
59
      else
1821
59
        f << "#";
1822
284
      listener->insertField(field);
1823
284
      break;
1824
727
    }
1825
767
    case 0x10: {
1826
767
      MWAWField field(MWAWField::Time);
1827
767
      field.m_DTFormat = "%H:%M";
1828
767
      listener->insertField(field);
1829
767
      break;
1830
727
    }
1831
235
    case 0x11:
1832
235
      listener->insertField(MWAWField(MWAWField::Title));
1833
235
      break;
1834
4.14k
    case 0x14: // mark separator ( ok to ignore )
1835
4.14k
      break;
1836
181
    case 0x1c:
1837
181
      if (isMain)
1838
181
        lastCharFootnote = true;
1839
181
      break;
1840
860
    case 0x1d: {
1841
860
      MWAWField::Type fType;
1842
860
      std::string content;
1843
860
      if (!m_mainParser->getReferenceData(zoneId, actVar, fType, content, varValues)) {
1844
860
        listener->insertChar(' ');
1845
860
        f << "#[ref]";
1846
860
        break;
1847
860
      }
1848
0
      if (fType != MWAWField::None)
1849
0
        listener->insertField(MWAWField(fType));
1850
0
      else if (content.length())
1851
0
        listener->insertUnicodeString(librevenge::RVNGString(content.c_str()));
1852
0
      else
1853
0
        f << "#[ref]";
1854
0
      break;
1855
860
    }
1856
    // checkme: find also 0x8, 0x13, 0x15, 0x1e, 0x1f in glossary
1857
2.62M
    default:
1858
2.62M
      i+=listener->insertCharacter(static_cast<unsigned char>(c), input, entry.end());
1859
2.62M
      break;
1860
2.80M
    }
1861
2.80M
  }
1862
3.98k
  f << str;
1863
3.98k
  ascFile.addPos(pos);
1864
3.98k
  ascFile.addNote(f.str().c_str());
1865
3.98k
  return true;
1866
3.98k
}
1867
1868
//! send data to the listener
1869
bool NisusWrtText::sendMainText()
1870
3.98k
{
1871
3.98k
  if (!m_parserState->m_textListener) return true;
1872
1873
3.98k
  if (!m_state->m_zones[0].m_entry.valid()) {
1874
0
    MWAW_DEBUG_MSG(("NisusWrtText::sendMainText: can not find the main text\n"));
1875
0
    return false;
1876
0
  }
1877
3.98k
  m_state->m_zones[0].m_entry.setParsed(true);
1878
3.98k
  sendText(m_state->m_zones[0].m_entry);
1879
3.98k
  return true;
1880
3.98k
}
1881
1882
1883
void NisusWrtText::flushExtra()
1884
0
{
1885
0
  if (!m_parserState->m_textListener) return;
1886
0
  for (size_t f = 0; f < m_state->m_footnoteList.size(); f++) {
1887
0
    if (m_state->m_footnoteList[f].m_parsed)
1888
0
      continue;
1889
0
    sendFootnote(int(f));
1890
0
  }
1891
0
  m_parserState->m_textListener->insertChar(' ');
1892
0
  for (size_t hf = 0; hf < m_state->m_hfList.size(); hf++) {
1893
0
    if (m_state->m_hfList[hf].m_parsed)
1894
0
      continue;
1895
0
    sendHeaderFooter(int(hf));
1896
0
  }
1897
0
}
1898
1899
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: