Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MoreText.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 <cstring>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <map>
39
#include <sstream>
40
41
#include <librevenge/librevenge.h>
42
43
#include "MWAWTextListener.hxx"
44
#include "MWAWDebug.hxx"
45
#include "MWAWFont.hxx"
46
#include "MWAWFontConverter.hxx"
47
#include "MWAWList.hxx"
48
#include "MWAWPageSpan.hxx"
49
#include "MWAWParagraph.hxx"
50
#include "MWAWPictData.hxx"
51
#include "MWAWPosition.hxx"
52
#include "MWAWRSRCParser.hxx"
53
#include "MWAWSubDocument.hxx"
54
55
#include "MoreParser.hxx"
56
57
#include "MoreText.hxx"
58
59
/** Internal: the structures of a MoreText */
60
namespace MoreTextInternal
61
{
62
////////////////////////////////////////
63
//! Internal: the paragraph of a MoreText
64
struct Paragraph final : public MWAWParagraph {
65
  //! constructor
66
  Paragraph()
67
102M
    : MWAWParagraph()
68
102M
    , m_listType(0)
69
102M
    , m_customListLevel()
70
102M
    , m_pageBreak(false)
71
102M
    , m_keepOutlineTogether(false)
72
102M
  {
73
102M
    m_marginsFromParent[0]=0.3;
74
102M
    m_marginsFromParent[1]=0;
75
102M
  }
76
11.0M
  Paragraph(Paragraph const &)=default;
77
5.63k
  Paragraph &operator=(Paragraph const &)=default;
78
  //! destructor
79
  ~Paragraph() final;
80
  //! set the left margin in inch
81
  void setLeftMargin(double margin, bool fromParent)
82
30.5k
  {
83
30.5k
    if (fromParent) {
84
27.9k
      m_marginsFromParent[0]=margin;
85
27.9k
      m_margins[1]=0;
86
27.9k
    }
87
2.66k
    else {
88
2.66k
      m_marginsFromParent[0]=-100;
89
2.66k
      m_margins[1]=margin;
90
2.66k
    }
91
30.5k
  }
92
  //! set the right margin in inch
93
  void setRightMargin(double margin, bool fromParent)
94
62.6k
  {
95
62.6k
    if (fromParent) {
96
59.6k
      m_marginsFromParent[1]=margin;
97
59.6k
      m_margins[2]=0;
98
59.6k
    }
99
3.05k
    else {
100
3.05k
      m_marginsFromParent[1]=-100;
101
3.05k
      m_margins[2]=margin;
102
3.05k
    }
103
62.6k
  }
104
  //! update the paragraph to obtain the final paragraph
105
  void updateToFinalState(MWAWParagraph const &parent, int level, MWAWListManager &listManager)
106
101k
  {
107
101k
    bool leftUseParent=m_marginsFromParent[0]>-10;
108
101k
    if (leftUseParent)
109
101k
      m_margins[1]=*parent.m_margins[1]+m_marginsFromParent[0];
110
101k
    if (m_marginsFromParent[1]>-10)
111
101k
      m_margins[2]=*parent.m_margins[2]+m_marginsFromParent[1];
112
101k
    if (level<0)
113
0
      return;
114
115
101k
    MWAWListLevel listLevel;
116
101k
    switch (m_listType) {
117
100k
    case 1: // leader
118
100k
      listLevel.m_type = MWAWListLevel::BULLET;
119
100k
      listLevel.m_bullet = "+"; // in fact + + and -
120
100k
      break;
121
0
    case 2: // hardvard
122
0
      listLevel.m_suffix = (level <= 3) ? "." : ")";
123
0
      if (level == 1) listLevel.m_type = MWAWListLevel::UPPER_ROMAN;
124
0
      else if (level == 2) listLevel.m_type = MWAWListLevel::UPPER_ALPHA;
125
0
      else if (level == 3) listLevel.m_type = MWAWListLevel::DECIMAL;
126
0
      else if (level == 4) listLevel.m_type =  MWAWListLevel::LOWER_ALPHA;
127
0
      else if ((level%3)==2) {
128
0
        listLevel.m_prefix = "(";
129
0
        listLevel.m_type = MWAWListLevel::DECIMAL;
130
0
      }
131
0
      else if ((level%3)==0) {
132
0
        listLevel.m_prefix = "(";
133
0
        listLevel.m_type = MWAWListLevel::LOWER_ALPHA;
134
0
      }
135
0
      else
136
0
        listLevel.m_type = MWAWListLevel::LOWER_ROMAN;
137
0
      break;
138
0
    case 3: // numeric
139
0
      listLevel.m_type = MWAWListLevel::DECIMAL;
140
0
      listLevel.m_suffix = ".";
141
0
      break;
142
0
    case 4: // legal
143
0
      listLevel.m_type = MWAWListLevel::DECIMAL;
144
0
      listLevel.m_numBeforeLabels = level-1;
145
0
      listLevel.m_suffix = ".";
146
0
      listLevel.m_labelWidth = 0.2*level;
147
0
      break;
148
0
    case 5: // bullets
149
0
      listLevel.m_type = MWAWListLevel::BULLET;
150
0
      libmwaw::appendUnicode(0x2022, listLevel.m_bullet);
151
0
      break;
152
380
    case 0: // none
153
380
      return;
154
0
    default:
155
0
      if (m_listType<11)
156
0
        return;
157
158
0
      listLevel=m_customListLevel;
159
0
      break;
160
101k
    }
161
162
100k
    m_listLevelIndex = level+1;
163
100k
    std::shared_ptr<MWAWList> parentList;
164
100k
    if (*parent.m_listId>=0)
165
9.55k
      parentList=listManager.getList(*parent.m_listId);
166
100k
    auto list=listManager.getNewList(parentList, level+1, listLevel);
167
100k
    if (list)
168
100k
      m_listId=list->getId();
169
0
    else
170
0
      m_listLevel=listLevel;
171
172
100k
    m_margins[1]=m_margins[1].get()-listLevel.m_labelWidth;
173
100k
  }
174
  //! the left and right margins from parent in inches
175
  double m_marginsFromParent[2];
176
  //! the list type (0: none, 1: leader, ...)
177
  int m_listType;
178
  //! a custom list level ( only defined if m_listType>=0xb)
179
  MWAWListLevel m_customListLevel;
180
  //! true if we need to add a page break before
181
  bool m_pageBreak;
182
  //! true if we need to keep outline together
183
  bool m_keepOutlineTogether;
184
};
185
186
Paragraph::~Paragraph()
187
113M
{
188
113M
}
189
190
////////////////////////////////////////
191
//! Internal: the outline data of a MoreText
192
struct Outline {
193
  //! constructor
194
  Outline()
195
1.27M
  {
196
    // set to default value
197
5.08M
    for (auto &font : m_fonts) font=MWAWFont(3,12);
198
1.27M
    m_paragraphs[0].m_listType=1;
199
1.27M
  }
200
  //! the paragraphs : organizer, slide, tree, unknowns
201
  Paragraph m_paragraphs[4];
202
  //! the fonts : organizer, slide, tree unknowns
203
  MWAWFont m_fonts[4];
204
};
205
206
////////////////////////////////////////
207
//! Internal and low level: the outline modifier header of a MoreText
208
struct OutlineMod {
209
  //! constructor
210
  OutlineMod()
211
3.62G
    : m_type(-1)
212
3.62G
    , m_flags(0)
213
3.62G
    , m_entry()
214
3.62G
    , m_extra("")
215
3.62G
  {
216
7.25G
    for (auto &unkn : m_unknowns) unkn=0;
217
3.62G
  }
218
  //! returns the data id to change in Outline
219
  int getModId() const
220
3.72G
  {
221
3.72G
    if (m_unknowns[0] || (m_flags&0xF)!= 1)
222
3.72G
      return 3;
223
4.25M
    switch (m_flags>>4) {
224
160k
    case 1:
225
160k
      return 0;
226
304k
    case 2:
227
304k
      return 1;
228
39.1k
    case 4:
229
39.1k
      return 2;
230
3.75M
    default:
231
3.75M
      break;
232
4.25M
    }
233
3.75M
    return 3;
234
4.25M
  }
235
  //! operator<<
236
  friend std::ostream &operator<<(std::ostream &o, OutlineMod const &head)
237
0
  {
238
0
    switch (head.m_flags>>4) {
239
0
    case 1: // organizer
240
0
      break;
241
0
    case 2:
242
0
      o << "slide,";
243
0
      break;
244
0
    case 4:
245
0
      o << "tree,";
246
0
      break;
247
0
    default:
248
0
      o << "##wh=" << std::hex << (head.m_flags>>4) << std::dec << ",";
249
0
      break;
250
0
    }
251
0
    switch (head.m_type) {
252
0
    case 0x301:
253
0
      o << "font,";
254
0
      break;
255
0
    case 0x402:
256
0
      o << "fSize,";
257
0
      break;
258
0
    case 0x603:
259
0
      o << "fFlags,";
260
0
      break;
261
0
    case 0x804:
262
0
      o << "fColor,";
263
0
      break;
264
0
    case 0xa05:
265
0
      o << "interline,";
266
0
      break;
267
0
    case 0xc0f:
268
0
      o << "firstIndent,";
269
0
      break;
270
0
    case 0xf07:
271
0
      o << "tabs,";
272
0
      break;
273
0
    case 0x1006:
274
0
      o << "justify,";
275
0
      break;
276
0
    case 0x1208:
277
0
      o << "bef/afterspace,";
278
0
      break;
279
0
    case 0x1409:
280
0
      o << "lMargin,";
281
0
      break;
282
0
    case 0x160a:
283
0
      o << "rMargin,";
284
0
      break;
285
0
    case 0x190b:
286
0
      o << "list[type],";
287
0
      break;
288
0
    case 0x1a0c:
289
0
      o << "break,";
290
0
      break;
291
0
    case 0x1c0d:
292
0
      o << "keepline,";
293
0
      break;
294
0
    case 0x1e0e:
295
0
      o << "keep[outline],";
296
0
      break;
297
0
    case -1:
298
0
      break;
299
0
    default:
300
0
      // 2914|2b15|3319|3b1c|6532|6934|7137|773a|7b3c -> backside|backpattern
301
0
      o << "type=" << std::hex << head.m_type << std::dec << ",";
302
0
      break;
303
0
    }
304
0
    for (int i=0; i<2; i++) { // unkn0=0|1|2(related to clone?), unkn1=0|1|999
305
0
      if (head.m_unknowns[i])
306
0
        o << "unkn" << i << "=" << head.m_unknowns[i] << ",";
307
0
    }
308
0
    if (head.m_flags&0xF)
309
0
      o << "fl=" << std::hex << (head.m_flags&0xF) << std::dec << ",";
310
0
    if (head.m_entry.valid())
311
0
      o << std::hex << head.m_entry.begin() << "<->" << head.m_entry.end() << std::dec << ",";
312
0
    o << head.m_extra;
313
0
    return o;
314
0
  }
315
  //! the type
316
  int m_type;
317
  //! the flag
318
  int m_flags;
319
  //! the data entry
320
  MWAWEntry m_entry;
321
  //! some unknown flags
322
  int m_unknowns[2];
323
  //! extra data
324
  std::string m_extra;
325
};
326
327
////////////////////////////////////////
328
//! Internal: the comment data of a MoreText
329
struct Comment {
330
  //! constructor
331
  Comment()
332
1.15M
    : m_entry()
333
1.15M
    , m_extra("")
334
1.15M
  {
335
1.15M
  }
336
  //! operator<<
337
  friend std::ostream &operator<<(std::ostream &o, Comment const &comment)
338
0
  {
339
0
    o << comment.m_extra;
340
0
    return o;
341
0
  }
342
  //! the text entry
343
  MWAWEntry m_entry;
344
  //! extra data
345
  std::string m_extra;
346
};
347
348
////////////////////////////////////////
349
//! Internal: the topic data of a MoreText
350
struct Topic {
351
  //! an enum used to define the different type of data attached to a topic
352
  enum AttachementType { AOutline=0, AComment, ASpeakerNote };
353
  //! constructor
354
  Topic()
355
2.14M
    : m_entry()
356
2.14M
    , m_level(0)
357
2.14M
    , m_isCloned(false)
358
2.14M
    , m_cloneId(-1)
359
2.14M
    , m_numPageBreak(-1)
360
2.14M
    , m_isStartSlide(false)
361
2.14M
    , m_extra("")
362
2.14M
  {
363
6.43M
    for (auto &hasData : m_hasList) hasData=false;
364
6.43M
    for (auto &attachData : m_attachList) attachData=-1;
365
2.14M
  }
366
  //! operator<<
367
  friend std::ostream &operator<<(std::ostream &o, Topic const &topic)
368
0
  {
369
0
    if (topic.m_level>0)
370
0
      o << "level=" << topic.m_level << ",";
371
0
    if (topic.m_hasList[AOutline])
372
0
      o << "outline,";
373
0
    if (topic.m_hasList[AComment])
374
0
      o << "comment,";
375
0
    if (topic.m_hasList[ASpeakerNote])
376
0
      o << "speakerNote,";
377
0
    if (topic.m_isCloned)
378
0
      o << "cloned,";
379
0
    if (topic.m_cloneId >= 0)
380
0
      o << "cloneId=" << topic.m_cloneId << ",";
381
0
    if (topic.m_isStartSlide)
382
0
      o << "newSlide,";
383
0
    o << topic.m_extra;
384
0
    return o;
385
0
  }
386
  //! the text entry
387
  MWAWEntry m_entry;
388
  //! the topic level
389
  int m_level;
390
  //! true if the entry is cloned
391
  bool m_isCloned;
392
  //! if not 0, indicate that we must cloned the cloneId^th clone
393
  int m_cloneId;
394
  //! a list of boolean use to note if a topic is associated with a Outline, ...
395
  bool m_hasList[3];
396
  //! a list of id to retrieve the attachment
397
  int m_attachList[3];
398
  //! the number of pages in the sub list
399
  int m_numPageBreak;
400
  //! true if we start a new slide
401
  bool m_isStartSlide;
402
  //! extra data
403
  std::string m_extra;
404
};
405
406
////////////////////////////////////////
407
//! Internal: the state of a MoreText
408
struct State {
409
  //! constructor
410
  State()
411
73.3k
    : m_version(-1)
412
73.3k
    , m_topicList()
413
73.3k
    , m_commentList()
414
73.3k
    , m_speakerList()
415
73.3k
    , m_outlineList()
416
73.3k
    , m_actualComment(0)
417
73.3k
    , m_actualSpeaker(0)
418
73.3k
    , m_actualOutline(0)
419
73.3k
    , m_numPages(-1)
420
73.3k
    , m_actualPage(1)
421
73.3k
  {
422
73.3k
  }
423
  //! the file version
424
  mutable int m_version;
425
  //! the topic list
426
  std::vector<Topic> m_topicList;
427
  //! the header/footer/comment list
428
  std::vector<Comment> m_commentList;
429
  //! the speaker note list
430
  std::vector<MWAWEntry> m_speakerList;
431
  //! the outline list
432
  std::vector<Outline> m_outlineList;
433
  //! the actual comment
434
  int m_actualComment;
435
  //! the actual speaker note
436
  int m_actualSpeaker;
437
  //! the actual outline
438
  int m_actualOutline;
439
  int m_numPages /* the number of pages */, m_actualPage /* the actual page */;
440
};
441
442
////////////////////////////////////////
443
//! Internal: the subdocument of a MoreText
444
class SubDocument final : public MWAWSubDocument
445
{
446
public:
447
  SubDocument(MoreText &pars, MWAWInputStreamPtr const &input, int zId, int what)
448
1.94k
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
449
1.94k
    , m_textParser(&pars)
450
1.94k
    , m_id(zId)
451
1.94k
    , m_what(what)
452
1.94k
  {
453
1.94k
  }
454
455
  //! destructor
456
0
  ~SubDocument() final {}
457
458
  //! operator!=
459
  bool operator!=(MWAWSubDocument const &doc) const final;
460
461
  //! the parser function
462
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
463
464
protected:
465
  /** the text parser */
466
  MoreText *m_textParser;
467
  //! the subdocument id
468
  int m_id;
469
  //! a int to know what to send 0: header/footer, 1: comment, 2:note
470
  int m_what;
471
private:
472
  SubDocument(SubDocument const &orig) = delete;
473
  SubDocument &operator=(SubDocument const &orig) = delete;
474
};
475
476
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
477
1.94k
{
478
1.94k
  if (!listener.get()) {
479
0
    MWAW_DEBUG_MSG(("MoreTextInternal::SubDocument::parse: no listener\n"));
480
0
    return;
481
0
  }
482
1.94k
  if (!m_textParser) {
483
0
    MWAW_DEBUG_MSG(("MoreTextInternal::SubDocument::parse: no parser\n"));
484
0
    return;
485
0
  }
486
487
1.94k
  long pos = m_input->tell();
488
1.94k
  switch (m_what) {
489
380
  case 0: {
490
380
    std::vector<MWAWParagraph> paraStack;
491
380
    m_textParser->sendTopic(m_id,0,paraStack);
492
380
    break;
493
0
  }
494
336
  case 1:
495
336
    m_textParser->sendComment(m_id);
496
336
    break;
497
1.23k
  case 2:
498
1.23k
    m_textParser->sendSpeakerNote(m_id);
499
1.23k
    break;
500
0
  default:
501
0
    MWAW_DEBUG_MSG(("SubDocument::parse: unknow value in m_what\n"));
502
0
    break;
503
1.94k
  }
504
1.94k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
505
1.94k
}
506
507
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
508
0
{
509
0
  if (MWAWSubDocument::operator!=(doc)) return true;
510
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
511
0
  if (!sDoc) return true;
512
0
  if (m_textParser != sDoc->m_textParser) return true;
513
0
  if (m_id != sDoc->m_id) return true;
514
0
  return m_what != sDoc->m_what;
515
0
}
516
}
517
518
////////////////////////////////////////////////////////////
519
// constructor/destructor, ...
520
////////////////////////////////////////////////////////////
521
MoreText::MoreText(MoreParser &parser)
522
73.3k
  : m_parserState(parser.getParserState())
523
73.3k
  , m_state(new MoreTextInternal::State)
524
73.3k
  , m_mainParser(&parser)
525
73.3k
{
526
73.3k
}
527
528
MoreText::~MoreText()
529
73.3k
{
530
73.3k
}
531
532
int MoreText::version() const
533
1.07M
{
534
1.07M
  if (m_state->m_version < 0)
535
17.9k
    m_state->m_version = m_parserState->m_version;
536
1.07M
  return m_state->m_version;
537
1.07M
}
538
539
int MoreText::numPages() const
540
24.2k
{
541
24.2k
  if (m_state->m_numPages >= 0)
542
24.2k
    return m_state->m_numPages;
543
544
0
  MWAW_DEBUG_MSG(("MoreText::createZones is not called\n"));
545
0
  const_cast<MoreText *>(this)->createZones();
546
0
  return m_state->m_numPages;
547
24.2k
}
548
549
std::shared_ptr<MWAWSubDocument> MoreText::getHeaderFooter(bool header)
550
48.5k
{
551
48.5k
  std::shared_ptr<MWAWSubDocument> res;
552
48.5k
  size_t id=header ? 1 : 2;
553
48.5k
  if (id >= m_state->m_topicList.size())
554
577
    return res;
555
47.9k
  auto const &topic= m_state->m_topicList[id];
556
  // check if the content is empty
557
47.9k
  int comment=topic.m_attachList[MoreTextInternal::Topic::AComment];
558
47.9k
  if (comment < 0 || comment >= int(m_state->m_commentList.size()))
559
47.5k
    return res;
560
380
  if (m_state->m_commentList[size_t(comment)].m_entry.length()<=4)
561
0
    return res;
562
380
  res.reset(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, int(id), 0));
563
380
  return res;
564
380
}
565
566
////////////////////////////////////////////////////////////
567
// Intermediate level
568
////////////////////////////////////////////////////////////
569
570
//
571
// find/send the different zones
572
//
573
bool MoreText::createZones()
574
24.2k
{
575
24.2k
  if (m_state->m_topicList.empty())
576
0
    return false;
577
578
  // first create the list of cloned topic
579
24.2k
  std::vector<int> clonedList;
580
2.16M
  for (size_t i=0; i < m_state->m_topicList.size(); i++) {
581
2.14M
    auto const &topic=m_state->m_topicList[i];
582
2.14M
    if (topic.m_isCloned)
583
530k
      clonedList.push_back(int(i));
584
2.14M
  }
585
  // now associated each topic with its outline, its comment, its original topic (if clone)
586
24.2k
  auto numCloned=int(clonedList.size());
587
24.2k
  size_t actAttach[3]= {0,0,0};
588
24.2k
  size_t numAttach[3]= {0,0,0};
589
24.2k
  numAttach[MoreTextInternal::Topic::AOutline]=m_state->m_outlineList.size();
590
24.2k
  numAttach[MoreTextInternal::Topic::AComment]=m_state->m_commentList.size();
591
24.2k
  numAttach[MoreTextInternal::Topic::ASpeakerNote]=m_state->m_speakerList.size();
592
24.2k
  int n=0;
593
2.14M
  for (auto &topic : m_state->m_topicList) {
594
2.14M
    ++n;
595
8.57M
    for (int j=0; j < 3; j++) {
596
6.43M
      if (!topic.m_hasList[j])
597
5.22M
        continue;
598
1.20M
      if (actAttach[j] >= numAttach[j]) {
599
714k
        MWAW_DEBUG_MSG(("MoreText::createZones: can not find attach-%d for topic %d\n", j, n-1));
600
714k
        continue;
601
714k
      }
602
493k
      topic.m_attachList[j]=int(actAttach[j]++);
603
493k
      switch (j) {
604
195k
      case MoreTextInternal::Topic::AOutline:
605
195k
        break;
606
138k
      case MoreTextInternal::Topic::AComment: // no need to add empty comment
607
138k
        if (m_state->m_commentList[size_t(topic.m_attachList[j])].m_entry.length() <= 4)
608
130k
          topic.m_attachList[j]=-1;
609
138k
        break;
610
160k
      case MoreTextInternal::Topic::ASpeakerNote: // no need to add empty speaker note
611
160k
        if (m_state->m_speakerList[size_t(topic.m_attachList[j])].length() <= 4)
612
150k
          topic.m_attachList[j]=-1;
613
160k
        break;
614
0
      default:
615
0
        break;
616
493k
      }
617
493k
    }
618
2.14M
    int cloneId=topic.m_cloneId;
619
2.14M
    if (cloneId < 0)
620
1.81M
      continue;
621
331k
    if (cloneId==0 || cloneId > numCloned) {
622
316k
      MWAW_DEBUG_MSG(("MoreText::createZones: can not find original for topic %d\n", n-1));
623
316k
      topic.m_cloneId=-1;
624
316k
    }
625
15.0k
    else
626
15.0k
      topic.m_cloneId=clonedList[size_t(cloneId-1)];
627
331k
  }
628
629
  // now check that we have no loop
630
2.16M
  for (size_t i=0; i < m_state->m_topicList.size(); i++) {
631
2.14M
    auto const &topic=m_state->m_topicList[i];
632
2.14M
    if (topic.m_cloneId<0)
633
2.12M
      continue;
634
15.0k
    std::set<size_t> parent;
635
15.0k
    checkTopicList(i, parent);
636
15.0k
  }
637
  // now compute the number of page
638
24.2k
  int nPages = 1;
639
2.14M
  for (auto const &topic : m_state->m_topicList) {
640
2.14M
    if (topic.m_numPageBreak >= 0) {
641
14.7k
      nPages+=topic.m_numPageBreak;
642
14.7k
    }
643
2.14M
    int outId=topic.m_attachList[MoreTextInternal::Topic::AOutline];
644
2.14M
    if (outId<0) continue;
645
195k
    if (m_state->m_outlineList[size_t(outId)].m_paragraphs[0].m_pageBreak)
646
0
      nPages++;
647
195k
  }
648
24.2k
  m_state->m_actualPage = 1;
649
24.2k
  m_state->m_numPages = nPages;
650
24.2k
  return true;
651
24.2k
}
652
653
int MoreText::getLastTopicChildId(int tId) const
654
29.2k
{
655
29.2k
  size_t numTopic=m_state->m_topicList.size();
656
29.2k
  if (tId < 0||tId>= int(numTopic)) {
657
0
    MWAW_DEBUG_MSG(("MoreText::getLastTopicChildId: can not find topic %d\n", tId));
658
0
    return tId;
659
0
  }
660
29.2k
  auto p=size_t(tId);
661
29.2k
  int level=m_state->m_topicList[p].m_level;
662
29.2k
  while (p+1<numTopic && m_state->m_topicList[p].m_level>level)
663
0
    p++;
664
29.2k
  return int(p);
665
29.2k
}
666
667
int MoreText::checkTopicList(size_t tId, std::set<size_t> &parent)
668
15.0k
{
669
15.0k
  size_t numTopic=m_state->m_topicList.size();
670
15.0k
  if (tId>=numTopic) {
671
0
    MWAW_DEBUG_MSG(("MoreText::checkTopicList: can not find topic %d\n", int(tId)));
672
0
    return 0;
673
0
  }
674
15.0k
  if (parent.find(tId)!=parent.end()) {
675
0
    MWAW_DEBUG_MSG(("MoreText::checkTopicList: repairing fails\n"));
676
0
    throw libmwaw::ParseException();
677
0
  }
678
15.0k
  parent.insert(tId);
679
15.0k
  auto &topic=m_state->m_topicList[tId];
680
15.0k
  int nPages=0;
681
15.0k
  int outId=topic.m_attachList[MoreTextInternal::Topic::AOutline];
682
15.0k
  if (outId>=0) {
683
2.57k
    if (m_state->m_outlineList[size_t(outId)].m_paragraphs[0].m_pageBreak)
684
0
      nPages++;
685
2.57k
  }
686
15.0k
  auto id=int(tId);
687
15.0k
  if (topic.m_cloneId>=0) {
688
15.0k
    if (parent.find(size_t(topic.m_cloneId))!=parent.end()) {
689
283
      MWAW_DEBUG_MSG(("MoreText::checkTopicList: find a loop, remove a clone\n"));
690
283
      topic.m_cloneId=-1;
691
283
      parent.erase(tId);
692
283
      return 0;
693
283
    }
694
14.7k
    id = topic.m_cloneId;
695
14.7k
    parent.insert(size_t(id));
696
14.7k
  }
697
14.7k
  int lastTId=getLastTopicChildId(id);
698
14.7k
  for (int i=id+1; i<=lastTId; i++)
699
0
    nPages+=checkTopicList(size_t(i), parent);
700
14.7k
  topic.m_numPageBreak=nPages;
701
14.7k
  parent.erase(tId);
702
14.7k
  if (id!=int(tId))
703
14.7k
    parent.erase(size_t(tId));
704
14.7k
  return nPages;
705
15.0k
}
706
707
// try read to the file text position
708
bool MoreText::readTopic(MWAWEntry const &entry)
709
24.3k
{
710
24.3k
  if (!entry.valid() || (entry.length()%10)) {
711
88
    MWAW_DEBUG_MSG(("MoreText::readTopic: the entry is bad\n"));
712
88
    return false;
713
88
  }
714
  // topic 0-2: ?, header,footer, topic 3: title, after document
715
24.2k
  long pos = entry.begin();
716
24.2k
  MWAWInputStreamPtr &input= m_parserState->m_input;
717
24.2k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
718
24.2k
  libmwaw::DebugStream f;
719
720
24.2k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
721
24.2k
  entry.setParsed(true);
722
723
24.2k
  ascFile.addPos(pos);
724
24.2k
  ascFile.addNote("Entries(Topic)");
725
726
24.2k
  auto N=int(entry.length()/10);
727
2.16M
  for (int i=0; i < N; i++) {
728
2.14M
    pos=input->tell();
729
2.14M
    MoreTextInternal::Topic topic;
730
2.14M
    f.str("");
731
2.14M
    topic.m_level = static_cast<int>(input->readLong(2));
732
2.14M
    bool isAClone=false;
733
2.14M
    auto flag = static_cast<int>(input->readULong(2)); // some flag ?
734
2.14M
    if ((flag&1)==0) f << "hidden,";
735
2.14M
    if (flag&4) f << "marked,";
736
2.14M
    if (flag&0x10) topic.m_isCloned=true;
737
2.14M
    if (flag&0x20) isAClone=true;
738
2.14M
    if (flag&0x40) {
739
466k
      topic.m_hasList[MoreTextInternal::Topic::ASpeakerNote]=true;
740
466k
      f << "S" << m_state->m_actualSpeaker++ << ",";
741
466k
    }
742
2.14M
    if (flag&0x80) {
743
369k
      topic.m_hasList[MoreTextInternal::Topic::AComment]=true;
744
369k
      f << "C" << m_state->m_actualComment++ << ",";
745
369k
    }
746
2.14M
    if (flag&0x400) f << "showComment,";
747
2.14M
    if (flag&0x2000) topic.m_isStartSlide=true;
748
2.14M
    if (flag&0x8000) {
749
372k
      topic.m_hasList[MoreTextInternal::Topic::AOutline]=true;
750
372k
      f << "O" << m_state->m_actualOutline++ << ",";
751
372k
    }
752
    // find only bits: 5208
753
2.14M
    flag &= 0x5B4A;
754
2.14M
    if (flag) f << "fl=" << std::hex << flag << std::dec << ",";
755
2.14M
    long fPos = input->readLong(4);
756
2.14M
    if (isAClone)
757
528k
      topic.m_cloneId=static_cast<int>(fPos);
758
1.61M
    else {
759
1.61M
      f << "pos=" << std::hex << fPos << std::dec << ",";
760
1.61M
      topic.m_entry.setBegin(fPos);
761
1.61M
      if (!m_mainParser->checkAndFindSize(topic.m_entry)) {
762
1.51M
        MWAW_DEBUG_MSG(("MoreText::readTopic: can not read a text position\n"));
763
1.51M
        f << "###";
764
1.51M
        topic.m_entry = MWAWEntry();
765
1.51M
      }
766
1.61M
    }
767
2.14M
    auto val = static_cast<int>(input->readLong(2)); // a small number 1 or 2
768
2.14M
    if (val)
769
1.50M
      f << "f1=" << val << ",";
770
2.14M
    topic.m_extra=f.str();
771
2.14M
    m_state->m_topicList.push_back(topic);
772
773
2.14M
    f.str("");
774
2.14M
    f << "Topic-" << i << ":" << topic;
775
2.14M
    ascFile.addPos(pos);
776
2.14M
    ascFile.addNote(f.str().c_str());
777
2.14M
    input->seek(pos+10, librevenge::RVNG_SEEK_SET);
778
2.14M
  }
779
24.2k
  return true;
780
24.3k
}
781
782
bool MoreText::readComment(MWAWEntry const &entry)
783
11.0k
{
784
11.0k
  if (!entry.valid() || (entry.length()%8)) {
785
160
    MWAW_DEBUG_MSG(("MoreText::readComment: the entry is bad\n"));
786
160
    return false;
787
160
  }
788
  // comment0? comment1: header, comment2: footer
789
10.9k
  long pos = entry.begin();
790
10.9k
  MWAWInputStreamPtr &input= m_parserState->m_input;
791
10.9k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
792
10.9k
  libmwaw::DebugStream f;
793
794
10.9k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
795
10.9k
  entry.setParsed(true);
796
797
10.9k
  ascFile.addPos(pos);
798
10.9k
  ascFile.addNote("Entries(Comment)");
799
800
10.9k
  auto N=int(entry.length()/8);
801
1.16M
  for (int i=0; i < N; i++) {
802
1.15M
    pos=input->tell();
803
1.15M
    MoreTextInternal::Comment comment;
804
1.15M
    f.str("");
805
1.15M
    long fPos = input->readLong(4);
806
1.15M
    f << "pos=" << std::hex << fPos << std::dec << ",";
807
1.15M
    comment.m_entry.setBegin(fPos);
808
1.15M
    if (!m_mainParser->checkAndFindSize(comment.m_entry)) {
809
1.08M
      MWAW_DEBUG_MSG(("MoreText::readComment: can not read a file position\n"));
810
1.08M
      f << "###";
811
1.08M
      comment.m_entry.setLength(0);
812
1.08M
    }
813
1.15M
    auto val = static_cast<int>(input->readLong(2)); // always 4 ?
814
1.15M
    if (val != 4)
815
1.14M
      f << "f0=" << val << ",";
816
1.15M
    val = static_cast<int>(input->readULong(2)); // some flag ? find 0x3333 0x200d ...
817
1.15M
    if (val) f << "fl=" << std::hex << val << std::dec << ",";
818
819
1.15M
    comment.m_extra=f.str();
820
1.15M
    m_state->m_commentList.push_back(comment);
821
1.15M
    f.str("");
822
1.15M
    f << "Comment-C" << i << ":" << comment;
823
1.15M
    ascFile.addPos(pos);
824
1.15M
    ascFile.addNote(f.str().c_str());
825
1.15M
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
826
1.15M
  }
827
10.9k
  return true;
828
11.0k
}
829
830
bool MoreText::readSpeakerNote(MWAWEntry const &entry)
831
7.10k
{
832
7.10k
  if (!entry.valid() || (entry.length()%4)) {
833
198
    MWAW_DEBUG_MSG(("MoreText::readSpeakerNote: the entry is bad\n"));
834
198
    return false;
835
198
  }
836
837
6.90k
  long pos = entry.begin();
838
6.90k
  MWAWInputStreamPtr &input= m_parserState->m_input;
839
6.90k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
840
6.90k
  libmwaw::DebugStream f;
841
842
6.90k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
843
6.90k
  entry.setParsed(true);
844
845
6.90k
  f << "Entries(SpeakerNote):";
846
6.90k
  auto N=int(entry.length()/4);
847
2.46M
  for (int i=0; i < N; i++) {
848
2.45M
    long fPos = input->readLong(4);
849
2.45M
    f << "S" << i << ":pos=" << std::hex << fPos << std::dec << ",";
850
2.45M
    MWAWEntry tEntry;
851
2.45M
    tEntry.setBegin(fPos);
852
2.45M
    if (!m_mainParser->checkAndFindSize(tEntry)) {
853
2.08M
      MWAW_DEBUG_MSG(("MoreText::readSpeakerNote: can not read a file position\n"));
854
2.08M
      f << "###";
855
2.08M
      tEntry.setLength(0);
856
2.08M
    }
857
2.45M
    m_state->m_speakerList.push_back(tEntry);
858
2.45M
  }
859
6.90k
  ascFile.addPos(pos);
860
6.90k
  ascFile.addNote(f.str().c_str());
861
6.90k
  return true;
862
7.10k
}
863
864
//
865
// send the text
866
//
867
bool MoreText::sendMainText()
868
24.2k
{
869
24.2k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
870
24.2k
  libmwaw::DebugStream f;
871
24.2k
  std::vector<MWAWParagraph> paraStack;
872
  /* skip 0: unknown, 1: header(comment), 2: footer(comment), 3: title?, after text */
873
2.07M
  for (size_t i=4; i < m_state->m_topicList.size(); i++) {
874
2.04M
    auto const &topic = m_state->m_topicList[i];
875
2.04M
    MWAWEntry const &entry=topic.m_entry;
876
2.04M
    if (!entry.valid()) { // a clone ?
877
1.94M
      sendTopic(int(i),0,paraStack);
878
1.94M
      continue;
879
1.94M
    }
880
100k
    ascFile.addPos(entry.end());
881
100k
    ascFile.addNote("_");
882
100k
    if (sendTopic(int(i),0,paraStack))
883
100k
      continue;
884
0
    ascFile.addPos(entry.end());
885
0
    ascFile.addNote("_");
886
0
    f.str("");
887
0
    f << "Topic-" << i << "[data]:";
888
0
    ascFile.addPos(entry.begin());
889
0
    ascFile.addNote(f.str().c_str());
890
0
  }
891
24.2k
  return true;
892
24.2k
}
893
894
bool MoreText::sendComment(int cId)
895
336
{
896
336
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
897
336
  if (!listener) {
898
0
    MWAW_DEBUG_MSG(("MoreText::sendComment: can not find a listener!"));
899
0
    return true;
900
0
  }
901
336
  if (cId < 0 || cId >= int(m_state->m_commentList.size())) {
902
0
    MWAW_DEBUG_MSG(("MoreText::sendComment: can not find the comment %d!", cId));
903
0
    return false;
904
0
  }
905
336
  return sendText(m_state->m_commentList[size_t(cId)].m_entry, MWAWFont(3,12));
906
336
}
907
908
bool MoreText::sendSpeakerNote(int nId)
909
1.23k
{
910
1.23k
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
911
1.23k
  if (!listener) {
912
0
    MWAW_DEBUG_MSG(("MoreText::sendSpeakerNote: can not find a listener!"));
913
0
    return true;
914
0
  }
915
1.23k
  if (nId < 0 || nId >= int(m_state->m_speakerList.size())) {
916
0
    MWAW_DEBUG_MSG(("MoreText::sendSpeakerNote: can not find the speaker note %d!", nId));
917
0
    return false;
918
0
  }
919
1.23k
  return sendText(m_state->m_speakerList[size_t(nId)], MWAWFont(3,12));
920
1.23k
}
921
922
bool MoreText::sendTopic(int tId, int dLevel, std::vector<MWAWParagraph> &paraStack)
923
2.04M
{
924
2.04M
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
925
2.04M
  if (!listener) {
926
0
    MWAW_DEBUG_MSG(("MoreText::sendTopic: can not find a listener!"));
927
0
    return true;
928
0
  }
929
2.04M
  if (tId < 0 || tId >= int(m_state->m_topicList.size())) {
930
0
    MWAW_DEBUG_MSG(("MoreText::sendTopic: can not find the topic note %d!", tId));
931
0
    return false;
932
0
  }
933
2.04M
  auto const &topic=m_state->m_topicList[size_t(tId)];
934
2.04M
  MWAWEntry entry=topic.m_entry;
935
2.04M
  int level=topic.m_level+dLevel;
936
2.04M
  if (level < 0) {
937
355k
    if (tId>=4) {
938
355k
      MWAW_DEBUG_MSG(("MoreText::sendTopic: oops level is negatif!\n"));
939
355k
    }
940
355k
    level=0;
941
355k
  }
942
  // data to send clone child
943
2.04M
  int actId=tId, lastId = tId, cloneDLevel=0;
944
2.04M
  if (tId==1||tId==2) {
945
    // header/footer: the data are in the comment...
946
380
    int comment=topic.m_attachList[MoreTextInternal::Topic::AComment];
947
380
    if (comment<0||comment>=int(m_state->m_commentList.size()))
948
0
      return false;
949
380
    entry=m_state->m_commentList[size_t(comment)].m_entry;
950
380
  }
951
2.04M
  else if (topic.m_cloneId>=0 && topic.m_cloneId < static_cast<int>(m_state->m_topicList.size())) {
952
14.4k
    auto const &cTopic = m_state->m_topicList[size_t(topic.m_cloneId)];
953
14.4k
    entry=cTopic.m_entry;
954
14.4k
    actId = topic.m_cloneId;
955
14.4k
    lastId = getLastTopicChildId(topic.m_cloneId);
956
14.4k
    cloneDLevel = cTopic.m_level-level;;
957
14.4k
  }
958
2.04M
  if (!entry.valid())
959
1.94M
    return false;
960
  // retrieve the ouline
961
101k
  MWAWFont font(3,12);
962
101k
  MoreTextInternal::Paragraph para;
963
101k
  int outl=topic.m_attachList[MoreTextInternal::Topic::AOutline];
964
101k
  if (outl>=0 && outl < static_cast<int>(m_state->m_outlineList.size())) {
965
5.63k
    auto const &outline=m_state->m_outlineList[size_t(outl)];
966
5.63k
    if (outline.m_paragraphs[0].m_pageBreak)
967
0
      m_mainParser->newPage(++m_state->m_actualPage);
968
5.63k
    para=outline.m_paragraphs[0];
969
5.63k
    font = outline.m_fonts[0];
970
5.63k
  }
971
95.4k
  else if (tId>=4) {
972
    /* default: leader is default for a paragraph
973
974
    note: sometimes, some small level are bold by default, I do not understand why ? */
975
95.1k
    para.m_listType=1;
976
95.1k
  }
977
101k
  if (tId==1||tId==2) // force no list in header footer
978
380
    para.m_listType=0;
979
101k
  if (level >= int(paraStack.size()))
980
24.5k
    paraStack.resize(size_t(level+1));
981
101k
  if (level>0)
982
54.3k
    para.updateToFinalState(paraStack[size_t(level-1)], level,
983
54.3k
                            *m_parserState->m_listManager);
984
46.7k
  else
985
46.7k
    para.updateToFinalState(MWAWParagraph(),0, *m_parserState->m_listManager);
986
101k
  if (level>=0)
987
101k
    paraStack[size_t(level)]=para;
988
989
101k
  listener->setParagraph(para);
990
101k
  bool ok=sendText(entry, font);
991
101k
  if (tId==1||tId==2)
992
380
    return true;
993
  // send potential comment and speakernote
994
100k
  int comment=topic.m_attachList[MoreTextInternal::Topic::AComment];
995
100k
  if (comment>=0) {
996
336
    MWAWSubDocumentPtr doc(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, comment, 1));
997
336
    listener->insertComment(doc);
998
336
  }
999
100k
  int speaker=topic.m_attachList[MoreTextInternal::Topic::ASpeakerNote];
1000
100k
  if (speaker>=0) {
1001
1.23k
    MWAWSubDocumentPtr doc(new MoreTextInternal::SubDocument(*this, m_parserState->m_input, speaker, 2));
1002
1.23k
    listener->insertComment(doc);
1003
1.23k
  }
1004
1005
100k
  listener->insertEOL();
1006
100k
  for (int i=actId+1; i <= lastId; i++)
1007
0
    sendTopic(i, dLevel+cloneDLevel, paraStack);
1008
100k
  return ok;
1009
101k
}
1010
1011
bool MoreText::sendText(MWAWEntry const &entry, MWAWFont const &font)
1012
102k
{
1013
102k
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
1014
102k
  if (!listener) {
1015
0
    MWAW_DEBUG_MSG(("MoreText::sendText: can not find a listener!"));
1016
0
    return true;
1017
0
  }
1018
1019
102k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1020
102k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1021
102k
  libmwaw::DebugStream f;
1022
102k
  long pos = entry.begin();
1023
102k
  long endPos = entry.end();
1024
102k
  if (entry.length()==4) { // no text, we can stop here
1025
41.1k
    ascFile.addPos(pos);
1026
41.1k
    ascFile.addNote("Entries(Text):");
1027
41.1k
    ascFile.addPos(entry.end());
1028
41.1k
    ascFile.addNote("_");
1029
41.1k
    return true;
1030
41.1k
  }
1031
1032
61.4k
  if (entry.length()<4) {
1033
0
    MWAW_DEBUG_MSG(("MoreText::sendText: the entry is bad\n"));
1034
0
    return false;
1035
0
  }
1036
1037
61.4k
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1038
61.4k
  listener->setFont(font);
1039
61.4k
  f << "Entries(Text):";
1040
61.4k
  int val;
1041
61.4k
  MWAWFont ft(font);
1042
61.4k
  MWAWColor defCol;
1043
61.4k
  font.getColor(defCol);
1044
61.4k
  uint32_t defFlags=font.flags();
1045
61.4k
  bool defHasUnderline=font.getUnderline().isSet();
1046
61.4k
  listener->setFont(ft);
1047
1.92G
  while (!input->isEnd()) {
1048
1.92G
    long actPos = input->tell();
1049
1.92G
    if (actPos >= endPos)
1050
59.4k
      break;
1051
1.92G
    auto c=static_cast<unsigned char>(input->readULong(1));
1052
1.92G
    if (c!=0x1b) {
1053
1.92G
      listener->insertCharacter(c);
1054
1.92G
      f << c;
1055
1.92G
      continue;
1056
1.92G
    }
1057
4.23M
    if (actPos+1 >= endPos) {
1058
1.20k
      f << "@[#]";
1059
1.20k
      MWAW_DEBUG_MSG(("MoreText::sendText: text end by 0x1b\n"));
1060
1.20k
      continue;
1061
1.20k
    }
1062
4.22M
    auto fld=static_cast<int>(input->readULong(1));
1063
4.22M
    bool sendFont=true;
1064
4.22M
    switch (fld) {
1065
41.3k
    case 0x9:
1066
41.3k
      listener->insertTab();
1067
41.3k
      f << "\t";
1068
41.3k
      break;
1069
52.3k
    case 0xd: // EOL in header/footer
1070
52.3k
      listener->insertEOL();
1071
52.3k
      f << char(0xd);
1072
52.3k
      break;
1073
3.17k
    case 0x2d: // geneva
1074
3.17k
      ft.setId(font.id());
1075
3.17k
      sendFont=false;
1076
3.17k
      f << "@[fId=def]";
1077
3.17k
      break;
1078
28.7k
    case 0x2e: // 12
1079
28.7k
      ft.setSize(font.size());
1080
28.7k
      sendFont=false;
1081
28.7k
      f << "@[fSz=def]";
1082
28.7k
      break;
1083
14.8k
    case 0x2f: // black
1084
14.8k
      ft.setColor(defCol);
1085
14.8k
      sendFont=false;
1086
14.8k
      f << "@[fCol=def]";
1087
14.8k
      break;
1088
25.3k
    case 0x30: // font
1089
25.3k
      if (actPos+4+2 > endPos) {
1090
604
        f << "@[#fId]";
1091
604
        MWAW_DEBUG_MSG(("MoreText::sendText: field font seems too short\n"));
1092
604
        break;
1093
604
      }
1094
24.7k
      val = static_cast<int>(input->readULong(2));
1095
24.7k
      if (!(val&0x8000)) {
1096
20.2k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fId: unexpected id\n"));
1097
20.2k
        f << "@[#fId]";
1098
20.2k
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
1099
20.2k
        break;
1100
20.2k
      }
1101
4.55k
      f << "@[fId=" << (val&0x7FFF) << "]";
1102
4.55k
      ft.setId(val&0x7FFF);
1103
4.55k
      sendFont = false;
1104
4.55k
      val = static_cast<int>(input->readULong(2));
1105
4.55k
      if (val!=0x1b30) {
1106
4.48k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fId: unexpected end field\n"));
1107
4.48k
        f << "###";
1108
4.48k
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
1109
4.48k
        break;
1110
4.48k
      }
1111
64
      break;
1112
161k
    case 0x31:
1113
161k
      if (actPos+4+2 > endPos) {
1114
893
        f << "@[#fSz]";
1115
893
        MWAW_DEBUG_MSG(("MoreText::sendText: field fSz seems too short\n"));
1116
893
        break;
1117
893
      }
1118
160k
      val = static_cast<int>(input->readLong(2));
1119
160k
      f << "@[fSz=" << val << "]";
1120
160k
      if (val <= 0) {
1121
86.0k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fSz seems bad\n"));
1122
86.0k
        f << "###";
1123
86.0k
      }
1124
74.8k
      else {
1125
74.8k
        ft.setSize(float(val));
1126
74.8k
        sendFont = false;
1127
74.8k
      }
1128
160k
      val = static_cast<int>(input->readULong(2));
1129
160k
      if (val!=0x1b31) {
1130
129k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fSz: unexpected end field\n"));
1131
129k
        f << "###";
1132
129k
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
1133
129k
        break;
1134
129k
      }
1135
31.6k
      break;
1136
42.3k
    case 0x38: {
1137
42.3k
      if (actPos+4+10 > endPos) {
1138
602
        f << "@[#fCol]";
1139
602
        MWAW_DEBUG_MSG(("MoreText::sendText: field fCol seems too short\n"));
1140
602
        break;
1141
602
      }
1142
41.6k
      uint16_t values[5];
1143
208k
      for (auto &v : values) v=static_cast<uint16_t>(input->readULong(2));
1144
41.6k
      if (values[0]!=0xe || values[4]!=0xe) {
1145
41.5k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fCol: color sep seems bad\n"));
1146
41.5k
        f << "@[fCol###]";
1147
41.5k
      }
1148
190
      else {
1149
190
        MWAWColor col(static_cast<unsigned char>(values[1]>>8),
1150
190
                      static_cast<unsigned char>(values[2]>>8),
1151
190
                      static_cast<unsigned char>(values[3]>>8));
1152
190
        ft.setColor(col);
1153
190
        sendFont = false;
1154
190
        f << "@[fCol=" << col << "]";
1155
190
      }
1156
41.6k
      val = static_cast<int>(input->readULong(2));
1157
41.6k
      if (val!=0x1b38) {
1158
40.8k
        MWAW_DEBUG_MSG(("MoreText::sendText: field fCol: unexpected end field\n"));
1159
40.8k
        f << "###";
1160
40.8k
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
1161
40.8k
        break;
1162
40.8k
      }
1163
890
      break;
1164
41.6k
    }
1165
19.5k
    case 0x41:
1166
19.5k
      ft.set(MWAWFont::Script(33));
1167
19.5k
      sendFont = false;
1168
19.5k
      f << "@[supersc]";
1169
19.5k
      break;
1170
11.3k
    case 0x42: // in fact, (line bold)^bold
1171
11.3k
      if (defFlags&MWAWFont::boldBit)
1172
0
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::boldBit));
1173
11.3k
      else
1174
11.3k
        ft.setFlags(ft.flags()|MWAWFont::boldBit);
1175
11.3k
      sendFont = false;
1176
11.3k
      f << "@[b]";
1177
11.3k
      break;
1178
4.09k
    case 0x49: // in fact, (line italic)^italic
1179
4.09k
      if (defFlags&MWAWFont::italicBit)
1180
0
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::italicBit));
1181
4.09k
      else
1182
4.09k
        ft.setFlags(ft.flags()|MWAWFont::italicBit);
1183
4.09k
      sendFont = false;
1184
4.09k
      f << "@[it]";
1185
4.09k
      break;
1186
3.25k
    case 0x4c:
1187
3.25k
      ft.set(MWAWFont::Script(-33));
1188
3.25k
      sendFont = false;
1189
3.25k
      f << "@[subsc]";
1190
3.25k
      break;
1191
13.2k
    case 0x4f:
1192
13.2k
      if (defFlags&MWAWFont::outlineBit)
1193
0
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::outlineBit));
1194
13.2k
      else
1195
13.2k
        ft.setFlags(ft.flags()|MWAWFont::outlineBit);
1196
13.2k
      sendFont = false;
1197
13.2k
      f << "@[outline]";
1198
13.2k
      break;
1199
5.91k
    case 0x53:
1200
5.91k
      if (defFlags&MWAWFont::shadowBit)
1201
0
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::shadowBit));
1202
5.91k
      else
1203
5.91k
        ft.setFlags(ft.flags()|MWAWFont::shadowBit);
1204
5.91k
      sendFont = false;
1205
5.91k
      f << "@[shadow]";
1206
5.91k
      break;
1207
9.93k
    case 0x55:
1208
9.93k
      ft.setUnderlineStyle(defHasUnderline ? MWAWFont::Line::None : MWAWFont::Line::Simple);
1209
9.93k
      sendFont = false;
1210
9.93k
      f << "@[underl]";
1211
9.93k
      break;
1212
3.33k
    case 0x61:
1213
3.33k
      ft.set(MWAWFont::Script());
1214
3.33k
      sendFont = false;
1215
3.33k
      f << "@[script=def]";
1216
3.33k
      break;
1217
5.53k
    case 0x62:
1218
5.53k
      if ((defFlags&MWAWFont::boldBit)==0)
1219
5.53k
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::boldBit));
1220
1
      else
1221
1
        ft.setFlags(ft.flags()|MWAWFont::boldBit);
1222
5.53k
      sendFont = false;
1223
5.53k
      f << "@[/b]";
1224
5.53k
      break;
1225
5.15k
    case 0x69:
1226
5.15k
      if ((defFlags&MWAWFont::italicBit)==0)
1227
5.15k
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::italicBit));
1228
0
      else
1229
0
        ft.setFlags(ft.flags()|MWAWFont::italicBit);
1230
5.15k
      sendFont = false;
1231
5.15k
      f << "@[/it]";
1232
5.15k
      break;
1233
3.58k
    case 0x6f:
1234
3.58k
      if ((defFlags&MWAWFont::outlineBit)==0)
1235
3.58k
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::outlineBit));
1236
0
      else
1237
0
        ft.setFlags(ft.flags()|MWAWFont::outlineBit);
1238
3.58k
      sendFont = false;
1239
3.58k
      f << "@[/outline]";
1240
3.58k
      break;
1241
4.44k
    case 0x73:
1242
4.44k
      if ((defFlags&MWAWFont::shadowBit)==0)
1243
4.44k
        ft.setFlags(ft.flags()&uint32_t(~MWAWFont::shadowBit));
1244
0
      else
1245
0
        ft.setFlags(ft.flags()|MWAWFont::shadowBit);
1246
4.44k
      sendFont = false;
1247
4.44k
      f << "@[/shadow]";
1248
4.44k
      break;
1249
3.19k
    case 0x75:
1250
3.19k
      ft.setUnderlineStyle(defHasUnderline ? MWAWFont::Line::Simple : MWAWFont::Line::None);
1251
3.19k
      sendFont = false;
1252
3.19k
      f << "@[/underl]";
1253
3.19k
      break;
1254
9.01k
    case 0xb9: {
1255
9.01k
      if (actPos+4+8 > endPos) {
1256
627
        f << "@[#field]";
1257
627
        MWAW_DEBUG_MSG(("MoreText::sendText: field b9 seems too short\n"));
1258
627
        break;
1259
627
      }
1260
8.39k
      uint16_t values[4];
1261
33.5k
      for (auto &v : values) v=static_cast<uint16_t>(input->readULong(2));
1262
8.39k
      if (values[0]!=0xc || values[3]!=0xc) {
1263
8.39k
        MWAW_DEBUG_MSG(("MoreText::sendText: field the separator seems bad\n"));
1264
8.39k
        f << "@[field###]";
1265
8.39k
      }
1266
0
      else {
1267
0
        switch (values[1]) {
1268
0
        case 1:
1269
0
          listener->insertUnicodeString(librevenge::RVNGString("#Slide#"));
1270
0
          f << "@[slide/title";
1271
0
          if (values[2]) f << ":" << values[2]; // always 0?
1272
0
          f << "]";
1273
0
          break;
1274
0
        case 3:
1275
0
          listener->insertField(MWAWField(MWAWField::Title));
1276
0
          f << "@[title";
1277
0
          if (values[2]) f << ":" << values[2]; // always 0?
1278
0
          f << "]";
1279
0
          break;
1280
0
        case 4:
1281
0
          listener->insertUnicodeString(librevenge::RVNGString("#Folder#"));
1282
0
          f << "@[folder]";
1283
0
          if (values[2]) f << ":" << values[2]; // always 0?
1284
0
          f << "]";
1285
0
          break;
1286
0
        case 5:
1287
0
          listener->insertField(MWAWField(MWAWField::PageNumber));
1288
0
          f << "@[pNumber";
1289
0
          if (values[2]!=0xa) f << ":" << values[2];
1290
0
          f << "]";
1291
0
          break;
1292
0
        case 6: // actual time
1293
0
        case 7: // last modif
1294
0
          listener->insertField(MWAWField(MWAWField::Time));
1295
0
          f << "@[time";
1296
0
          if (values[1]==7) f << "2";
1297
0
          if (values[2]!=1) f << ":" << values[2];
1298
0
          f << "]";
1299
0
          break;
1300
0
        case 8: // actual date
1301
0
        case 9: // last modif
1302
0
          listener->insertField(MWAWField(MWAWField::Date));
1303
0
          f << "@[date";
1304
0
          if (values[1]==7) f << "2";
1305
0
          if (values[2]!=0x200) f << ":" << values[2];
1306
0
          f << "]";
1307
0
          break;
1308
0
        case 0xc:
1309
0
          listener->insertField(MWAWField(MWAWField::PageCount));
1310
0
          f << "@[pNumber";
1311
0
          if (values[2]!=0xa) f << ":" << values[2];
1312
0
          f << "]";
1313
0
          break;
1314
0
        default:
1315
0
          f << "@[field=##" << values[1] << ":" << values[2] << "]";
1316
0
          MWAW_DEBUG_MSG(("MoreText::sendText: unknown field\n"));
1317
0
          break;
1318
0
        }
1319
0
      }
1320
8.39k
      val = static_cast<int>(input->readULong(2));
1321
8.39k
      if (val!=0x1bb9) {
1322
6.64k
        MWAW_DEBUG_MSG(("MoreText::sendText: field b9: unexpected end field\n"));
1323
6.64k
        f << "###";
1324
6.64k
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
1325
6.64k
      }
1326
8.39k
      break;
1327
8.39k
    }
1328
35.8k
    case 0xf9: {
1329
35.8k
      if (actPos+22 > endPos) {
1330
493
        f << "@[#picture]";
1331
493
        MWAW_DEBUG_MSG(("MoreText::sendText: field f9 seems too short\n"));
1332
493
        break;
1333
493
      }
1334
35.3k
      auto sz=long(input->readULong(4));
1335
35.3k
      if (sz<22 || actPos+sz>=endPos) {
1336
5.28k
        MWAW_DEBUG_MSG(("MoreText::sendText: field f9: bad field size\n"));
1337
5.28k
        f << "###";
1338
5.28k
        input->seek(actPos+2, librevenge::RVNG_SEEK_CUR);
1339
5.28k
        break;
1340
5.28k
      }
1341
30.1k
      input->seek(actPos+sz-6, librevenge::RVNG_SEEK_SET);
1342
30.1k
      if (static_cast<int>(input->readULong(4))!=sz &&
1343
29.0k
          static_cast<int>(input->readULong(2))!=int(0x1b00|fld)) {
1344
22.4k
        MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown picture end field\n"));
1345
22.4k
        f << "@[#" << std::hex << fld << std::dec << ":" << sz << "]";
1346
22.4k
        input->seek(actPos+2, librevenge::RVNG_SEEK_SET);
1347
22.4k
        break;
1348
22.4k
      }
1349
7.66k
      input->seek(actPos+6, librevenge::RVNG_SEEK_SET);
1350
7.66k
      f << "[picture:";
1351
7.66k
      val = static_cast<int>(input->readLong(2));
1352
7.66k
      if (val!=0x100)
1353
6.85k
        f << "type=" << std::hex << val << std::dec << ",";
1354
7.66k
      float dim[4];
1355
30.6k
      for (auto &d : dim) d = float(input->readLong(2));
1356
7.66k
      MWAWBox2f bdbox(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
1357
7.66k
      f << "bdbox=" << bdbox << ",";
1358
7.66k
      if (sz>22) {
1359
7.66k
        std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, static_cast<int>(sz)-22));
1360
7.66k
        MWAWEmbeddedObject picture;
1361
7.66k
        if (pict && pict->getBinary(picture)) {
1362
7.66k
          MWAWPosition pictPos(MWAWVec2f(0,0), bdbox.size(), librevenge::RVNG_POINT);
1363
7.66k
          pictPos.m_anchorTo = MWAWPosition::Char;
1364
7.66k
          listener->insertPicture(pictPos, picture);
1365
7.66k
        }
1366
#ifdef DEBUG_WITH_FILES
1367
        if (1) {
1368
          librevenge::RVNGBinaryData file;
1369
          input->seek(actPos+16, librevenge::RVNG_SEEK_SET);
1370
          input->readDataBlock(sz-22, file);
1371
          static int volatile pictName = 0;
1372
          libmwaw::DebugStream f2;
1373
          f2 << "Pict-" << ++pictName << ".pct";
1374
          libmwaw::Debug::dumpFile(file, f2.str().c_str());
1375
          ascFile.skipZone(actPos+16, actPos+sz-7);
1376
        }
1377
#endif
1378
7.66k
      }
1379
7.66k
      input->seek(actPos+sz, librevenge::RVNG_SEEK_SET);
1380
7.66k
      break;
1381
30.1k
    }
1382
3.72M
    default: {
1383
3.72M
      auto sz=static_cast<int>(input->readULong(2));
1384
3.72M
      if (sz>4 && actPos+sz<=endPos) {
1385
3.04M
        input->seek(actPos+sz-4, librevenge::RVNG_SEEK_SET);
1386
3.04M
        if (static_cast<int>(input->readULong(2))==sz &&
1387
113k
            static_cast<int>(input->readULong(2))==int(0x1b00|fld)) {
1388
62.0k
          MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown field, but can infer size\n"));
1389
62.0k
          f << "@[#" << std::hex << fld << std::dec << ":" << sz << "]";
1390
62.0k
          break;
1391
62.0k
        }
1392
2.98M
        input->seek(actPos+2, librevenge::RVNG_SEEK_SET);
1393
2.98M
      }
1394
3.66M
      MWAW_DEBUG_MSG(("MoreText::sendText: find a unknown field\n"));
1395
3.66M
      f << "@[#" << std::hex << fld << std::dec << "]";
1396
3.66M
      break;
1397
3.72M
    }
1398
4.22M
    }
1399
4.22M
    if (!sendFont)
1400
218k
      listener->setFont(ft);
1401
4.22M
  }
1402
61.4k
  ascFile.addPos(pos);
1403
61.4k
  ascFile.addNote(f.str().c_str());
1404
61.4k
  ascFile.addPos(entry.end());
1405
61.4k
  ascFile.addNote("_");
1406
61.4k
  return true;
1407
61.4k
}
1408
1409
//////////////////////////////////////////////
1410
// Fonts
1411
//////////////////////////////////////////////
1412
bool MoreText::readFonts(MWAWEntry const &entry)
1413
6.29k
{
1414
6.29k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1415
6.29k
  if (!entry.valid() || !input || !input->checkPosition(entry.end())) {
1416
0
    MWAW_DEBUG_MSG(("MoreText::readFonts: the entry is bad\n"));
1417
0
    return false;
1418
0
  }
1419
1420
6.29k
  long pos = entry.begin();
1421
6.29k
  long endPos = entry.end();
1422
6.29k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1423
6.29k
  libmwaw::DebugStream f;
1424
1425
6.29k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1426
6.29k
  entry.setParsed(true);
1427
1428
6.29k
  int n=0;
1429
48.8k
  while (1) {
1430
48.8k
    pos=input->tell();
1431
48.8k
    if (pos+1 > endPos) {
1432
52
      MWAW_DEBUG_MSG(("MoreText::readFonts: problem reading a font\n"));
1433
52
      break;
1434
52
    }
1435
48.7k
    auto fSz=int(input->readULong(1));
1436
48.7k
    if (fSz==0)
1437
5.47k
      break;
1438
43.2k
    if (pos+1+fSz+2 > endPos) {
1439
772
      input->seek(-1, librevenge::RVNG_SEEK_CUR);
1440
772
      break;
1441
772
    }
1442
42.5k
    f.str("");
1443
42.5k
    if (n==0)
1444
3.32k
      f << "Entries(Fonts)-" << n++ << ",";
1445
39.1k
    else
1446
39.1k
      f << "Fonts-"  << n++ << ":";
1447
42.5k
    std::string name("");
1448
1.19M
    for (int i=0; i < fSz; i++)
1449
1.15M
      name+=char(input->readULong(1));
1450
42.5k
    if ((fSz&1)==0) input->seek(1, librevenge::RVNG_SEEK_CUR);
1451
42.5k
    auto id=static_cast<int>(input->readULong(2));
1452
42.5k
    f << name << ",id=" << id << ",";
1453
42.5k
    if (!name.empty())
1454
42.5k
      m_parserState->m_fontConverter->setCorrespondance(id, name);
1455
42.5k
    ascFile.addPos(pos);
1456
42.5k
    ascFile.addNote(f.str().c_str());
1457
42.5k
  }
1458
1459
6.29k
  pos = input->tell();
1460
6.29k
  if (pos != endPos) {
1461
6.20k
    MWAW_DEBUG_MSG(("MoreText::readFonts: problem reading a font\n"));
1462
6.20k
    ascFile.addPos(pos);
1463
6.20k
    ascFile.addNote("Fonts:###");
1464
6.20k
  }
1465
1466
6.29k
  return true;
1467
6.29k
}
1468
1469
//////////////////////////////////////////////
1470
// outline
1471
//////////////////////////////////////////////
1472
bool MoreText::readOutlineList(MWAWEntry const &entry)
1473
18.5k
{
1474
18.5k
  if (!entry.valid() || (entry.length()%4)) {
1475
100
    MWAW_DEBUG_MSG(("MoreText::readOutlineList: the entry is bad\n"));
1476
100
    return false;
1477
100
  }
1478
1479
18.4k
  long pos = entry.begin();
1480
18.4k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1481
18.4k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1482
18.4k
  libmwaw::DebugStream f;
1483
1484
18.4k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1485
18.4k
  entry.setParsed(true);
1486
1487
18.4k
  f << "Entries(Outline):";
1488
18.4k
  auto N=int(entry.length()/4);
1489
18.4k
  std::vector<MWAWEntry> posList;
1490
3.63M
  for (int i=0; i < N; i++) {
1491
3.61M
    MWAWEntry tEntry;
1492
3.61M
    tEntry.setBegin(input->readLong(4));
1493
3.61M
    tEntry.setId(int(i));
1494
3.61M
    if (!m_mainParser->checkAndFindSize(tEntry)) {
1495
3.44M
      MWAW_DEBUG_MSG(("MoreText::readOutlineList: can not read a file position\n"));
1496
3.44M
      f << "###,";
1497
3.44M
    }
1498
173k
    else
1499
173k
      f << std::hex << tEntry.begin() << "<->" << tEntry.end() << ",";
1500
3.61M
    posList.push_back(tEntry);
1501
3.61M
  }
1502
18.4k
  ascFile.addPos(pos);
1503
18.4k
  ascFile.addNote(f.str().c_str());
1504
1505
3.61M
  for (auto const &tEntry : posList) {
1506
3.61M
    if (!tEntry.valid())
1507
2.47M
      continue;
1508
1.13M
    MoreTextInternal::Outline outline;
1509
1.13M
    if (readOutline(tEntry, outline)) {
1510
1.00M
      m_state->m_outlineList.push_back(outline);
1511
1.00M
      continue;
1512
1.00M
    }
1513
132k
    m_state->m_outlineList.push_back(MoreTextInternal::Outline());
1514
132k
    ascFile.addPos(tEntry.begin());
1515
132k
    ascFile.addNote("Outline-data:###");
1516
132k
    ascFile.addPos(tEntry.end());
1517
132k
    ascFile.addNote("_");
1518
132k
  }
1519
18.4k
  return true;
1520
18.5k
}
1521
1522
bool MoreText::readOutline(MWAWEntry const &entry, MoreTextInternal::Outline &outline)
1523
1.13M
{
1524
1.13M
  if (!entry.valid() || entry.length()<8) {
1525
68.0k
    MWAW_DEBUG_MSG(("MoreText::readOutline: the entry is bad\n"));
1526
68.0k
    return false;
1527
68.0k
  }
1528
1.07M
  int vers = version();
1529
1.07M
  long pos = entry.begin();
1530
1.07M
  long endPos = entry.end();
1531
1.07M
  MWAWInputStreamPtr &input= m_parserState->m_input;
1532
1.07M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1533
1.07M
  libmwaw::DebugStream f;
1534
1535
1.07M
  input->seek(pos+4, librevenge::RVNG_SEEK_SET); // skip size
1536
1537
1.07M
  f << "Outline[O" << entry.id() << "]:";
1538
1.07M
  auto val=static_cast<int>(input->readULong(2));
1539
1.07M
  if (val!=6*(vers-1)) {
1540
1.07M
    MWAW_DEBUG_MSG(("MoreText::readOutline: find unexpected type\n"));
1541
1.07M
    f << "#f0=" << val << ",";
1542
1.07M
  }
1543
1.07M
  auto N=static_cast<int>(input->readULong(2));
1544
1.07M
  f << "N=" << N << ",";
1545
1.07M
  long lastListPos = pos+8+N*16;
1546
1.07M
  if (lastListPos > endPos) {
1547
64.1k
    MWAW_DEBUG_MSG(("MoreText::readOutline: can not read length\n"));
1548
64.1k
    return false;
1549
64.1k
  }
1550
1.00M
  ascFile.addPos(pos);
1551
1.00M
  ascFile.addNote(f.str().c_str());
1552
1553
1.00M
  std::vector<MoreTextInternal::OutlineMod> outlineModList;
1554
3.63G
  for (int n=0; n<N; n++) {
1555
3.62G
    pos = input->tell();
1556
3.62G
    f.str("");
1557
1558
3.62G
    MoreTextInternal::OutlineMod outlineMod;
1559
3.62G
    val=int(input->readLong(1));
1560
3.62G
    if (val!=6*(vers-1))
1561
3.62G
      f << "#f0=" << val << ",";
1562
1563
3.62G
    outlineMod.m_flags=int(input->readULong(1));
1564
7.25G
    for (auto &unkn : outlineMod.m_unknowns) unkn=int(input->readLong(2));
1565
3.62G
    outlineMod.m_type=int(input->readULong(2));
1566
3.62G
    int values[4];
1567
14.5G
    for (auto &v : values) v = static_cast<int>(input->readULong(2));
1568
3.62G
    int const which= outlineMod.getModId();
1569
3.62G
    auto &para = outline.m_paragraphs[which];
1570
3.62G
    MWAWFont &font=outline.m_fonts[which];
1571
3.62G
    uint32_t fFlags=font.flags();
1572
3.62G
    bool haveExtra=false;
1573
3.62G
    switch (outlineMod.m_type) {
1574
294k
    case 0x301: // font name
1575
323k
    case 0xf07: // left indent+tabs
1576
323k
      haveExtra=true;
1577
323k
      break;
1578
220k
    case 0x402:
1579
      // size can be very big, force it to be smallest than 100
1580
220k
      if (values[0]>0 && values[0] <= 100) {
1581
36.3k
        font.setSize(float(values[0]));
1582
36.3k
        f << "sz=" << values[0] << ",";
1583
36.3k
      }
1584
183k
      else {
1585
183k
        MWAW_DEBUG_MSG(("MoreText::readOutline: the font size seems bad\n"));
1586
183k
        f << "##sz=" << values[0] << ",";
1587
183k
      }
1588
220k
      break;
1589
124k
    case 0x603: {
1590
124k
      uint32_t bit=0;
1591
124k
      switch (values[0]) {
1592
17.4k
      case 0:
1593
17.4k
        f << "plain";
1594
17.4k
        if (values[1]==1)
1595
4.22k
          fFlags=0;
1596
17.4k
        break;
1597
4.91k
      case 1:
1598
4.91k
        bit = MWAWFont::boldBit;
1599
4.91k
        f << "b";
1600
4.91k
        break;
1601
4.99k
      case 2:
1602
4.99k
        bit = MWAWFont::italicBit;
1603
4.99k
        f << "it";
1604
4.99k
        break;
1605
5.87k
      case 3:
1606
5.87k
        if (values[1]==1)
1607
1.11k
          font.setUnderlineStyle(MWAWFont::Line::Simple);
1608
5.87k
        f << "underl";
1609
5.87k
        break;
1610
4.93k
      case 4:
1611
4.93k
        bit = MWAWFont::outlineBit;
1612
4.93k
        f << "outline";
1613
4.93k
        break;
1614
1.43k
      case 5:
1615
1.43k
        bit = MWAWFont::shadowBit;
1616
1.43k
        f << "shadow";
1617
1.43k
        break;
1618
85.1k
      default:
1619
85.1k
        f << "##fl=" << std::hex << values[0] << std::dec;
1620
85.1k
        break;
1621
124k
      }
1622
124k
      if (values[1]==1) {
1623
7.73k
        if (bit) fFlags = fFlags & (~bit);
1624
7.73k
        f << "[of],";
1625
7.73k
      }
1626
117k
      else if (values[1]!=0)
1627
102k
        f << "=##" << values[1] << ",";
1628
14.7k
      else
1629
14.7k
        fFlags |= bit;
1630
124k
      values[1]=0;
1631
124k
      break;
1632
124k
    }
1633
94.1k
    case 0x804: {
1634
94.1k
      MWAWColor col(static_cast<unsigned char>(static_cast<uint16_t>(values[0])>>8),
1635
94.1k
                    static_cast<unsigned char>(static_cast<uint16_t>(values[1])>>8),
1636
94.1k
                    static_cast<unsigned char>(static_cast<uint16_t>(values[2])>>8));
1637
94.1k
      font.setColor(col);
1638
94.1k
      f << col << ",";
1639
94.1k
      values[1]=values[2]=0;
1640
94.1k
      break;
1641
124k
    }
1642
140k
    case 0xa05:
1643
140k
      if (values[0]&0x8000) {
1644
3.13k
        para.setInterline(double(values[0]&0x7FFF)/20., librevenge::RVNG_POINT, MWAWParagraph::AtLeast);
1645
3.13k
        f << "interline=" << *para.m_spacings[0] << "pt,";
1646
3.13k
      }
1647
137k
      else {
1648
137k
        para.setInterline(double(values[0])/double(0x1000), librevenge::RVNG_PERCENT);
1649
137k
        f << "interline=" << 100* *para.m_spacings[0] << "%,";
1650
137k
      }
1651
140k
      break;
1652
26.2k
    case 0xc0f: // firstIndent
1653
26.2k
      para.m_margins[0] = double(values[0])/1440.;
1654
26.2k
      f << "indent=" << *para.m_margins[0] << ",";
1655
26.2k
      break;
1656
172k
    case 0x1006:
1657
172k
      switch (values[0]) {
1658
123k
      case 0:
1659
123k
        para.m_justify = MWAWParagraph::JustificationLeft;
1660
123k
        f << "left,";
1661
123k
        break;
1662
3.02k
      case 1:
1663
3.02k
        para.m_justify = MWAWParagraph::JustificationCenter;
1664
3.02k
        f << "center,";
1665
3.02k
        break;
1666
3.98k
      case 2:
1667
3.98k
        para.m_justify = MWAWParagraph::JustificationRight;
1668
3.98k
        f << "right,";
1669
3.98k
        break;
1670
5.70k
      case 3:
1671
5.70k
        para.m_justify = MWAWParagraph::JustificationFull;
1672
5.70k
        f << "full,";
1673
5.70k
        break;
1674
36.6k
      default:
1675
36.6k
        f << "##justify=" << values[0] << ",";
1676
36.6k
        break;
1677
172k
      }
1678
172k
      break;
1679
172k
    case 0x1208:
1680
53.7k
      if (values[0] & 0x8000) {
1681
4.41k
        para.m_spacings[1]=double(values[0]&0x7FFF)/1440.;
1682
4.41k
        f << "bef=" << double(values[0]&0x7FFF)/20. << "pt,";
1683
4.41k
      }
1684
49.3k
      else {
1685
        // assume 12pt
1686
49.3k
        para.m_spacings[1]=double(values[0])/double(0x1000)*12./72.;
1687
49.3k
        if (values[0])
1688
42.6k
          f << "bef=" << 100.*double(values[0])/double(0x1000) << "%,";
1689
49.3k
      }
1690
1691
53.7k
      if (values[1] & 0x8000) {
1692
10.8k
        para.m_spacings[2]=double(values[1]&0x7FFF)/1440.;
1693
10.8k
        f << "aft=" << double(values[1]&0x7FFF)/20. << "pt,";
1694
10.8k
      }
1695
42.9k
      else {
1696
42.9k
        para.m_spacings[2]=double(values[1])/double(0x1000)*12./72.;
1697
42.9k
        if (values[1])
1698
42.1k
          f << "aft=" << 100.*double(values[1])/double(0x1000) << "%,";
1699
42.9k
      }
1700
53.7k
      values[1]=0;
1701
53.7k
      break;
1702
30.5k
    case 0x1409: // lMargin in TWIP
1703
30.5k
      para.setLeftMargin(double(values[0]&0x7FFF)/1440., (values[0]&0x8000)==0);
1704
30.5k
      if (values[0]&0x8000)
1705
2.66k
        f << "indent=" << double(values[0]&0x7FFF)/1440. << ",";
1706
27.9k
      else // checkme
1707
27.9k
        f << "indent=" << double(values[0])/1440. << "[fromParent],";
1708
30.5k
      break;
1709
62.6k
    case 0x160a: // rMargin in TWIP
1710
62.6k
      para.setRightMargin(double(values[0]&0x7FFF)/1440., (values[0]&0x8000)==0);
1711
62.6k
      if (values[0]&0x8000)
1712
3.05k
        f << "indent=" << double(values[0]&0x7FFF)/1440. << ",";
1713
59.6k
      else // checkme
1714
59.6k
        f << "indent=" << double(values[0])/1440. << "[fromParent],";
1715
62.6k
      break;
1716
16.9k
    case 0x1a0c:
1717
16.9k
      para.m_pageBreak=(values[0]==0x100);
1718
16.9k
      if (values[0]==0x100)
1719
79
        f << "pagebreak,";
1720
16.8k
      else if (values[0]==0)
1721
160
        f << "no,";
1722
16.7k
      else
1723
16.7k
        f << "##break=" << std::hex << values[0] << std::dec << ",";
1724
16.9k
      break;
1725
27.8k
    case 0x1c0d:
1726
27.8k
      if (values[0]==0x100) {
1727
2.10k
        para.m_breakStatus = (*para.m_breakStatus)|MWAWParagraph::NoBreakWithNextBit;
1728
2.10k
        f << "together,";
1729
2.10k
      }
1730
25.7k
      else if (values[0]==0) {
1731
2.22k
        para.m_breakStatus = (*para.m_breakStatus)|int(~MWAWParagraph::NoBreakWithNextBit);
1732
2.22k
        f << "no,";
1733
2.22k
      }
1734
23.4k
      else
1735
23.4k
        f << "#keepLine=" << std::hex << values[0] << std::dec << ",";
1736
27.8k
      break;
1737
16.3k
    case 0x1e0e:
1738
16.3k
      para.m_keepOutlineTogether = (values[0]==0x100);
1739
16.3k
      if (values[0]==0x100)
1740
16
        f << "together,";
1741
16.2k
      else if (values[0]==0)
1742
2.55k
        f << "no,";
1743
13.7k
      else
1744
13.7k
        f << "#keepOutline=" << std::hex << values[0] << std::dec << ",";
1745
16.3k
      break;
1746
267k
    case 0x190b:
1747
267k
      para.m_listType = values[0];
1748
267k
      switch (values[0]) {
1749
2.04k
      case 0:
1750
2.04k
        f << "no,";
1751
2.04k
        break;
1752
91
      case 1:
1753
91
        f << "leader,";
1754
91
        break;
1755
249
      case 2:
1756
249
        f << "hardvard,";
1757
249
        break;
1758
7.06k
      case 3:
1759
7.06k
        f << "numeric,";
1760
7.06k
        break;
1761
8
      case 4:
1762
8
        f << "legal,";
1763
8
        break;
1764
1.76k
      case 5:
1765
1.76k
        f << "bullets,";
1766
1.76k
        break;
1767
256k
      default:
1768
256k
        if (values[0]>=11) {
1769
251k
          f << "custom[" << values[0] << "],";
1770
251k
          haveExtra=true;
1771
251k
          break;
1772
251k
        }
1773
4.87k
        f << "##bullet=" << values[0] << ",";
1774
4.87k
        break;
1775
267k
      }
1776
267k
      break;
1777
3.62G
    default:
1778
3.62G
      if (values[0])
1779
322M
        f << "f2=" << std::hex << values[0] << std::dec << ",";
1780
      // use heuristic to define extra data
1781
3.62G
      if (values[0]>0x2800)
1782
141M
        haveExtra = (values[0] & 0x0100);
1783
3.48G
      else
1784
3.48G
        haveExtra=values[1]==0;
1785
3.62G
      break;
1786
3.62G
    }
1787
3.62G
    font.setFlags(fFlags);
1788
3.62G
    if (values[1]) f << "g0=" << std::hex << values[1] << std::dec << ",";
1789
1790
3.62G
    if (haveExtra && values[3]>0 &&
1791
97.7M
        lastListPos+values[2]+values[3] <= endPos) {
1792
97.5M
      outlineMod.m_entry.setBegin(lastListPos+values[2]);
1793
97.5M
      outlineMod.m_entry.setLength(values[3]);
1794
97.5M
      outlineMod.m_entry.setId(n);
1795
97.5M
    }
1796
3.53G
    else {
1797
10.5G
      for (int i=2; i < 4; i++) {
1798
7.06G
        if (values[i])
1799
472M
          f << "g" << i-1 << "=" << std::hex << values[i] << std::dec << ",";
1800
7.06G
      }
1801
3.53G
    }
1802
3.62G
    outlineMod.m_extra=f.str();
1803
3.62G
    f.str("");
1804
3.62G
    f << "Outline[O" << entry.id() << "-" << n << "]:" << outlineMod;
1805
3.62G
    outlineModList.push_back(outlineMod);
1806
3.62G
    ascFile.addPos(pos);
1807
3.62G
    ascFile.addNote(f.str().c_str());
1808
3.62G
    input->seek(pos+16, librevenge::RVNG_SEEK_SET);
1809
3.62G
  }
1810
1811
1.00M
  int n=0;
1812
3.62G
  for (auto const &outlineMod : outlineModList) {
1813
3.62G
    n++;
1814
3.62G
    if (!outlineMod.m_entry.valid())
1815
3.53G
      continue;
1816
97.5M
    f.str("");
1817
97.5M
    f << "Outline[O" << entry.id() << "-A" << n-1 << "]:";
1818
97.5M
    bool ok=false;
1819
1820
97.5M
    auto &para = outline.m_paragraphs[outlineMod.getModId()];
1821
97.5M
    switch (outlineMod.m_type) {
1822
253k
    case 0x301: {
1823
253k
      std::string fName;
1824
253k
      int fId;
1825
253k
      ok = readFont(outlineMod.m_entry, fName,fId);
1826
253k
      if (!ok) break;
1827
1.24k
      f << "font=[";
1828
1.24k
      f << "name=" << fName;
1829
1.24k
      if (fId>=0) {
1830
1.24k
        f << ":" << fId;
1831
1.24k
        MWAWFont &font=outline.m_fonts[outlineMod.getModId()];
1832
1.24k
        font.setId(fId);
1833
1.24k
      }
1834
1.24k
      f << "],";
1835
1.24k
      break;
1836
253k
    }
1837
27.7k
    case 0xf07: {
1838
27.7k
      std::string mess;
1839
27.7k
      ok = readTabs(outlineMod.m_entry, para, mess);
1840
27.7k
      if (!ok) break;
1841
374
      f << "tabs=[" << mess << "],";
1842
374
      break;
1843
27.7k
    }
1844
250k
    case 0x190b: {
1845
250k
      ok = readCustomListLevel(outlineMod.m_entry, para.m_customListLevel);
1846
250k
      if (!ok) break;
1847
12.2k
      f << para.m_customListLevel << ",";
1848
12.2k
      break;
1849
250k
    }
1850
97.0M
    default:
1851
97.0M
      break;
1852
97.5M
    }
1853
    // can be also pattern or backside or custom header
1854
97.5M
    if (!ok) {
1855
97.5M
      f << "[" << outlineMod << "]";
1856
97.5M
      if (!parseUnknown(outlineMod.m_entry, 0))
1857
97.1M
        f << "###";
1858
97.5M
    }
1859
97.5M
    ascFile.addPos(outlineMod.m_entry.begin());
1860
97.5M
    ascFile.addNote(f.str().c_str());
1861
97.5M
  }
1862
1.00M
  ascFile.addPos(endPos);
1863
1.00M
  ascFile.addNote("_");
1864
1.00M
  return true;
1865
1.00M
}
1866
1867
//////////////////////////////////////////////
1868
// small structure
1869
//////////////////////////////////////////////
1870
bool MoreText::readFont(MWAWEntry const &entry, std::string &fName, int &fId)
1871
97.4M
{
1872
97.4M
  fName="";
1873
97.4M
  fId=-1;
1874
97.4M
  MWAWInputStreamPtr &input= m_parserState->m_input;
1875
97.4M
  if (entry.length() < 2 || !input->checkPosition(entry.end()))
1876
82.2M
    return false;
1877
15.1M
  long pos = entry.begin();
1878
15.1M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1879
1880
15.1M
  auto fSz=static_cast<int>(input->readULong(1));
1881
15.1M
  long remain=entry.length()-long(1+fSz);
1882
15.1M
  if (fSz==0 || remain<0 || remain==1)
1883
7.28M
    return false;
1884
7.88M
  if (remain>=2 && remain!=2+(1-(fSz%2)))
1885
7.74M
    return false;
1886
2.46M
  for (int i=0; i < fSz; i++) {
1887
2.41M
    auto c=char(input->readULong(1));
1888
2.41M
    if (c==0) return false;
1889
2.33M
    fName+=c;
1890
2.33M
  }
1891
56.8k
  if (remain==0) { // let try to retrieve the font id
1892
31.5k
    fId=m_parserState->m_fontConverter->getId(fName);
1893
31.5k
    return true;
1894
31.5k
  }
1895
25.3k
  if ((fSz%2)==0) input->seek(1,librevenge::RVNG_SEEK_CUR);
1896
25.3k
  fId=static_cast<int>(input->readULong(2));
1897
25.3k
  return true;
1898
56.8k
}
1899
1900
bool MoreText::readCustomListLevel(MWAWEntry const &entry, MWAWListLevel &level)
1901
250k
{
1902
250k
  level=MWAWListLevel();
1903
250k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1904
250k
  if (entry.length()<22 || !input || !input->checkPosition(entry.end()))
1905
109k
    return false;
1906
1907
141k
  libmwaw::DebugStream f;
1908
141k
  long pos = entry.begin();
1909
141k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1910
141k
  MWAWFont font;
1911
141k
  auto fId=static_cast<int>(input->readULong(2));
1912
141k
  if (fId==0xFFFF) // default
1913
7.94k
    ;
1914
133k
  else if (fId&0x8000) {
1915
22.1k
    f << "fId=" << (fId&0x7FFF) << ",";
1916
22.1k
    font.setId(fId&0x7FFF);
1917
22.1k
  }
1918
110k
  else
1919
110k
    f << "#fId=" << std::hex << fId << std::dec << ",";
1920
141k
  auto fSz = static_cast<int>(input->readLong(2));
1921
141k
  if (fSz != -1) {
1922
132k
    font.setSize(float(fSz));
1923
132k
    f << "fSz=" << fSz << ",";
1924
132k
  }
1925
141k
  auto fFlags=static_cast<int>(input->readULong(1));
1926
141k
  uint32_t flags=0;
1927
141k
  if (fFlags&1) flags |= MWAWFont::boldBit;
1928
141k
  if (fFlags&2) flags |= MWAWFont::italicBit;
1929
141k
  if (fFlags&4) font.setUnderlineStyle(MWAWFont::Line::Simple);
1930
141k
  if (fFlags&8) flags |= MWAWFont::outlineBit;
1931
141k
  if (fFlags&0x10) flags |= MWAWFont::shadowBit;
1932
141k
  if (fFlags&0xE0)
1933
42.2k
    f << "#fFlags=" << std::hex << (fFlags&0xE0) << std::dec << ",";
1934
141k
  font.setFlags(flags);
1935
1936
141k
  auto fColor = static_cast<int>(input->readLong(1));
1937
141k
  if (fColor==1)
1938
6.28k
    input->seek(6, librevenge::RVNG_SEEK_CUR);
1939
134k
  else if (fColor==3) {
1940
5.62k
    unsigned char color[3];
1941
16.8k
    for (auto &c : color) c=static_cast<unsigned char>(input->readULong(2)>>8);
1942
5.62k
    font.setColor(MWAWColor(color[0], color[1], color[2]));
1943
5.62k
  }
1944
129k
  else {
1945
129k
    f << "#fCol=" << fColor << ",";
1946
129k
    input->seek(6, librevenge::RVNG_SEEK_CUR);
1947
129k
  }
1948
#if defined(DEBUG_WITH_FILES)
1949
  f << "font=[" << font.getDebugString(m_parserState->m_fontConverter) << "],";
1950
#endif
1951
1952
  // now 4 bool
1953
141k
  bool bVal[4]= {false, false, false, false };
1954
141k
  long val;
1955
705k
  for (int i=0; i < 4; i++) {
1956
564k
    val = input->readLong(1);
1957
564k
    if (!val) continue;
1958
339k
    if (val!=1) {
1959
325k
      f << "#g" << i << "=" << val << ",";
1960
325k
      continue;
1961
325k
    }
1962
14.2k
    bVal[i]=true;
1963
14.2k
  }
1964
423k
  for (int i=0; i<2; i++) { // g1: field left ident modify?
1965
282k
    if (bVal[i])
1966
6.32k
      f << "g" << i << "=true,";
1967
282k
  }
1968
141k
  if (bVal[2]) // or flush left at
1969
2.65k
    f << "flushRight,";
1970
141k
  if (!bVal[3])
1971
135k
    f << "useFirstlineIdent,";
1972
141k
  val = input->readLong(2);
1973
141k
  if (val!=0x2d0) // default 0.5"
1974
131k
    f << "leftIdent=" << double(val)/1440. << ",";
1975
141k
  val = input->readLong(2);
1976
141k
  if (val != 0xb)
1977
141k
    f << "f6=" << val << ",";
1978
141k
  if (fId!=0xFFFF) { // maybe the font name
1979
133k
    auto fontSz=static_cast<int>(input->readULong(1));
1980
133k
    if (!fontSz || input->tell()+fontSz >= entry.end())
1981
81.5k
      input->seek(-1,librevenge::RVNG_SEEK_CUR);
1982
51.5k
    else {
1983
51.5k
      std::string fName("");
1984
4.00M
      for (int i=0; i<fontSz; i++)
1985
3.94M
        fName+=char(input->readULong(1));
1986
51.5k
      f << "fName=" << fName << ",";
1987
51.5k
      int newId=m_parserState->m_fontConverter->getId(fName);
1988
51.5k
      if (newId > 0)
1989
50.2k
        font.setId(fId=newId);
1990
51.5k
    }
1991
133k
  }
1992
1993
141k
  auto labelSz = static_cast<int>(input->readULong(1));
1994
141k
  if (input->tell()+labelSz != entry.end())
1995
128k
    return false;
1996
1997
12.2k
  f << "label=";
1998
12.2k
  if (fId == 0xFFFF)
1999
1.05k
    fId=3;
2000
1.45M
  for (int c=0; c < labelSz; c++) {
2001
1.43M
    auto ch=static_cast<unsigned char>(input->readULong(1));
2002
1.43M
    f << ch;
2003
1.43M
    int unicode = m_parserState->m_fontConverter->unicode(fId, static_cast<unsigned char>(ch));
2004
1.43M
    if (unicode!=-1)
2005
631k
      libmwaw::appendUnicode(uint32_t(unicode), level.m_label);
2006
806k
    else if (ch==0x9 || ch > 0x1f)
2007
159k
      libmwaw::appendUnicode(static_cast<uint32_t>(c), level.m_label);
2008
646k
    else {
2009
646k
      f << "##";
2010
646k
      MWAW_DEBUG_MSG(("MoreText::readCustomListLevel: label char seems bad\n"));
2011
646k
      libmwaw::appendUnicode('#', level.m_label);
2012
646k
    }
2013
1.43M
  }
2014
12.2k
  f << ",";
2015
12.2k
  level.m_type=MWAWListLevel::LABEL;
2016
12.2k
  level.m_extra=f.str();
2017
12.2k
  if (input->tell()!=entry.end())
2018
0
    m_parserState->m_asciiFile.addDelimiter(input->tell(),'|');
2019
12.2k
  return true;
2020
141k
}
2021
2022
bool MoreText::readTabs(MWAWEntry const &entry, MoreTextInternal::Paragraph &para,
2023
                        std::string &mess)
2024
97.5M
{
2025
97.5M
  mess="";
2026
97.5M
  if (entry.length() < 4)
2027
5.85M
    return false;
2028
91.7M
  MWAWInputStreamPtr &input= m_parserState->m_input;
2029
91.7M
  libmwaw::DebugStream f;
2030
2031
91.7M
  long pos = entry.begin();
2032
91.7M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2033
2034
91.7M
  auto nTabs=static_cast<int>(input->readULong(2));
2035
91.7M
  if (entry.length()!=4+4*nTabs)
2036
91.3M
    return false;
2037
374k
  auto repeat=static_cast<int>(input->readLong(2));
2038
374k
  if (uint16_t(repeat)==0x8000) // special case
2039
35
    f << "def[center,right],";
2040
374k
  else
2041
374k
    f << "repeat=" << double(repeat)/1440. << ",";
2042
374k
  para.m_tabs->resize(0);
2043
7.65M
  for (int i=0; i < nTabs; i++) {
2044
7.27M
    libmwaw::DebugStream f2;
2045
7.27M
    MWAWTabStop tab;
2046
7.27M
    tab.m_position = double(input->readULong(2))/1440.;
2047
7.27M
    auto val=static_cast<int>(input->readULong(1));
2048
7.27M
    switch (val&0xF) {
2049
293k
    case 1: // left
2050
293k
      break;
2051
178k
    case 2:
2052
178k
      tab.m_alignment=MWAWTabStop::CENTER;
2053
178k
      break;
2054
134k
    case 3:
2055
134k
      tab.m_alignment=MWAWTabStop::RIGHT;
2056
134k
      break;
2057
268k
    case 4:
2058
268k
      tab.m_alignment=MWAWTabStop::DECIMAL;
2059
268k
      break;
2060
6.40M
    default:
2061
6.40M
      f2 << "#align=" << (val&0xF) << ",";
2062
6.40M
      break;
2063
7.27M
    }
2064
7.27M
    switch (val>>4) {
2065
5.64M
    case 0: // none
2066
5.64M
      break;
2067
91.6k
    case 1:
2068
91.6k
      tab.m_leaderCharacter = '_';
2069
91.6k
      break;
2070
123k
    case 3: // more large space
2071
123k
      f2 << "dot[large],";
2072
123k
      MWAW_FALLTHROUGH;
2073
334k
    case 2:
2074
334k
      tab.m_leaderCharacter = '.';
2075
334k
      break;
2076
1.20M
    default:
2077
1.20M
      f2 << "#leader=" << (val>>4) << ",";
2078
1.20M
      break;
2079
7.27M
    }
2080
7.27M
    auto decimalChar = char(input->readULong(1));
2081
7.27M
    if (decimalChar) {
2082
2.27M
      int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(decimalChar));
2083
2.27M
      if (unicode==-1)
2084
758k
        tab.m_decimalCharacter = uint16_t(decimalChar);
2085
1.52M
      else
2086
1.52M
        tab.m_decimalCharacter = uint16_t(unicode);
2087
2.27M
    }
2088
7.27M
    f << "tab" << i << "=[" << tab << "," << f2.str() << "],";
2089
7.27M
    para.m_tabs->push_back(tab);
2090
7.27M
  }
2091
374k
  mess=f.str();
2092
374k
  return true;
2093
374k
}
2094
2095
//////////////////////////////////////////////
2096
// unknown structure
2097
//////////////////////////////////////////////
2098
bool MoreText::parseUnknown(MWAWEntry const &entry, long fDecal)
2099
97.5M
{
2100
97.5M
  MWAWInputStreamPtr &input= m_parserState->m_input;
2101
97.5M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
2102
97.5M
  libmwaw::DebugStream f;
2103
2104
97.5M
  MoreStruct::Pattern pattern;
2105
97.5M
  long pos = entry.begin();
2106
97.5M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2107
97.5M
  if (m_mainParser->readPattern(entry.end(),pattern)) {
2108
14.6k
    f << pattern;
2109
14.6k
    if (input->tell()!=entry.end())
2110
14.2k
      ascFile.addDelimiter(input->tell(),'|');
2111
14.6k
    ascFile.addPos(pos+fDecal);
2112
14.6k
    ascFile.addNote(f.str().c_str());
2113
14.6k
    return true;
2114
14.6k
  }
2115
  // can we find a backsidde here
2116
97.5M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2117
97.5M
  std::string extra("");
2118
97.5M
  if (m_mainParser->readBackside(entry.end(), extra)) {
2119
21.2k
    f << extra;
2120
21.2k
    if (input->tell()!=entry.end())
2121
20.3k
      ascFile.addDelimiter(input->tell(),'|');
2122
21.2k
    ascFile.addPos(pos+fDecal);
2123
21.2k
    ascFile.addNote(f.str().c_str());
2124
21.2k
    return true;
2125
21.2k
  }
2126
2127
97.5M
  std::string mess;
2128
97.5M
  MoreTextInternal::Paragraph para;
2129
97.5M
  if (readTabs(entry, para, mess)) {
2130
374k
    f << "tabs=[" << mess << "],";
2131
374k
    ascFile.addPos(pos+fDecal);
2132
374k
    ascFile.addNote(f.str().c_str());
2133
374k
    return true;
2134
374k
  }
2135
2136
97.1M
  std::string fName;
2137
97.1M
  int fId;
2138
97.1M
  if (readFont(entry, fName,fId)) {
2139
55.5k
    f << "font=[";
2140
55.5k
    f << "name=" << fName;
2141
55.5k
    if (fId>=0) f << ":" << fId;
2142
55.5k
    f << "],";
2143
55.5k
    ascFile.addPos(pos+fDecal);
2144
55.5k
    ascFile.addNote(f.str().c_str());
2145
55.5k
    return true;
2146
55.5k
  }
2147
97.1M
  return false;
2148
97.1M
}
2149
2150
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: