Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MsWrdTextStyles.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
#include <map>
34
35
#include "MWAWTextListener.hxx"
36
#include "MWAWSection.hxx"
37
38
#include "MsWrdParser.hxx"
39
#include "MsWrdStruct.hxx"
40
#include "MsWrdText.hxx"
41
42
#include "MsWrdTextStyles.hxx"
43
44
/** Internal: the structures of a MsWrdTextStyles */
45
namespace MsWrdTextStylesInternal
46
{
47
////////////////////////////////////////
48
//! Internal: the state of a MsWrdTextStylesInternal
49
struct State {
50
  //! constructor
51
  State()
52
172k
    : m_version(-1)
53
172k
    , m_defaultFont(2,12)
54
172k
    , m_nextStyleMap()
55
172k
    , m_fontList()
56
172k
    , m_paragraphList()
57
172k
    , m_sectionList()
58
172k
    , m_textstructParagraphList()
59
172k
    , m_styleFontMap()
60
172k
    , m_styleParagraphMap()
61
172k
  {
62
172k
  }
63
  //! the file version
64
  int m_version;
65
66
  //! the default font ( NewYork 12pt)
67
  MWAWFont m_defaultFont;
68
69
  //! a map styleId to next styleId
70
  std::map<int, int> m_nextStyleMap;
71
72
  //! the list of fonts
73
  std::vector<MsWrdStruct::Font> m_fontList;
74
75
  //! the list of paragraph
76
  std::vector<MsWrdStruct::Paragraph> m_paragraphList;
77
78
  //! the list of section
79
  std::vector<MsWrdStruct::Section> m_sectionList;
80
81
  //! the list of paragraph in textstruct
82
  std::vector<MsWrdStruct::Paragraph> m_textstructParagraphList;
83
84
  //! the list of fonts in style
85
  std::map<int, MsWrdStruct::Font> m_styleFontMap;
86
87
  //! the list of paragraph in style
88
  std::map<int, MsWrdStruct::Paragraph> m_styleParagraphMap;
89
};
90
}
91
92
////////////////////////////////////////////////////////////
93
// constructor/destructor, ...
94
////////////////////////////////////////////////////////////
95
MsWrdTextStyles::MsWrdTextStyles(MsWrdText &textParser)
96
172k
  : m_parserState(textParser.getParserState())
97
172k
  , m_state(new MsWrdTextStylesInternal::State)
98
172k
  , m_mainParser(textParser.m_mainParser)
99
172k
  , m_textParser(&textParser)
100
172k
{
101
172k
}
102
103
MsWrdTextStyles::~MsWrdTextStyles()
104
172k
{ }
105
106
int MsWrdTextStyles::version() const
107
8.82M
{
108
8.82M
  if (m_state->m_version < 0)
109
51.4k
    m_state->m_version = m_parserState->m_version;
110
8.82M
  return m_state->m_version;
111
8.82M
}
112
113
MWAWFont const &MsWrdTextStyles::getDefaultFont() const
114
0
{
115
0
  return m_state->m_defaultFont;
116
0
}
117
118
////////////////////////////////////////////////////////////
119
// try to read a font
120
////////////////////////////////////////////////////////////
121
bool MsWrdTextStyles::readFont(MsWrdStruct::Font &font, MsWrdTextStyles::ZoneType type)
122
1.35M
{
123
1.35M
  bool mainZone = type==TextZone;
124
1.35M
  libmwaw::DebugStream f;
125
126
1.35M
  MWAWInputStreamPtr &input= m_parserState->m_input;
127
1.35M
  long pos = input->tell();
128
1.35M
  auto sz = static_cast<int>(input->readULong(1));
129
1.35M
  if (sz > 20 || sz == 3) {
130
502k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
131
502k
    return false;
132
502k
  }
133
134
851k
  if (sz == 0) return true;
135
136
617k
  auto flag = static_cast<int>(input->readULong(1));
137
617k
  uint32_t flags = font.m_font->flags();
138
617k
  if (flag&0x80) flags ^= MWAWFont::boldBit;
139
617k
  if (flag&0x40) flags ^= MWAWFont::italicBit;
140
617k
  if (flag&0x20) {
141
98.3k
    if (font.m_font->getStrikeOut().m_style==MWAWFont::Line::Simple)
142
17.7k
      font.m_font->setStrikeOutStyle(MWAWFont::Line::None);
143
80.5k
    else
144
80.5k
      font.m_font->setStrikeOutStyle(MWAWFont::Line::Simple);
145
98.3k
  }
146
617k
  if (flag&0x10) flags ^= MWAWFont::outlineBit;
147
617k
  if (flag&0x8) flags ^= MWAWFont::shadowBit;
148
617k
  if (flag&0x4) flags ^= MWAWFont::smallCapsBit;
149
617k
  if (flag&0x2) flags ^= MWAWFont::uppercaseBit;
150
617k
  if (flag&0x1) flags ^= MWAWFont::hiddenBit;
151
152
617k
  int what = 0;
153
  /*  01: horizontal decal, 2: vertical decal, 4; underline, 08: fSize,  10: set font, 20: font color, 40: ???(maybe reset)
154
  */
155
617k
  if (sz >= 2) what = static_cast<int>(input->readULong(1));
156
157
617k
  if (sz >= 4) {
158
506k
    auto fId = static_cast<int>(input->readULong(2));
159
506k
    if (fId) {
160
415k
      if (mainZone && (what & 0x50)==0) f << "#fId,";
161
415k
      font.m_font->setId(fId);
162
415k
    }
163
91.4k
    else if (what & 0x10) {
164
9.02k
    }
165
506k
    what &= 0xEF;
166
506k
  }
167
110k
  else if (what & 0x10) {
168
3.50k
  }
169
617k
  if (sz >= 5) {
170
489k
    float fSz = float(input->readULong(1))/2.0f;
171
489k
    if (fSz>0) {
172
294k
      if (mainZone && (what & 0x48)==0) f << "#fSz,";
173
294k
      font.m_font->setSize(fSz);
174
294k
    }
175
489k
    what &= 0xF7;
176
489k
  }
177
178
617k
  if (sz >= 6) {
179
478k
    auto decal = static_cast<int>(input->readLong(1)); // unit point
180
478k
    if (decal) {
181
389k
      if (what & 0x2)
182
166k
        font.m_font->set(MWAWFont::Script(float(decal)/2.f, librevenge::RVNG_POINT));
183
222k
      else
184
222k
        f << "#vDecal=" << decal;
185
389k
    }
186
478k
    what &= 0xFD;
187
478k
  }
188
617k
  if (sz >= 7) {
189
470k
    auto decal = static_cast<int>(input->readLong(1)); // unit point > 0 -> expand < 0: condensed
190
470k
    if (decal) {
191
297k
      if ((what & 0x1) == 0) f << "#hDecal=" << decal <<",";
192
63.3k
      else font.m_font->setDeltaLetterSpacing(float(decal)/16.0f);
193
297k
    }
194
470k
    what &= 0xFE;
195
470k
  }
196
197
617k
  if (sz >= 8) {
198
459k
    auto val = static_cast<int>(input->readULong(1));
199
459k
    if (val & 0xF0) {
200
210k
      if (what & 0x20) {
201
43.3k
        MWAWColor col;
202
43.3k
        if (m_mainParser->getColor((val>>4),col))
203
27.8k
          font.m_font->setColor(col);
204
15.5k
        else
205
15.5k
          f << "#fColor=" << (val>>4) << ",";
206
43.3k
      }
207
166k
      else
208
166k
        f << "#fColor=" << (val>>4) << ",";
209
210k
    }
210
459k
    what &= 0xDF;
211
212
459k
    if (val && (what & 0x4)) {
213
233k
      auto style=MWAWFont::Line::Simple;
214
233k
      switch ((val>>1)&0x7) {
215
12.6k
      case 4:
216
12.6k
        style=MWAWFont::Line::Dot;
217
12.6k
        break;
218
32.9k
      case 3:
219
32.9k
        font.m_font->setUnderlineType(MWAWFont::Line::Double);
220
32.9k
        break;
221
39.1k
      case 2:
222
39.1k
        font.m_font->setUnderlineWordFlag(true);
223
39.1k
        break;
224
51.0k
      case 1:
225
51.0k
        break;
226
98.1k
      default:
227
98.1k
        f << "#underline=" << ((val>>1) &0x7) << ",";
228
98.1k
        break;
229
233k
      }
230
233k
      if (font.m_font->getUnderline().m_style==style)
231
3.83k
        style=MWAWFont::Line::None;
232
233k
      font.m_font->setUnderlineStyle(style);
233
233k
      what &= 0xFB;
234
233k
    }
235
226k
    else if (val & 0xe)
236
88.4k
      f << "#underline?=" << ((val>>1) &0x7) << ",";
237
459k
    if (val & 0xF1)
238
278k
      f << "#underline[unkn]=" << std::hex << (val & 0xF1) << std::dec << ",";
239
459k
  }
240
617k
  if (what & 0x20) {
241
8.33k
    font.m_font->setColor(MWAWColor::black());
242
8.33k
    what &= 0xDF;
243
8.33k
  }
244
617k
  if (what & 0x4) {
245
40.1k
    font.m_font->setUnderlineStyle(MWAWFont::Line::None);
246
40.1k
    what &= 0xFB;
247
40.1k
  }
248
617k
  if (what & 0x2) {
249
20.0k
    font.m_font->set(MWAWFont::Script(0, librevenge::RVNG_POINT));
250
20.0k
    what &= 0xFD;
251
20.0k
  }
252
617k
  if (what & 0x1) {
253
16.2k
    font.m_font->setDeltaLetterSpacing(0);
254
16.2k
    what &= 0xFE;
255
16.2k
  }
256
617k
  font.m_unknown =what;
257
617k
  font.m_font->setFlags(flags);
258
259
617k
  bool ok = false;
260
617k
  if (mainZone && sz >= 10 && sz <= 12) {
261
176k
    auto wh = static_cast<int>(input->readULong(1));
262
176k
    long pictPos = 0;
263
705k
    for (int i = 10; i < 13; i++) {
264
529k
      pictPos <<= 8;
265
529k
      if (i <= sz) pictPos += input->readULong(1);
266
529k
    }
267
176k
    long actPos = input->tell();
268
176k
    if (m_mainParser->checkPicturePos(pictPos, wh)) {
269
47.3k
      ok = true;
270
47.3k
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
271
47.3k
      font.m_picturePos = pictPos;
272
47.3k
      f << "pictWh=" << wh << ",";
273
47.3k
    }
274
129k
    else
275
129k
      input->seek(pos+1+8, librevenge::RVNG_SEEK_SET);
276
176k
  }
277
617k
  if (!ok && sz >= 9) {
278
394k
    auto wh = static_cast<int>(input->readLong(1));
279
394k
    switch (wh) {
280
10.6k
    case -1:
281
10.6k
      ok = true;
282
10.6k
      break;
283
99.9k
    case 0: // line height ?
284
99.9k
      if (sz < 10) break;
285
90.9k
      font.m_size=float(input->readULong(1))/2.f;
286
90.9k
      ok = true;
287
90.9k
      break;
288
283k
    default:
289
283k
      break;
290
394k
    }
291
394k
  }
292
617k
  if (!ok && sz >= 9) {
293
292k
    input->seek(pos+1+8, librevenge::RVNG_SEEK_SET);
294
292k
    f << "#";
295
292k
  }
296
617k
  if (long(input->tell()) != pos+1+sz)
297
353k
    m_parserState->m_asciiFile.addDelimiter(input->tell(), '|');
298
299
617k
  input->seek(pos+1+sz, librevenge::RVNG_SEEK_SET);
300
617k
  font.m_extra = f.str();
301
617k
  return true;
302
617k
}
303
304
bool MsWrdTextStyles::getFont(ZoneType type, int id, MsWrdStruct::Font &font)
305
169k
{
306
169k
  MsWrdStruct::Font *fFont = nullptr;
307
169k
  switch (type) {
308
143k
  case TextZone:
309
143k
    if (id < 0 || id >= int(m_state->m_fontList.size()))
310
0
      break;
311
143k
    fFont = &m_state->m_fontList[size_t(id)];
312
143k
    break;
313
25.4k
  case StyleZone:
314
25.4k
    if (m_state->m_styleFontMap.find(id) == m_state->m_styleFontMap.end())
315
2.92k
      break;
316
22.5k
    fFont = &m_state->m_styleFontMap.find(id)->second;
317
22.5k
    break;
318
0
  case TextStructZone:
319
0
  case InParagraphDefinition:
320
#if !defined(__clang__)
321
  default:
322
#endif
323
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::getFont: do not know how to send this type of font\n"));
324
0
    return false;
325
169k
  }
326
169k
  if (!fFont) {
327
2.92k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::getFont: can not find font with %d[type=%d]\n", id, int(type)));
328
2.92k
    return false;
329
2.92k
  }
330
166k
  int fId = font.m_font->id();
331
166k
  float fSz = font.m_font->size();
332
166k
  font = *fFont;
333
166k
  if (font.m_font->id() < 0)
334
118k
    font.m_font->setId(fId);
335
166k
  if (font.m_font->size() <= 0)
336
120k
    font.m_font->setSize(fSz);
337
166k
  return true;
338
169k
}
339
340
void MsWrdTextStyles::setProperty(MsWrdStruct::Font const &font)
341
708k
{
342
708k
  if (!m_parserState->m_textListener) return;
343
708k
  MsWrdStruct::Font tmp = font;
344
708k
  if (tmp.m_font->id() < 0) tmp.m_font->setId(m_state->m_defaultFont.id());
345
708k
  if (tmp.m_font->size() <= 0) tmp.m_font->setSize(m_state->m_defaultFont.size());
346
708k
  tmp.updateFontToFinalState();
347
708k
  m_parserState->m_textListener->setFont(*tmp.m_font);
348
708k
}
349
350
////////////////////////////////////////////////////////////
351
// read/send the paragraph zone
352
////////////////////////////////////////////////////////////
353
bool MsWrdTextStyles::getParagraph(ZoneType type, int id, MsWrdStruct::Paragraph &para)
354
969k
{
355
969k
  switch (type) {
356
599k
  case TextZone:
357
599k
    if (id < 0 || id >= int(m_state->m_paragraphList.size()))
358
0
      break;
359
599k
    para = m_state->m_paragraphList[size_t(id)];
360
599k
    return true;
361
251k
  case StyleZone:
362
251k
    if (m_state->m_styleParagraphMap.find(id) == m_state->m_styleParagraphMap.end())
363
102k
      break;
364
148k
    para = m_state->m_styleParagraphMap.find(id)->second;
365
148k
    return true;
366
119k
  case TextStructZone:
367
119k
    if (id < 0 || id >= int(m_state->m_textstructParagraphList.size()))
368
16.9k
      break;
369
102k
    para = m_state->m_textstructParagraphList[size_t(id)];
370
102k
    return true;
371
0
  case InParagraphDefinition:
372
#if !defined(__clang__)
373
  default:
374
#endif
375
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::getParagraph: do not know how to send this type of font\n"));
376
0
    return false;
377
969k
  }
378
379
119k
  MWAW_DEBUG_MSG(("MsWrdTextStyles::getParagraph: can not find paragraph with %d[type=%d]\n", id, int(type)));
380
119k
  return false;
381
969k
}
382
383
void MsWrdTextStyles::sendDefaultParagraph()
384
0
{
385
0
  if (!m_parserState->m_textListener) return;
386
0
  m_parserState->m_textListener->setParagraph(MsWrdStruct::Paragraph(version()));
387
0
}
388
389
bool MsWrdTextStyles::readParagraph(MsWrdStruct::Paragraph &para, int dataSz)
390
2.34M
{
391
2.34M
  int sz;
392
2.34M
  MWAWInputStreamPtr &input= m_parserState->m_input;
393
2.34M
  if (dataSz >= 0)
394
2.33M
    sz = dataSz;
395
11.5k
  else
396
11.5k
    sz = static_cast<int>(input->readULong(2));
397
398
2.34M
  long pos = input->tell();
399
2.34M
  long endPos = pos+sz;
400
401
2.34M
  if (sz == 0) return true;
402
2.33M
  if (!input->checkPosition(endPos)) return false;
403
404
2.33M
  int const vers = version();
405
2.33M
  libmwaw::DebugStream f;
406
2.33M
  int numFont=0;
407
11.1M
  while (long(input->tell()) < endPos) {
408
10.8M
    long actPos = input->tell();
409
    /* 5-16: basic paragraph properties
410
       75-84: basic section properties
411
       other
412
     */
413
10.8M
    if (para.read(input,endPos)) continue;
414
5.03M
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
415
416
5.03M
    int wh = static_cast<int>(input->readULong(1)), val;
417
5.03M
    if (vers <= 3 && wh >= 0x36 && wh <= 0x45) {
418
      // this section data has different meaning in v3 and after...
419
28.5k
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
420
28.5k
      break;
421
28.5k
    }
422
5.00M
    bool done = false;
423
5.00M
    long dSz = endPos-actPos;
424
5.00M
    switch (wh) {
425
328k
    case 0:
426
328k
      done = (actPos+1==endPos||(dataSz==2 && actPos+2==endPos));
427
328k
      break;
428
54.3k
    case 0x38:
429
54.3k
      if (dSz < 4) break;
430
51.3k
      val = static_cast<int>(input->readLong(1));
431
51.3k
      if (val != 2) f << "#shadType=" <<  val << ",";
432
51.3k
      f << "shad=" << float(input->readLong(2))/100.f << "%,";
433
51.3k
      done = true;
434
51.3k
      break;
435
32.7k
    case 0x3a: // checkme: maybe plain
436
32.7k
      f << "f3a,";
437
32.7k
      done = true;
438
32.7k
      break;
439
85.5k
    case 0x4d: {
440
85.5k
      if (dSz < 2) break;
441
84.2k
      val = static_cast<int>(input->readLong(1));
442
84.2k
      para.m_modFont->m_font->set(MWAWFont::Script(float(val)/2.f,librevenge::RVNG_POINT));
443
84.2k
      if (val==0) f << "pos[y]=0,";
444
84.2k
      done = true;
445
84.2k
      break;
446
85.5k
    }
447
82.5k
    case 0x3c: // bold
448
125k
    case 0x3d: // italic?
449
163k
    case 0x3e: // strikeout (chekme)
450
212k
    case 0x3f: // outline (chekme)
451
239k
    case 0x40: // shadow (chekme)
452
290k
    case 0x41: // small caps (chekme)
453
320k
    case 0x42: // all caps (chekme)
454
421k
    case 0x43: // hidden (chekme)
455
445k
    case 0x45: // underline
456
628k
    case 0x4a: {
457
628k
      if (dSz < 2) break;
458
623k
      done = true;
459
623k
      val = static_cast<int>(input->readULong(1));
460
623k
      if (wh == 0x4a) {
461
181k
        if (val > 4 && val < 40)
462
17.7k
          para.m_modFont->m_font->setSize(float(val)/2.0f);
463
163k
        else
464
163k
          f << "#fSize=" << val << ",";
465
181k
        break;
466
181k
      }
467
441k
      switch (wh) {
468
81.9k
      case 0x3c:
469
124k
      case 0x3d:
470
162k
      case 0x3e:
471
210k
      case 0x3f:
472
236k
      case 0x40:
473
287k
      case 0x41:
474
317k
      case 0x42:
475
418k
      case 0x43:
476
418k
        para.m_modFont->m_flags[wh-0x3c]=val;
477
418k
        break;
478
23.6k
      case 0x45:
479
23.6k
        para.m_modFont->m_flags[8]=val;
480
23.6k
        break;
481
0
      default:
482
0
        break;
483
441k
      }
484
441k
      break;
485
441k
    }
486
441k
    case 0x44:
487
199k
      if (dSz < 3) break;
488
195k
      done = true;
489
195k
      val = static_cast<int>(input->readULong(2));
490
195k
      para.m_modFont->m_font->setId(val);
491
195k
      break;
492
3.11k
    case 0x2: // a small number between 0 and 4
493
113k
    case 0x34: // 0 ( one time)
494
162k
    case 0x39: // 0 ( one time)
495
290k
    case 0x47: // 0 one time
496
335k
    case 0x49: // 0 ( one time)
497
408k
    case 0x4c: // 0, 6, -12
498
439k
    case 0x5e: // 0
499
439k
      if (dSz < 2) break;
500
432k
      done = true;
501
432k
      val = static_cast<int>(input->readLong(1));
502
432k
      f << "f" << std::hex << wh << std::dec << "=" << val << ",";
503
432k
      break;
504
122k
    case 0x23: // alway 0 ?
505
122k
      if (dSz < 3) break;
506
101k
      done = true;
507
101k
      val = static_cast<int>(input->readLong(2));
508
101k
      f << "f" << std::hex << wh << std::dec << "=" << val << ",";
509
101k
      break;
510
26.6k
    case 0x9f: // two small number: table range?
511
26.6k
      if (dSz < 3) break;
512
24.6k
      done = true;
513
24.6k
      f << "f" << std::hex << wh << "=[";
514
74.0k
      for (int i = 0; i < 2; i++)
515
49.3k
        f << input->readULong(1) << ",";
516
24.6k
      f << std::dec << "],";
517
24.6k
      break;
518
49.5k
    case 0x50: // two small number
519
49.5k
      if (dSz < 4) break;
520
45.6k
      done = true;
521
45.6k
      f << "f" << std::hex << wh << std::dec << "=[";
522
45.6k
      f << input->readLong(1) << ",";
523
45.6k
      f << input->readLong(2) << ",";
524
45.6k
      f << "],";
525
45.6k
      break;
526
1.07M
    case 0x4f: // a small int and a pos?
527
1.07M
      if (dSz < 4) break;
528
1.05M
      done = true;
529
1.05M
      f << "f" << std::hex << wh << std::dec << "=[";
530
1.05M
      f << input->readLong(1) << ",";
531
1.05M
      f << std::hex << input->readULong(2) << std::dec << "],";
532
1.05M
      break;
533
20.4k
    case 0x9e: // two small number + a pos?
534
20.4k
      if (dSz < 5) break;
535
18.8k
      done = true;
536
18.8k
      f << "f" << std::hex << wh << std::dec << "=[";
537
56.4k
      for (int i = 0; i < 2; i++)
538
37.6k
        f << input->readLong(1) << ",";
539
18.8k
      f << std::hex << input->readULong(2) << std::dec << "],";
540
18.8k
      break;
541
142k
    case 0x4e:
542
187k
    case 0x53: { // same as 4e ( new format )
543
      // checkme: sometimes, we can have a list of font, do we need to
544
      // use only the last one?
545
187k
      if (numFont++)
546
17.2k
        f << "#font" << numFont-1 << "=["
547
17.2k
          << para.m_font->m_font->getDebugString(m_parserState->m_fontConverter)
548
17.2k
          << "," << *para.m_font << "],";
549
187k
      done = true;
550
187k
      para.m_font = MsWrdStruct::Font();
551
187k
      if (!readFont(*para.m_font, InParagraphDefinition) || long(input->tell()) > endPos) {
552
131k
        done = false;
553
131k
        f << "#";
554
131k
        break;
555
131k
      }
556
56.7k
      break;
557
187k
    }
558
213k
    case 0x5f: { // 4 index
559
213k
      if (dSz < 10) break;
560
207k
      done = true;
561
207k
      sz = static_cast<int>(input->readULong(1));
562
207k
      if (sz != 8) f << "#sz=" << sz << ",";
563
207k
      f << "f5f=[";
564
1.03M
      for (int i = 0; i < 4; i++) f << input->readLong(2) << ",";
565
207k
      f << "],";
566
207k
      break;
567
213k
    }
568
37.1k
    case 0x94: // checkme space between column divided by 2 (in table) ?
569
37.1k
      if (dSz < 3) break;
570
35.7k
      done = true;
571
35.7k
      val = static_cast<int>(input->readLong(2));
572
35.7k
      f << "colSep[table]=" << 2*val/1440. << ",";
573
35.7k
      break;
574
1.50M
    default:
575
1.50M
      break;
576
5.00M
    }
577
5.00M
    if (!done) {
578
1.98M
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
579
1.98M
      break;
580
1.98M
    }
581
5.00M
  }
582
2.33M
  if (long(input->tell()) != endPos) {
583
2.01M
    static bool first = true;
584
2.01M
    if (first) {
585
25
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readParagraph: can not read end of paragraph\n"));
586
25
      first = false;
587
25
    }
588
2.01M
    libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
589
2.01M
    ascFile.addDelimiter(input->tell(),'|');
590
2.01M
    f << "####";
591
2.01M
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
592
2.01M
  }
593
2.33M
  para.m_extra += f.str();
594
595
2.33M
  return true;
596
2.33M
}
597
598
////////////////////////////////////////////////////////////
599
// read the char/parag plc
600
////////////////////////////////////////////////////////////
601
bool MsWrdTextStyles::readPLCList(MsWrdEntry const &entry)
602
56.4k
{
603
56.4k
  if (entry.length() < 10 || (entry.length()%6) != 4) {
604
6.80k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLCList: the zone size seems odd\n"));
605
6.80k
    return false;
606
6.80k
  }
607
49.5k
  long pos = entry.begin();
608
49.5k
  entry.setParsed(true);
609
49.5k
  MWAWInputStreamPtr &input= m_parserState->m_input;
610
49.5k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
611
49.5k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
612
49.5k
  libmwaw::DebugStream f;
613
49.5k
  f << entry.type() << ":";
614
49.5k
  auto N=int(entry.length()/6);
615
49.5k
  std::vector<long> textPos; // limit of the text in the file
616
49.5k
  textPos.resize(size_t(N)+1);
617
11.1M
  for (auto &tPos : textPos) tPos = long(input->readULong(4));
618
49.5k
  int const expectedSize = (version() <= 3) ? 0x80 : 0x200;
619
11.1M
  for (int i = 0; i < N; i++) {
620
11.0M
    if (!input->checkPosition(textPos[size_t(i)])) f << "#";
621
622
11.0M
    auto defPos = long(input->readULong(2));
623
11.0M
    f << std::hex << "[filePos?=" << textPos[size_t(i)] << ",dPos=" << defPos << std::dec << ",";
624
11.0M
    f << "],";
625
626
11.0M
    MsWrdEntry plc;
627
11.0M
    plc.setType(entry.id() ? "ParagPLC" : "CharPLC");
628
11.0M
    plc.setId(i);
629
11.0M
    plc.setBegin(defPos *expectedSize);
630
11.0M
    plc.setLength(expectedSize);
631
11.0M
    if (!input->checkPosition(plc.end())) {
632
6.55M
      f << "#PLC,";
633
6.55M
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLCList: plc def is outside the file\n"));
634
6.55M
    }
635
4.51M
    else {
636
4.51M
      long actPos = input->tell();
637
4.51M
      MWAWVec2<long> fLimit(textPos[size_t(i)], textPos[size_t(i)+1]);
638
4.51M
      readPLC(plc, entry.id(), fLimit);
639
4.51M
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
640
4.51M
    }
641
11.0M
  }
642
49.5k
  f << std::hex << "end?=" << textPos[size_t(N)] << ",";
643
644
49.5k
  ascFile.addPos(pos);
645
49.5k
  ascFile.addNote(f.str().c_str());
646
647
49.5k
  ascFile.addPos(entry.end());
648
49.5k
  ascFile.addNote("_");
649
49.5k
  return true;
650
56.4k
}
651
652
bool MsWrdTextStyles::readPLC(MsWrdEntry &entry, int type, MWAWVec2<long> const &fLimit)
653
4.75M
{
654
4.75M
  int const vers = version();
655
4.75M
  int const expectedSize = (vers <= 3) ? 0x80 : 0x200;
656
4.75M
  int const posFactor = (vers <= 3) ? 1 : 2;
657
4.75M
  if (entry.length() != expectedSize) {
658
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: the zone size seems odd\n"));
659
0
    return false;
660
0
  }
661
4.75M
  MWAWInputStreamPtr &input= m_parserState->m_input;
662
4.75M
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
663
4.75M
  auto N=static_cast<int>(input->readULong(1));
664
4.75M
  if (N==0 || 5*(N+1) > entry.length()) {
665
3.03M
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: the number of plc seems odd\n"));
666
3.03M
    return false;
667
3.03M
  }
668
669
1.71M
  long pos = entry.begin();
670
1.71M
  entry.setParsed(true);
671
1.71M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
672
1.71M
  libmwaw::DebugStream f;
673
1.71M
  f << "Entries("<< entry.type() << ")[" << entry.id() << "]:N=" << N << ",";
674
675
1.71M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
676
1.71M
  std::vector<long> filePos;
677
1.71M
  filePos.resize(size_t(N)+1);
678
59.6M
  for (auto &fPos : filePos) fPos = long(input->readULong(4));
679
1.71M
  if (filePos[0] != fLimit[0]) {
680
1.42M
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: bad first limit\n"));
681
1.42M
    return false;
682
1.42M
  }
683
298k
  std::map<int, int> mapPosId;
684
298k
  std::vector<int> decal;
685
298k
  decal.resize(size_t(N));
686
298k
  size_t numData = type == 0 ? m_state->m_fontList.size() :
687
298k
                   m_state->m_paragraphList.size();
688
298k
  auto plcType = type == 0 ? MsWrdText::PLC::Font : MsWrdText::PLC::Paragraph;
689
298k
  auto &plcMap = m_textParser->getFilePLCMap();
690
691
9.81M
  for (size_t i = 0; i < size_t(N); i++) {
692
9.51M
    decal[i] = static_cast<int>(input->readULong(1));
693
9.51M
    int id = -1;
694
9.51M
    if (decal[i]) {
695
7.46M
      if (mapPosId.find(decal[i]) != mapPosId.end())
696
3.66M
        id = mapPosId.find(decal[i])->second;
697
3.79M
      else {
698
3.79M
        id = int(numData++);
699
3.79M
        mapPosId[decal[i]] = id;
700
701
3.79M
        long actPos = input->tell();
702
3.79M
        libmwaw::DebugStream f2;
703
3.79M
        f2 << entry.type() << "-";
704
705
3.79M
        long dataPos = entry.begin()+posFactor*decal[i];
706
3.79M
        if (type == 0) {
707
943k
          input->seek(dataPos, librevenge::RVNG_SEEK_SET);
708
943k
          f2 << "F" << id << ":";
709
943k
          MsWrdStruct::Font font;
710
943k
          if (!readFont(font, TextZone)) {
711
310k
            font = MsWrdStruct::Font();
712
310k
            f2 << "#";
713
310k
          }
714
632k
          else
715
632k
            f2 << font.m_font->getDebugString(m_parserState->m_fontConverter) << font << ",";
716
943k
          m_state->m_fontList.push_back(font);
717
943k
        }
718
2.85M
        else {
719
2.85M
          MsWrdStruct::Paragraph para(vers);
720
2.85M
          f2 << "P" << id << ":";
721
722
2.85M
          input->seek(dataPos, librevenge::RVNG_SEEK_SET);
723
2.85M
          auto sz = static_cast<int>(input->readLong(1));
724
2.85M
          long endPos;
725
2.85M
          if (vers <= 3) {
726
529k
            sz++;
727
529k
            endPos = dataPos+sz;
728
529k
          }
729
2.32M
          else
730
2.32M
            endPos = dataPos+2*sz+1;
731
2.85M
          if (sz < 4 || endPos > entry.end()) {
732
1.18M
            MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: can not read plcSz\n"));
733
1.18M
            f2 << "#";
734
1.18M
          }
735
1.66M
          else {
736
1.66M
            auto stId = static_cast<int>(input->readLong(1));
737
1.66M
            if (m_state->m_styleParagraphMap.find(stId)==m_state->m_styleParagraphMap.end()) {
738
1.60M
              MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: can not find parent paragraph\n"));
739
1.60M
              f2 << "#";
740
1.60M
            }
741
65.8k
            else
742
65.8k
              para.m_styleId = stId;
743
1.66M
            f2 << "sP" << stId << ",";
744
1.66M
            if (vers > 3) {
745
1.35M
              if (!para.m_info->read(input, endPos, vers)) {
746
0
                f2 << "###info,";
747
0
                input->seek(dataPos+2+6, librevenge::RVNG_SEEK_SET);
748
0
              }
749
              // osnole: do we need to check here if the paragraph is empty ?
750
              // ie. if (para.m_info->isEmpty()&&stId==0)
751
1.35M
            }
752
309k
            else {   // always 0 ?
753
309k
              auto val = static_cast<int>(input->readLong(2));
754
309k
              if (val) f << "g0=" << val << ",";
755
309k
            }
756
1.66M
            ascFile.addDelimiter(input->tell(),'|');
757
1.66M
            if (readParagraph(para, int(endPos-input->tell()))) {
758
#ifdef DEBUG_WITH_FILES
759
              para.print(f2, m_parserState->m_fontConverter);
760
#endif
761
1.66M
            }
762
0
            else {
763
0
              para = MsWrdStruct::Paragraph(vers);
764
0
              f2 << "#";
765
0
            }
766
1.66M
          }
767
2.85M
          m_state->m_paragraphList.push_back(para);
768
2.85M
        }
769
3.79M
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
770
3.79M
        ascFile.addPos(dataPos);
771
3.79M
        ascFile.addNote(f2.str().c_str());
772
3.79M
      }
773
7.46M
    }
774
9.51M
    f << std::hex << filePos[i] << std::dec;
775
9.51M
    MsWrdText::PLC plc(plcType, id);
776
9.51M
    plcMap.insert(std::multimap<long, MsWrdText::PLC>::value_type
777
9.51M
                  (filePos[type == 0 ? i : i+1], plc));
778
9.51M
    if (id >= 0) {
779
7.46M
      if (type==0) f << ":F" << id;
780
6.00M
      else f << ":P" << id;
781
7.46M
    }
782
9.51M
    f << ",";
783
9.51M
  }
784
785
298k
  ascFile.addPos(pos);
786
298k
  ascFile.addNote(f.str().c_str());
787
788
298k
  ascFile.addPos(entry.end());
789
298k
  ascFile.addNote("_");
790
298k
  if (filePos[size_t(N)] != fLimit[1]) {
791
242k
    if (input->isEnd()) {
792
0
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readPLC: we are already at the end of the stream\n"));
793
0
      return false;
794
0
    }
795
242k
    MsWrdEntry nextEntry(entry);
796
242k
    nextEntry.setBegin(entry.begin()+expectedSize);
797
242k
    MWAWVec2<long> newLimit(filePos[size_t(N)], fLimit[1]);
798
242k
    readPLC(nextEntry,type,newLimit);
799
242k
  }
800
298k
  return true;
801
298k
}
802
803
////////////////////////////////////////////////////////////
804
// read the text structure
805
////////////////////////////////////////////////////////////
806
bool MsWrdTextStyles::readTextStructList(MsWrdEntry &entry)
807
11.6k
{
808
11.6k
  if (entry.length() < 19) {
809
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readTextStructList: the zone seems to short\n"));
810
0
    return false;
811
0
  }
812
11.6k
  int const vers = version();
813
11.6k
  long pos = entry.begin();
814
11.6k
  MWAWInputStreamPtr &input= m_parserState->m_input;
815
11.6k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
816
11.6k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
817
11.6k
  libmwaw::DebugStream f;
818
11.6k
  auto type = static_cast<int>(input->readLong(1));
819
11.6k
  if (type != 1 && type != 2) {
820
3.60k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readTextStructList: find odd type %d\n", type));
821
3.60k
    return false;
822
3.60k
  }
823
824
8.07k
  int num = 0;
825
18.6k
  while (type == 1) {
826
    /* probably a paragraph definition. Fixme: create a function */
827
11.6k
    auto length = static_cast<int>(input->readULong(2));
828
11.6k
    long endPos = pos+3+length;
829
11.6k
    if (endPos > entry.end()) {
830
113
      ascFile.addPos(pos);
831
113
      ascFile.addNote("TextStruct[paragraph]#");
832
113
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readTextStructList: zone(paragraph) is too big\n"));
833
113
      return false;
834
113
    }
835
11.5k
    f.str("");
836
11.5k
    f << "ParagPLC:tP" << num++<< "]:";
837
11.5k
    MsWrdStruct::Paragraph para(vers);
838
11.5k
    input->seek(-2,librevenge::RVNG_SEEK_CUR);
839
11.5k
    if (readParagraph(para) && long(input->tell()) <= endPos) {
840
#ifdef DEBUG_WITH_FILES
841
      para.print(f, m_parserState->m_fontConverter);
842
#endif
843
11.5k
    }
844
0
    else {
845
0
      para = MsWrdStruct::Paragraph(vers);
846
0
      f << "#";
847
0
    }
848
11.5k
    m_state->m_textstructParagraphList.push_back(para);
849
11.5k
    ascFile.addPos(pos);
850
11.5k
    ascFile.addNote(f.str().c_str());
851
11.5k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
852
853
11.5k
    pos = input->tell();
854
11.5k
    type = static_cast<int>(input->readULong(1));
855
11.5k
    if (type == 2) break;
856
10.7k
    if (type != 1) {
857
176
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readTextStructList: find odd type %d\n", type));
858
176
      return false;
859
176
    }
860
10.7k
  }
861
7.78k
  input->seek(-1,librevenge::RVNG_SEEK_CUR);
862
7.78k
  return true;
863
8.07k
}
864
865
int MsWrdTextStyles::readPropertyModifier(bool &complex, std::string &extra)
866
1.06M
{
867
1.06M
  MWAWInputStreamPtr &input= m_parserState->m_input;
868
1.06M
  long pos = input->tell();
869
1.06M
  auto c = static_cast<int>(input->readULong(1));
870
1.06M
  complex = false;
871
1.06M
  if (c&0x80) { // complex data, let get the id
872
176k
    complex=true;
873
176k
    return ((c&0x7F)<<8)|static_cast<int>(input->readULong(1));
874
176k
  }
875
884k
  if (c==0) {
876
433k
    input->seek(pos+2, librevenge::RVNG_SEEK_SET);
877
433k
    return -1;
878
433k
  }
879
450k
  int id = -1;
880
450k
  libmwaw::DebugStream f;
881
450k
  MsWrdStruct::Paragraph para(version());
882
450k
  input->seek(-1, librevenge::RVNG_SEEK_CUR);
883
450k
  if (readParagraph(para, 2)) {
884
450k
    id = int(m_state->m_textstructParagraphList.size());
885
450k
    m_state->m_textstructParagraphList.push_back(para);
886
#ifdef DEBUG_WITH_FILES
887
    f << "[";
888
    para.print(f, m_parserState->m_fontConverter);
889
    f << "]";
890
#endif
891
450k
  }
892
0
  else {
893
0
    input->seek(pos+1, librevenge::RVNG_SEEK_SET);
894
0
    f << "#f" << std::hex << c << std::dec << "=" << static_cast<int>(input->readULong(1));
895
0
  }
896
450k
  extra = f.str();
897
450k
  input->seek(pos+2, librevenge::RVNG_SEEK_SET);
898
450k
  return id;
899
884k
}
900
901
////////////////////////////////////////////////////////////
902
// read/send the section zone
903
////////////////////////////////////////////////////////////
904
bool MsWrdTextStyles::getSection(ZoneType type, int id, MsWrdStruct::Section &section)
905
0
{
906
0
  switch (type) {
907
0
  case TextZone:
908
0
    if (id < 0 || id >= int(m_state->m_sectionList.size()))
909
0
      break;
910
0
    section = m_state->m_sectionList[size_t(id)];
911
0
    return true;
912
0
  case StyleZone:
913
0
  case TextStructZone:
914
0
  case InParagraphDefinition:
915
#if !defined(__clang__)
916
  default:
917
#endif
918
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::getSection do not know how to get this type of section\n"));
919
0
    return false;
920
0
  }
921
0
  MWAW_DEBUG_MSG(("MsWrdTextStyles::getSection can not find this section\n"));
922
0
  return false;
923
0
}
924
925
bool MsWrdTextStyles::getSectionParagraph(ZoneType type, int id, MsWrdStruct::Paragraph &para)
926
0
{
927
0
  MsWrdStruct::Section sec;
928
0
  if (!getSection(type, id, sec)) return false;
929
0
  if (!sec.m_paragraphId.isSet()) return false;
930
0
  return getParagraph(StyleZone, *sec.m_paragraphId, para);
931
0
}
932
933
bool MsWrdTextStyles::getSectionFont(ZoneType type, int id, MsWrdStruct::Font &font)
934
0
{
935
0
  MsWrdStruct::Section sec;
936
0
  if (!getSection(type, id, sec)) return false;
937
938
0
  if (!sec.m_paragraphId.isSet()) return false;
939
0
  MsWrdStruct::Paragraph para(version());
940
0
  if (!getParagraph(StyleZone, *sec.m_paragraphId, para))
941
0
    return false;
942
943
0
  if (para.m_font.isSet())
944
0
    font = para.m_font.get();
945
0
  else
946
0
    return false;
947
0
  return true;
948
0
}
949
950
951
bool MsWrdTextStyles::readSection(MsWrdEntry &entry, std::vector<long> &cLimits)
952
13.7k
{
953
13.7k
  if (entry.length() < 14 || (entry.length()%10) != 4) {
954
3.24k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readSection: the zone size seems odd\n"));
955
3.24k
    return false;
956
3.24k
  }
957
10.4k
  long pos = entry.begin();
958
10.4k
  entry.setParsed(true);
959
10.4k
  MWAWInputStreamPtr &input= m_parserState->m_input;
960
10.4k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
961
10.4k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
962
10.4k
  libmwaw::DebugStream f;
963
10.4k
  f << "Section:";
964
10.4k
  auto N=size_t(entry.length()/10);
965
10.4k
  cLimits.resize(N+1);
966
4.08M
  for (auto &limit : cLimits) limit = long(input->readULong(4));
967
968
10.4k
  MsWrdText::PLC plc(MsWrdText::PLC::Section);
969
10.4k
  auto &plcMap = m_textParser->getTextPLCMap();
970
10.4k
  long textLength = m_textParser->getMainTextLength();
971
4.08M
  for (size_t i = 0; i < N; i++) {
972
4.07M
    MsWrdStruct::Section sec;
973
4.07M
    sec.m_type = static_cast<int>(input->readULong(1)); // 0|40|80|C0
974
4.07M
    sec.m_flag = static_cast<int>(input->readULong(1)); // number between 2 and 7
975
4.07M
    sec.m_id = int(i);
976
4.07M
    unsigned long filePos = input->readULong(4);
977
4.07M
    if (textLength && cLimits[i] > textLength) {
978
1.32M
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readSection: text positions is bad...\n"));
979
1.32M
      f << "#";
980
1.32M
    }
981
2.74M
    else {
982
2.74M
      plc.m_id = int(i);
983
2.74M
      plcMap.insert(std::multimap<long, MsWrdText::PLC>::value_type(cLimits[i],plc));
984
2.74M
    }
985
4.07M
    f << std::hex << "cPos=" << cLimits[i] << ":[" << sec << ",";
986
4.07M
    if (filePos != 0xFFFFFFFFL) {
987
3.98M
      f << "pos=" << std::hex << filePos << std::dec << ",";
988
3.98M
      long actPos = input->tell();
989
3.98M
      readSection(sec,long(filePos));
990
3.98M
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
991
3.98M
    }
992
4.07M
    f << "],";
993
994
4.07M
    m_state->m_sectionList.push_back(sec);
995
4.07M
  }
996
10.4k
  ascFile.addPos(pos);
997
10.4k
  ascFile.addNote(f.str().c_str());
998
999
10.4k
  ascFile.addPos(entry.end());
1000
10.4k
  ascFile.addNote("_");
1001
10.4k
  return true;
1002
13.7k
}
1003
1004
bool MsWrdTextStyles::readSection(MsWrdStruct::Section &sec, long debPos)
1005
3.98M
{
1006
3.98M
  MWAWInputStreamPtr &input= m_parserState->m_input;
1007
3.98M
  if (!input->checkPosition(debPos)) {
1008
2.83M
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readSection: can not find section data...\n"));
1009
2.83M
    return false;
1010
2.83M
  }
1011
1.14M
  int const vers = version();
1012
1.14M
  input->seek(debPos, librevenge::RVNG_SEEK_SET);
1013
1.14M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1014
1.14M
  libmwaw::DebugStream f;
1015
1.14M
  auto sz = static_cast<int>(input->readULong(1));
1016
1.14M
  long endPos = debPos+sz+1;
1017
1.14M
  if (sz < 1 || sz >= 255) {
1018
226k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readSection: data section size seems bad...\n"));
1019
226k
    f << "Section-" << sec.m_id.get() << ":#" << sec;
1020
226k
    ascFile.addPos(debPos);
1021
226k
    ascFile.addNote(f.str().c_str());
1022
226k
    return false;
1023
226k
  }
1024
1.54M
  while (input->tell() < endPos) {
1025
1.53M
    long pos = input->tell();
1026
1.53M
    bool ok;
1027
1.53M
    if (vers <= 3)
1028
783k
      ok = sec.readV3(input, endPos);
1029
750k
    else
1030
750k
      ok = sec.read(input, endPos);
1031
1.53M
    if (ok) continue;
1032
914k
    f << "#";
1033
914k
    ascFile.addDelimiter(pos,'|');
1034
914k
    break;
1035
1.53M
  }
1036
921k
  f << "Section-S" << sec.m_id.get() << ":" << sec;
1037
921k
  ascFile.addPos(debPos);
1038
921k
  ascFile.addNote(f.str().c_str());
1039
1040
921k
  ascFile.addPos(endPos);
1041
921k
  ascFile.addNote("_");
1042
921k
  return true;
1043
1.14M
}
1044
1045
void MsWrdTextStyles::setProperty(MsWrdStruct::Section const &sec)
1046
61.8k
{
1047
61.8k
  MWAWTextListenerPtr listener=m_parserState->m_textListener;
1048
61.8k
  if (!listener) return;
1049
61.8k
  if (listener->isHeaderFooterOpened()) {
1050
7.55k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::setProperty: can not open a section in header/footer\n"));
1051
7.55k
  }
1052
54.3k
  else {
1053
54.3k
    int numCols = sec.m_col.get();
1054
54.3k
    int actCols = listener->getSection().numColumns();
1055
54.3k
    if (numCols >= 1 && actCols > 1 && sec.m_colBreak.get()) {
1056
84
      if (!listener->isSectionOpened()) {
1057
0
        MWAW_DEBUG_MSG(("MsWrdTextStyles::setProperty: section is not opened\n"));
1058
0
      }
1059
84
      else
1060
84
        listener->insertBreak(MWAWTextListener::ColumnBreak);
1061
84
    }
1062
54.2k
    else {
1063
54.2k
      if (listener->isSectionOpened())
1064
48.8k
        listener->closeSection();
1065
54.2k
      listener->openSection(sec.getSection(m_mainParser->getPageWidth()));
1066
54.2k
    }
1067
54.3k
  }
1068
61.8k
}
1069
1070
bool MsWrdTextStyles::sendSection(int id, int textStructId)
1071
61.8k
{
1072
61.8k
  if (!m_parserState->m_textListener) return true;
1073
1074
61.8k
  if (id < 0 || id >= int(m_state->m_sectionList.size())) {
1075
0
    MWAW_DEBUG_MSG(("MsWrdTextStyles::sendText: can not find new section\n"));
1076
0
    return false;
1077
0
  }
1078
61.8k
  auto section=m_state->m_sectionList[size_t(id)];
1079
61.8k
  MsWrdStruct::Paragraph para(version());
1080
61.8k
  if (textStructId >= 0 &&
1081
13.4k
      getParagraph(MsWrdTextStyles::TextStructZone, textStructId, para) &&
1082
7.10k
      para.m_section.isSet()) {
1083
245
    section.insert(*para.m_section);
1084
245
  }
1085
61.8k
  setProperty(section);
1086
61.8k
  return true;
1087
61.8k
}
1088
1089
////////////////////////////////////////////////////////////
1090
// read the styles
1091
////////////////////////////////////////////////////////////
1092
std::map<int, int> const &MsWrdTextStyles::getNextStyleMap() const
1093
0
{
1094
0
  return m_state->m_nextStyleMap;
1095
0
}
1096
1097
bool MsWrdTextStyles::readStyles(MsWrdEntry &entry)
1098
11.9k
{
1099
11.9k
  if (entry.length() < 6) {
1100
322
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readStyles: zone seems to short...\n"));
1101
322
    return false;
1102
322
  }
1103
11.5k
  m_state->m_styleFontMap.clear();
1104
11.5k
  m_state->m_styleParagraphMap.clear();
1105
11.5k
  m_state->m_nextStyleMap.clear();
1106
11.5k
  entry.setParsed(true);
1107
11.5k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1108
11.5k
  ascFile.addPos(entry.end());
1109
11.5k
  ascFile.addNote("_");
1110
1111
11.5k
  long pos = entry.begin();
1112
11.5k
  libmwaw::DebugStream f;
1113
11.5k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1114
11.5k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1115
11.5k
  f << entry << ":";
1116
11.5k
  auto N = static_cast<int>(input->readLong(2));
1117
11.5k
  if (N) f << "N?=" << N;
1118
11.5k
  ascFile.addPos(pos);
1119
11.5k
  ascFile.addNote(f.str().c_str());
1120
1121
  // first find the different zone
1122
11.5k
  long debPos[4];
1123
11.5k
  int const overOk[3]= {0,30,100}; // name, font, paragraph
1124
35.3k
  for (int st = 0; st < 3; st++) {
1125
27.5k
    debPos[st] = input->tell();
1126
27.5k
    auto dataSz = static_cast<int>(input->readULong(2));
1127
27.5k
    long endPos = debPos[st]+dataSz;
1128
27.5k
    if (dataSz < 2+N || endPos > entry.end()+overOk[st]) {
1129
3.85k
      ascFile.addPos(pos);
1130
3.85k
      ascFile.addNote("###Styles(bad)");
1131
3.85k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStyles: can not read styles(%d)...\n", st));
1132
3.85k
      return false;
1133
3.85k
    }
1134
23.7k
    if (endPos > entry.end()) {
1135
6.71k
      entry.setEnd(endPos+1);
1136
6.71k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStyles(%d): size seems incoherent...\n", st));
1137
6.71k
      f.str("");
1138
6.71k
      f << "#sz=" << dataSz << ",";
1139
6.71k
      ascFile.addPos(debPos[st]);
1140
6.71k
      ascFile.addNote(f.str().c_str());
1141
6.71k
    }
1142
23.7k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1143
23.7k
  }
1144
7.73k
  debPos[3] = input->tell();
1145
  // read the styles parents
1146
7.73k
  std::vector<int> orig, order;
1147
7.73k
  if (readStylesHierarchy(entry, N, orig))
1148
7.40k
    order=orderStyles(orig);
1149
1150
7.73k
  int N1=0;
1151
7.73k
  MsWrdEntry zone;
1152
7.73k
  zone.setBegin(debPos[0]);
1153
7.73k
  zone.setEnd(debPos[1]);
1154
7.73k
  if (!readStylesNames(zone, N, N1)) {
1155
809
    N1=int(orig.size())-N;
1156
809
    if (N1 < 0)
1157
39
      return false;
1158
809
  }
1159
  // ok, repair orig, and order if need
1160
7.69k
  if (int(orig.size()) < N+N1)
1161
1.17k
    orig.resize(size_t(N+N1), -1000);
1162
7.69k
  if (int(order.size()) < N+N1) {
1163
391k
    for (auto i = int(order.size()); i < N+N1; i++)
1164
389k
      order.push_back(i);
1165
1.17k
  }
1166
7.69k
  zone.setBegin(debPos[1]);
1167
7.69k
  zone.setEnd(debPos[2]);
1168
7.69k
  readStylesFont(zone, N, orig, order);
1169
1170
7.69k
  zone.setBegin(debPos[2]);
1171
7.69k
  zone.setEnd(debPos[3]);
1172
7.69k
  readStylesParagraph(zone, N, orig, order);
1173
7.69k
  return true;
1174
7.73k
}
1175
1176
bool MsWrdTextStyles::readStylesNames(MsWrdEntry const &zone, int N, int &Nnamed)
1177
7.73k
{
1178
7.73k
  long pos = zone.begin();
1179
7.73k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1180
7.73k
  if (!zone.valid() || !input || !input->checkPosition(zone.end())) {
1181
70
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesNames: zone(names) seems to short...\n"));
1182
70
    return false;
1183
70
  }
1184
7.66k
  input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1185
7.66k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1186
7.66k
  libmwaw::DebugStream f;
1187
7.66k
  f << "Styles(names):";
1188
7.66k
  int actN=0;
1189
791k
  while (long(input->tell()) < zone.end()) {
1190
788k
    auto sz = static_cast<int>(input->readULong(1));
1191
788k
    if (sz == 0) {
1192
491k
      f << "*";
1193
491k
      actN++;
1194
491k
      continue;
1195
491k
    }
1196
297k
    if (sz == 0xFF) {
1197
59.9k
      f << "_";
1198
59.9k
      actN++;
1199
59.9k
      continue;
1200
59.9k
    }
1201
237k
    pos = input->tell();
1202
237k
    if (pos+sz > zone.end()) {
1203
4.85k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesNames: zone(names) seems to short...\n"));
1204
4.85k
      f << "#";
1205
4.85k
      ascFile.addNote(f.str().c_str());
1206
4.85k
      input->seek(pos-1, librevenge::RVNG_SEEK_SET);
1207
4.85k
      break;
1208
4.85k
    }
1209
232k
    std::string s("");
1210
6.08M
    for (int i = 0; i < sz; i++) s += char(input->readULong(1));
1211
232k
    f << "N" << actN-N << "=" ;
1212
232k
    f << s << ",";
1213
232k
    actN++;
1214
232k
  }
1215
7.66k
  Nnamed=actN-N;
1216
7.66k
  if (Nnamed < 0) {
1217
739
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesNames: zone(names) seems to short: stop...\n"));
1218
739
    f << "#";
1219
739
  }
1220
7.66k
  ascFile.addPos(zone.begin());
1221
7.66k
  ascFile.addNote(f.str().c_str());
1222
7.66k
  return Nnamed >= 0;
1223
7.73k
}
1224
1225
bool MsWrdTextStyles::readStylesFont
1226
(MsWrdEntry &zone, int N, std::vector<int> const &previous, std::vector<int> const &order)
1227
7.69k
{
1228
7.69k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1229
7.69k
  libmwaw::DebugStream f;
1230
7.69k
  long pos = zone.begin();
1231
7.69k
  ascFile.addPos(pos);
1232
7.69k
  ascFile.addNote("Styles(font):");
1233
1234
7.69k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1235
7.69k
  input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1236
7.69k
  size_t numElt = order.size();
1237
7.69k
  std::vector<long> debPos;
1238
7.69k
  std::vector<int> dataSize;
1239
7.69k
  debPos.resize(numElt, 0);
1240
7.69k
  dataSize.resize(numElt, 0);
1241
572k
  for (size_t i = 0; i < numElt; i++) {
1242
570k
    pos = input->tell();
1243
570k
    debPos[i] = pos;
1244
570k
    int sz = dataSize[i] = static_cast<int>(input->readULong(1));
1245
570k
    if (sz == 0xFF)
1246
49.5k
      sz = 0;
1247
520k
    else if (pos+1+sz > zone.end()) {
1248
5.94k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesFont: can not read a font\n"));
1249
5.94k
      if (i == 0)
1250
858
        return false;
1251
5.08k
      numElt = i-1;
1252
5.08k
      break;
1253
5.94k
    }
1254
564k
    if (sz)
1255
224k
      input->seek(sz, librevenge::RVNG_SEEK_CUR);
1256
339k
    else {
1257
339k
      f.str("");
1258
339k
      f << "CharPLC(sF" << int(i)-N << "):";
1259
339k
      ascFile.addPos(pos);
1260
339k
      ascFile.addNote(f.str().c_str());
1261
339k
    }
1262
564k
  }
1263
1264
115M
  for (auto id : order) {
1265
115M
    if (id < 0 || id >= int(numElt)) continue;
1266
559k
    int prevId = previous[size_t(id)];
1267
559k
    MsWrdStruct::Font font;
1268
    // osnola:what is the difference between dataSize[(size_t)id]=0|0xFF
1269
559k
    if (prevId >= 0 && m_state->m_styleFontMap.find(prevId-N) != m_state->m_styleFontMap.end())
1270
390k
      font = m_state->m_styleFontMap.find(prevId-N)->second;
1271
559k
    if (dataSize[size_t(id)] && dataSize[size_t(id)] != 0xFF) {
1272
223k
      input->seek(debPos[size_t(id)], librevenge::RVNG_SEEK_SET);
1273
1274
223k
      f.str("");
1275
223k
      f << "CharPLC(sF" << id-int(N) << "):";
1276
223k
      if (!readFont(font, StyleZone)) f << "#";
1277
156k
      else if (id==int(N)) m_state->m_defaultFont=font.m_font.get();
1278
223k
      f << "font=[" << font.m_font->getDebugString(m_parserState->m_fontConverter) << font << "],";
1279
223k
      ascFile.addPos(debPos[size_t(id)]);
1280
223k
      ascFile.addNote(f.str().c_str());
1281
223k
    }
1282
559k
    m_state->m_styleFontMap.insert(std::map<int, MsWrdStruct::Font>::value_type(id-N,font));
1283
559k
  }
1284
6.83k
  return true;
1285
7.69k
}
1286
1287
bool MsWrdTextStyles::readStylesParagraph(MsWrdEntry &zone, int N, std::vector<int> const &previous,
1288
    std::vector<int> const &order)
1289
7.69k
{
1290
7.69k
  int const vers=version();
1291
7.69k
  int minSz = vers <= 3 ? 3 : 7;
1292
7.69k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1293
7.69k
  libmwaw::DebugStream f;
1294
7.69k
  long pos = zone.begin();
1295
7.69k
  ascFile.addPos(pos);
1296
7.69k
  ascFile.addNote("Styles(paragraph):");
1297
1298
7.69k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1299
7.69k
  input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1300
7.69k
  size_t numElt = order.size();
1301
7.69k
  std::vector<long> debPos;
1302
7.69k
  std::vector<int> dataSize;
1303
7.69k
  debPos.resize(numElt, 0);
1304
7.69k
  dataSize.resize(numElt, 0);
1305
841k
  for (size_t i = 0; i < numElt; i++) {
1306
839k
    pos = input->tell();
1307
839k
    debPos[i] = pos;
1308
839k
    int sz = dataSize[i] = static_cast<int>(input->readULong(1));
1309
839k
    if (sz != 0xFF && pos+1+sz > zone.end()) {
1310
5.71k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesParagraph: can not read a paragraph\n"));
1311
5.71k
      if (i == 0)
1312
632
        return false;
1313
5.08k
      numElt = i-1;
1314
5.08k
      break;
1315
5.71k
    }
1316
833k
    if (sz && sz != 0xFF)
1317
298k
      input->seek(sz, librevenge::RVNG_SEEK_CUR);
1318
535k
    else {
1319
535k
      f.str("");
1320
535k
      f << "ParagPLC(sP" << int(i)-N << "):";
1321
535k
      ascFile.addPos(pos);
1322
535k
      ascFile.addNote(f.str().c_str());
1323
535k
    }
1324
833k
  }
1325
118M
  for (auto id : order) {
1326
118M
    if (id < 0 || id >= int(numElt)) continue;
1327
828k
    int prevId = previous[size_t(id)];
1328
828k
    MsWrdStruct::Paragraph para(vers);
1329
828k
    if (prevId >= 0 && m_state->m_styleParagraphMap.find(prevId-N) != m_state->m_styleParagraphMap.end())
1330
552k
      para = m_state->m_styleParagraphMap.find(prevId-N)->second;
1331
    /** osnola: update the font style here or after reading data ? */
1332
828k
    if (m_state->m_styleFontMap.find(id-N) != m_state->m_styleFontMap.end())
1333
266k
      para.m_font = m_state->m_styleFontMap.find(id-N)->second;
1334
828k
    if (dataSize[size_t(id)] != 0xFF) {
1335
731k
      f.str("");
1336
731k
      f << "ParagPLC(sP" << id-N << "):";
1337
731k
      if (dataSize[size_t(id)] < minSz) {
1338
499k
        MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesParagraph: zone(paragraph) the id seems bad...\n"));
1339
499k
        f << "#";
1340
499k
      }
1341
232k
      else {
1342
232k
        input->seek(debPos[size_t(id)]+1, librevenge::RVNG_SEEK_SET);
1343
232k
        auto pId = static_cast<int>(input->readLong(1));
1344
232k
        if (id >= N && pId != id-N) {
1345
179k
          MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesParagraph: zone(paragraph) the id seems bad...\n"));
1346
179k
          f << "#id=" << pId << ",";
1347
179k
        }
1348
232k
        auto val = static_cast<int>(input->readLong(2)); // always 0?
1349
232k
        if (val) f << "g0=" << val << ",";
1350
1351
232k
        if (vers > 3) {
1352
188k
          for (int j = 1; j < 3; j++) { // 0|90|c0,0|1
1353
125k
            val = static_cast<int>(input->readLong(2));
1354
125k
            if (val) f << "g" << j << "=" << std::hex << val << std::dec << ",";
1355
125k
          }
1356
62.9k
        }
1357
1358
232k
        if (dataSize[size_t(id)] != minSz && !readParagraph(para, dataSize[size_t(id)]-minSz))
1359
0
          f << "#";
1360
#ifdef DEBUG_WITH_FILES
1361
        para.print(f, m_parserState->m_fontConverter);
1362
#endif
1363
232k
      }
1364
731k
      ascFile.addPos(debPos[size_t(id)]);
1365
731k
      ascFile.addNote(f.str().c_str());
1366
731k
    }
1367
828k
    para.m_modFont.setSet(false);
1368
828k
    m_state->m_styleParagraphMap.insert
1369
828k
    (std::map<int, MsWrdStruct::Paragraph>::value_type(id-N,para));
1370
828k
  }
1371
7.06k
  return true;
1372
7.69k
}
1373
1374
bool MsWrdTextStyles::readStylesHierarchy(MsWrdEntry &entry, int N, std::vector<int> &orig)
1375
7.73k
{
1376
7.73k
  MWAWInputStreamPtr &input= m_parserState->m_input;
1377
7.73k
  long pos = input->tell();
1378
7.73k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1379
7.73k
  libmwaw::DebugStream f;
1380
7.73k
  f << "Styles(hierarchy):";
1381
1382
7.73k
  auto N2 = static_cast<int>(input->readULong(2));
1383
7.73k
  if (N2 < N) {
1384
333
    MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesHierarchy: N seems too small...\n"));
1385
333
    f << "#N=" << N2 << ",";
1386
333
    ascFile.addPos(pos);
1387
333
    ascFile.addNote("Styles(hierarchy):#"); // big problem
1388
333
    return false;
1389
333
  }
1390
7.40k
  if (pos+(N2+1)*2 > entry.end()) {
1391
5.13k
    if (N2>40) {
1392
4.58k
      MWAW_DEBUG_MSG(("MsWrdTextStyles::readStylesHierarchy: N seems very big...\n"));
1393
4.58k
      ascFile.addPos(pos);
1394
4.58k
      ascFile.addNote("Styles(hierarchy):#"); // big problem
1395
4.58k
    }
1396
5.13k
    f << "#";
1397
5.13k
  }
1398
7.40k
  orig.resize(0);
1399
7.40k
  orig.resize(size_t(N2), -1000);
1400
124M
  for (int i = 0; i < N2; i++) {
1401
124M
    auto v0 = static_cast<int>(input->readLong(1)); // often 0 or i-N
1402
124M
    auto v1 = static_cast<int>(input->readLong(1));
1403
124M
    f << "prev(sP"<< i-N << ")";
1404
124M
    if (v1 == -34) {
1405
16.3k
    }
1406
124M
    else if (v1 < -N || v1+N >= N2)
1407
30.9M
      f << "=###" << v1;
1408
93.4M
    else {
1409
93.4M
      orig[size_t(i)] = v1+N;
1410
93.4M
      f << "=sP" << v1;
1411
93.4M
    }
1412
124M
    if (v0 < -N || v0+N >= N2) {
1413
31.0M
      f << "[###next" << v0 << "]";
1414
31.0M
      m_state->m_nextStyleMap[i-N]=i-N;
1415
31.0M
    }
1416
93.4M
    else {
1417
93.4M
      m_state->m_nextStyleMap[i-N]=v0;
1418
93.4M
      if (v0==i-N)
1419
8.21k
        f << "*";
1420
93.4M
      else if (v0)
1421
3.98M
        f << "[next" << v0 << "]";
1422
93.4M
    }
1423
124M
    f << ",";
1424
124M
  }
1425
1426
7.40k
  ascFile.addPos(pos);
1427
7.40k
  ascFile.addNote(f.str().c_str());
1428
1429
7.40k
  pos = input->tell();
1430
7.40k
  if (pos < entry.end()) {
1431
962
    ascFile.addPos(pos);
1432
962
    ascFile.addNote("_");
1433
962
  }
1434
6.44k
  else if (pos > entry.end())
1435
5.11k
    entry.setEnd(pos);
1436
1437
7.40k
  return true;
1438
7.73k
}
1439
1440
std::vector<int> MsWrdTextStyles::orderStyles(std::vector<int> const &previous)
1441
7.40k
{
1442
7.40k
  std::vector<int> order, numChild;
1443
7.40k
  size_t N = previous.size();
1444
7.40k
  numChild.resize(N, 0);
1445
124M
  for (auto id : previous) {
1446
124M
    if (id == -1000) continue;
1447
93.4M
    if (id < 0 || id >= int(N)) {
1448
0
      MWAW_DEBUG_MSG(("MsWrdTextStyles::orderStyles: find a bad previous %d\n", id));
1449
0
      continue;
1450
0
    }
1451
93.4M
    numChild[size_t(id)]++;
1452
93.4M
  }
1453
7.40k
  order.resize(N);
1454
7.40k
  size_t numElt = 0;
1455
23.1k
  while (numElt < N) {
1456
19.0k
    bool read = false;
1457
394M
    for (size_t i = 0; i < N; i++) {
1458
394M
      if (numChild[i]) continue;
1459
124M
      order[N-(++numElt)]=int(i);
1460
124M
      if (previous[i] >= 0 && previous[i] < int(N))
1461
93.4M
        numChild[size_t(previous[i])]--;
1462
124M
      read = true;
1463
124M
      numChild[i]=-1;
1464
124M
    }
1465
19.0k
    if (read) continue;
1466
3.29k
    MWAW_DEBUG_MSG(("MsWrdTextStyles::orderStyles: find a loop, stop...\n"));
1467
67.7M
    for (size_t i = 0; i < N; i++) {
1468
67.7M
      if (numChild[i] != -1)
1469
7.82k
        order[N-(++numElt)]=int(i);
1470
67.7M
    }
1471
3.29k
    break;
1472
19.0k
  }
1473
7.40k
  return order;
1474
7.40k
}
1475
1476
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: