Coverage Report

Created: 2026-10-28 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/HanMacWrdJText.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <iomanip>
35
#include <iostream>
36
#include <limits>
37
#include <map>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWTextListener.hxx"
43
#include "MWAWDebug.hxx"
44
#include "MWAWFont.hxx"
45
#include "MWAWFontConverter.hxx"
46
#include "MWAWGraphicListener.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWRSRCParser.hxx"
50
#include "MWAWSection.hxx"
51
#include "MWAWSubDocument.hxx"
52
53
#include "HanMacWrdJParser.hxx"
54
55
#include "HanMacWrdJText.hxx"
56
57
/** Internal: the structures of a HanMacWrdJText */
58
namespace HanMacWrdJTextInternal
59
{
60
/** different PLC types */
61
enum PLCType { CHAR=0, RULER, LINE, TOKEN, Unknown};
62
/** Internal and low level: the PLC different types and their structures of a HanMacWrdJText */
63
struct PLC {
64
  //! constructor
65
  explicit PLC(PLCType w= Unknown, int id=0)
66
195k
    : m_type(w)
67
195k
    , m_id(id)
68
195k
    , m_extra("") {}
69
  //! operator<<
70
  friend std::ostream &operator<<(std::ostream &o, PLC const &plc)
71
0
  {
72
0
    switch (plc.m_type) {
73
0
    case CHAR:
74
0
      o << "F" << plc.m_id << ",";
75
0
      break;
76
0
    case LINE:
77
0
      o << "L" << plc.m_id << ",";
78
0
      break;
79
0
    case RULER:
80
0
      o << "R" << plc.m_id << ",";
81
0
      break;
82
0
    case TOKEN:
83
0
      o << "T" << plc.m_id << ",";
84
0
      break;
85
0
    case Unknown:
86
0
#if !defined(__clang__)
87
0
    default:
88
0
#endif
89
0
      o << "#unknown" << plc.m_id << ",";
90
0
    }
91
0
    o << plc.m_extra;
92
0
    return o;
93
0
  }
94
  //! PLC type
95
  PLCType m_type;
96
  //! the indentificator
97
  int m_id;
98
  //! extra data
99
  std::string m_extra;
100
};
101
102
/** Internal: class to store a token of a HanMacWrdJText */
103
struct Token {
104
  //! constructor
105
  Token()
106
2.68k
    : m_type(0)
107
2.68k
    , m_id(0)
108
2.68k
    , m_localId(0)
109
2.68k
    , m_bookmark("")
110
2.68k
    , m_length(0)
111
2.68k
    , m_extra("")
112
2.68k
  {
113
2.68k
  }
114
  //! operator<<
115
  friend std::ostream &operator<<(std::ostream &o, Token const &tk)
116
0
  {
117
0
    switch (tk.m_type) { // checkme
118
0
    case 0:
119
0
      break;
120
0
    case 1:
121
0
      o << "field,";
122
0
      break;
123
0
    case 2:
124
0
      o << "footnote,";
125
0
      break;
126
0
    case 8:
127
0
      o << "toc,";
128
0
      break;
129
0
    case 0x20:
130
0
      o << "bookmark,";
131
0
      break;
132
0
    default:
133
0
      o << "#type=" << tk.m_type << ",";
134
0
      break;
135
0
    }
136
0
    if (tk.m_bookmark.length())
137
0
      o << "text[bookmark]=" << tk.m_bookmark << ",";
138
0
    if (tk.m_id)
139
0
      o << "zId=" << std::hex << tk.m_id << std::dec << ",";
140
0
    if (tk.m_localId)
141
0
      o << "id=" << tk.m_localId << ",";
142
0
    if (tk.m_length)
143
0
      o << "length=" << tk.m_length << ",";
144
0
    o << tk.m_extra;
145
0
    return o;
146
0
  }
147
  //! the token type
148
  int m_type;
149
  //! the id ( to be send)
150
  long m_id;
151
  //! the local id
152
  int m_localId;
153
  //! the bookmark string
154
  std::string m_bookmark;
155
  //! the token length in caller text
156
  int m_length;
157
  //! extra string string
158
  std::string m_extra;
159
};
160
161
/** Internal: class to store a section of a HanMacWrdJText */
162
struct Section {
163
  //! constructor
164
  Section()
165
4.01k
    : m_numCols(1)
166
4.01k
    , m_colWidth()
167
4.01k
    , m_colSep()
168
4.01k
    , m_id(0)
169
4.01k
    , m_extra("")
170
4.01k
  {
171
4.01k
  }
172
  //! returns a MWAWSection
173
  MWAWSection getSection() const
174
2.36k
  {
175
2.36k
    MWAWSection sec;
176
2.36k
    if (m_colWidth.size()==0) {
177
0
      MWAW_DEBUG_MSG(("HanMacWrdJTextInternal::Section:getSection can not find any width\n"));
178
0
      return sec;
179
0
    }
180
2.36k
    if (m_numCols <= 1)
181
1.59k
      return sec;
182
771
    bool hasSep = m_colWidth.size()==m_colSep.size();
183
771
    sec.m_columns.resize(size_t(m_numCols));
184
771
    if (m_colWidth.size()==size_t(m_numCols)) {
185
156
      for (size_t c=0; c < size_t(m_numCols); c++) {
186
116
        sec.m_columns[c].m_width = double(m_colWidth[c]);
187
116
        sec.m_columns[c].m_widthUnit = librevenge::RVNG_POINT;
188
116
        if (!hasSep) continue;
189
116
        sec.m_columns[c].m_margins[libmwaw::Left]=
190
116
          sec.m_columns[c].m_margins[libmwaw::Right]=double(m_colSep[c])/2.0/72.;
191
116
      }
192
40
    }
193
731
    else {
194
731
      if (m_colWidth.size()>1) {
195
0
        MWAW_DEBUG_MSG(("HanMacWrdJTextInternal::Section:getSection colWidth is not coherent with numCols\n"));
196
0
      }
197
731
      sec.setColumns(m_numCols, double(m_colWidth[0]), librevenge::RVNG_POINT,
198
731
                     hasSep ? double(m_colSep[0])/72. : 0);
199
731
    }
200
771
    return sec;
201
2.36k
  }
202
  //! operator<<
203
  friend std::ostream &operator<<(std::ostream &o, Section const &sec)
204
0
  {
205
0
    if (sec.m_numCols!=1)
206
0
      o << "numCols=" << sec.m_numCols << ",";
207
0
    if (sec.m_colWidth.size()) {
208
0
      o << "colWidth=[";
209
0
      for (size_t i = 0; i < sec.m_colWidth.size(); i++)
210
0
        o << sec.m_colWidth[i] << ":" << sec.m_colSep[i] << ",";
211
0
      o << "],";
212
0
    }
213
0
    if (sec.m_id)
214
0
      o << "id=" << std::hex << sec.m_id << std::dec << ",";
215
0
    o << sec.m_extra;
216
0
    return o;
217
0
  }
218
  //! the number of column
219
  int m_numCols;
220
  //! the columns width
221
  std::vector<double> m_colWidth;
222
  //! the columns separator width
223
  std::vector<double> m_colSep;
224
  //! the id
225
  long m_id;
226
  //! extra string string
227
  std::string m_extra;
228
};
229
230
//! Internal: a struct used to store a text zone
231
struct TextZone {
232
  //! enum used to define the zone type
233
  enum Type { T_Main=0, T_Header=1, T_Footer=2, T_Footnote=3, T_Textbox=4,
234
              T_Table=9, T_Comment=10, T_Unknown
235
            };
236
  //! constructor
237
  TextZone()
238
152k
    : m_type(T_Unknown)
239
152k
    , m_entry()
240
152k
    , m_id(0)
241
152k
    , m_PLCMap()
242
152k
    , m_tokenList()
243
152k
    , m_parsed(false)
244
152k
  {
245
152k
  }
246
247
  //! the zone type
248
  Type m_type;
249
  //! the main entry
250
  MWAWEntry m_entry;
251
  //! the file zone id
252
  long m_id;
253
  //! the plc map
254
  std::multimap<long, PLC> m_PLCMap;
255
  //! the tokens list
256
  std::vector<Token> m_tokenList;
257
258
  //! true if the zone is sended
259
  mutable bool m_parsed;
260
};
261
262
263
/** Internal: class to store the paragraph properties of a HanMacWrdJText */
264
struct Paragraph final : public MWAWParagraph {
265
  //! Constructor
266
  Paragraph()
267
105k
    : MWAWParagraph()
268
105k
    , m_type(0)
269
105k
    , m_addPageBreak(false)
270
105k
  {
271
105k
  }
272
113k
  Paragraph(Paragraph const &)=default;
273
  Paragraph &operator=(Paragraph const &)=default;
274
52.9k
  Paragraph &operator=(Paragraph &&)=default;
275
  //! destructor
276
  ~Paragraph() final;
277
  //! operator<<
278
  friend std::ostream &operator<<(std::ostream &o, Paragraph const &ind)
279
0
  {
280
0
    switch (ind.m_type) {
281
0
    case 0:
282
0
      break;
283
0
    case 1:
284
0
      o << "header,";
285
0
      break;
286
0
    case 2:
287
0
      o << "footer,";
288
0
      break;
289
0
    case 5:
290
0
      o << "footnote,";
291
0
      break;
292
0
    default:
293
0
      o << "#type=" << ind.m_type << ",";
294
0
      break;
295
0
    }
296
0
    o << static_cast<MWAWParagraph const &>(ind) << ",";
297
0
    if (ind.m_addPageBreak) o << "pageBreakBef,";
298
0
    return o;
299
0
  }
300
  //! the type
301
  int m_type;
302
  //! flag to store a force page break
303
  bool m_addPageBreak;
304
};
305
306
Paragraph::~Paragraph()
307
219k
{
308
219k
}
309
310
////////////////////////////////////////
311
//! Internal: the state of a HanMacWrdJText
312
struct State {
313
  //! constructor
314
  State()
315
35.0k
    : m_version(-1)
316
35.0k
    , m_fontList()
317
35.0k
    , m_paragraphList()
318
35.0k
    , m_sectionList()
319
35.0k
    , m_ftnTextId(0)
320
35.0k
    , m_ftnFirstPosList()
321
35.0k
    , m_textZoneList()
322
35.0k
    , m_idTextZoneMap()
323
35.0k
    , m_numPages(-1)
324
35.0k
    , m_actualPage(0)
325
35.0k
  {
326
35.0k
  }
327
  //! the file version
328
  mutable int m_version;
329
  /** the font list */
330
  std::vector<MWAWFont> m_fontList;
331
  //! the list of paragraph
332
  std::vector<Paragraph> m_paragraphList;
333
  //! the list of section
334
  std::vector<Section> m_sectionList;
335
  //! the footnote zone id;
336
  long m_ftnTextId;
337
  //! the footnote begin positions
338
  std::vector<long> m_ftnFirstPosList;
339
  //! the list of text zone
340
  std::vector<TextZone> m_textZoneList;
341
  //! a map textId -> id in m_textZoneList
342
  std::map<long, int> m_idTextZoneMap;
343
  int m_numPages /* the number of pages */, m_actualPage /* the actual page */;
344
};
345
346
////////////////////////////////////////
347
//! Internal: the subdocument of a HanMacWrdJText
348
class SubDocument final : public MWAWSubDocument
349
{
350
protected:
351
  //! the subdocument type
352
  enum Type { S_TextZone, S_String };
353
public:
354
  //! constructor to call a textzone
355
  SubDocument(HanMacWrdJText &pars, MWAWInputStreamPtr const &input, long id, long cPos=0)
356
1.79k
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
357
1.79k
    , m_type(S_TextZone)
358
1.79k
    , m_textParser(&pars)
359
1.79k
    , m_id(id)
360
1.79k
    , m_cPos(cPos)
361
1.79k
    , m_bookmark("") {}
362
  //! constructor to send a string
363
  SubDocument(HanMacWrdJText &pars, MWAWInputStreamPtr const &input, std::string const &text)
364
8
    : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry())
365
8
    , m_type(S_String)
366
8
    , m_textParser(&pars)
367
8
    , m_id(0)
368
8
    , m_cPos(0)
369
8
    , m_bookmark(text) {}
370
371
372
  //! destructor
373
1.80k
  ~SubDocument() final {}
374
375
  //! operator!=
376
  bool operator!=(MWAWSubDocument const &doc) const final;
377
378
  //! the parser function
379
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
380
381
protected:
382
  /** the subdocument type */
383
  Type m_type;
384
  /** the text parser */
385
  HanMacWrdJText *m_textParser;
386
  //! the subdocument id
387
  long m_id;
388
  //! the first charecter position
389
  long m_cPos;
390
  //! the bookmark string
391
  std::string m_bookmark;
392
private:
393
  SubDocument(SubDocument const &orig) = delete;
394
  SubDocument &operator=(SubDocument const &orig) = delete;
395
};
396
397
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
398
1.78k
{
399
1.78k
  if (!listener.get()) {
400
0
    MWAW_DEBUG_MSG(("HanMacWrdJTextInternal::SubDocument::parse: no listener\n"));
401
0
    return;
402
0
  }
403
404
1.78k
  if (m_type==S_String) {
405
8
    for (auto &c : m_bookmark)
406
0
      listener->insertCharacter(static_cast<unsigned char>(c));
407
8
    return;
408
8
  }
409
1.77k
  if (!m_textParser) {
410
0
    MWAW_DEBUG_MSG(("HanMacWrdJTextInternal::SubDocument::parse: no parser\n"));
411
0
    return;
412
0
  }
413
1.77k
  long pos = m_input->tell();
414
1.77k
  m_textParser->sendText(m_id, m_cPos);
415
1.77k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
416
1.77k
}
417
418
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
419
14
{
420
14
  if (MWAWSubDocument::operator!=(doc)) return true;
421
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
422
0
  if (!sDoc) return true;
423
0
  if (m_textParser != sDoc->m_textParser) return true;
424
0
  if (m_type != sDoc->m_type) return true;
425
0
  if (m_id != sDoc->m_id) return true;
426
0
  if (m_cPos != sDoc->m_cPos) return true;
427
0
  if (m_bookmark != sDoc->m_bookmark) return true;
428
0
  return false;
429
0
}
430
}
431
432
////////////////////////////////////////////////////////////
433
// constructor/destructor, ...
434
////////////////////////////////////////////////////////////
435
HanMacWrdJText::HanMacWrdJText(HanMacWrdJParser &parser)
436
35.0k
  : m_parserState(parser.getParserState())
437
35.0k
  , m_state(new HanMacWrdJTextInternal::State)
438
35.0k
  , m_mainParser(&parser)
439
35.0k
{
440
35.0k
}
441
442
HanMacWrdJText::~HanMacWrdJText()
443
35.0k
{
444
35.0k
}
445
446
int HanMacWrdJText::version() const
447
0
{
448
0
  if (m_state->m_version < 0)
449
0
    m_state->m_version = m_parserState->m_version;
450
0
  return m_state->m_version;
451
0
}
452
453
int HanMacWrdJText::numPages() const
454
12.5k
{
455
12.5k
  int nPages = 1;
456
12.5k
  for (auto const &zone : m_state->m_textZoneList) {
457
8.68k
    if (zone.m_type != HanMacWrdJTextInternal::TextZone::T_Main)
458
2.30k
      continue;
459
6.38k
    nPages = const_cast<HanMacWrdJText *>(this)->computeNumPages(zone);
460
6.38k
    break;
461
8.68k
  }
462
  // fixme: compute the number of page
463
12.5k
  m_state->m_numPages = nPages;
464
12.5k
  return nPages;
465
12.5k
}
466
467
std::vector<long> HanMacWrdJText::getTokenIdList() const
468
12.5k
{
469
12.5k
  std::vector<long> res;
470
151k
  for (auto const &zone : m_state->m_textZoneList) {
471
151k
    for (auto const &token : zone.m_tokenList) {
472
2.67k
      if (token.m_type==1)
473
28
        res.push_back(token.m_id);
474
2.67k
    }
475
151k
  }
476
12.5k
  return res;
477
12.5k
}
478
479
////////////////////////////////////////////////////////////
480
// Intermediate level
481
////////////////////////////////////////////////////////////
482
483
////////////////////////////////////////////////////////////
484
//     Text
485
////////////////////////////////////////////////////////////
486
bool HanMacWrdJText::canSendTextAsGraphic(long id, long cPos)
487
26
{
488
26
  if (m_state->m_idTextZoneMap.find(id)==m_state->m_idTextZoneMap.end()) {
489
26
    MWAW_DEBUG_MSG(("HanMacWrdJText::canSendTextAsGraphic: can not find text zone with id %lx\n", static_cast<long unsigned int>(id)));
490
26
    return false;
491
26
  }
492
0
  int zId = m_state->m_idTextZoneMap.find(id)->second;
493
0
  if (zId < 0 || zId >= static_cast<int>(m_state->m_textZoneList.size()))
494
0
    return false;
495
0
  return canSendTextAsGraphic(m_state->m_textZoneList[size_t(zId)], cPos);
496
0
}
497
498
bool HanMacWrdJText::canSendTextAsGraphic(HanMacWrdJTextInternal::TextZone const &zone, long cPos)
499
0
{
500
0
  if (!zone.m_entry.valid())
501
0
    return false;
502
503
0
  auto plcIt=zone.m_PLCMap.find(cPos);
504
0
  while (plcIt != zone.m_PLCMap.end() && plcIt->first < cPos)
505
0
    ++plcIt;
506
0
  while (plcIt != zone.m_PLCMap.end()) {
507
0
    auto const &plc = plcIt++->second;
508
0
    if (plc.m_type!=HanMacWrdJTextInternal::TOKEN) continue;
509
0
    if (plc.m_id < 0 || plc.m_id >= static_cast<int>(zone.m_tokenList.size()))
510
0
      continue;
511
0
    auto const &tkn=zone.m_tokenList[size_t(plc.m_id)];
512
0
    switch (tkn.m_type) {
513
0
    case 1:
514
0
    case 2:
515
0
    case 0x20:
516
0
      return false;
517
0
    default:
518
0
      break;
519
0
    }
520
0
  }
521
0
  return true;
522
0
}
523
524
bool HanMacWrdJText::sendText(long id, long cPos, MWAWListenerPtr listener)
525
14.0k
{
526
14.0k
  if (m_state->m_idTextZoneMap.find(id)==m_state->m_idTextZoneMap.end()) {
527
3.04k
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find text zone with id %lx\n", static_cast<long unsigned int>(id)));
528
3.04k
    return false;
529
3.04k
  }
530
11.0k
  int zId = m_state->m_idTextZoneMap.find(id)->second;
531
11.0k
  if (zId < 0 || zId >= static_cast<int>(m_state->m_textZoneList.size()))
532
0
    return false;
533
11.0k
  return sendText(m_state->m_textZoneList[size_t(zId)], cPos, listener);
534
11.0k
}
535
536
bool HanMacWrdJText::sendMainText()
537
12.5k
{
538
12.5k
  for (auto &zone : m_state->m_textZoneList) {
539
8.68k
    if (zone.m_type != HanMacWrdJTextInternal::TextZone::T_Main)
540
2.30k
      continue;
541
6.38k
    sendText(zone,0);
542
6.38k
    return true;
543
8.68k
  }
544
6.12k
  MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find the main zone\n"));
545
6.12k
  return false;
546
12.5k
}
547
548
549
bool HanMacWrdJText::sendText(HanMacWrdJTextInternal::TextZone const &zone, long fPos, MWAWListenerPtr listener)
550
17.3k
{
551
17.3k
  if (!zone.m_entry.valid()) {
552
3.17k
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: call without entry\n"));
553
3.17k
    return false;
554
3.17k
  }
555
14.2k
  bool withLocalListener=false;
556
14.2k
  if (listener)
557
0
    withLocalListener=true;
558
14.2k
  else
559
14.2k
    listener=m_parserState->m_textListener;
560
14.2k
  if (!listener) {
561
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find the listener\n"));
562
0
    return false;
563
0
  }
564
565
14.2k
  zone.m_parsed=true;
566
14.2k
  librevenge::RVNGBinaryData data;
567
14.2k
  if (!m_mainParser->decodeZone(zone.m_entry, data)) {
568
4
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not decode a zone\n"));
569
4
    m_parserState->m_asciiFile.addPos(zone.m_entry.begin());
570
4
    m_parserState->m_asciiFile.addNote("###");
571
4
    return false;
572
4
  }
573
14.2k
  if (!data.size())
574
0
    return true;
575
14.2k
  if (fPos < 0 || 2*fPos > long(data.size())) {
576
252
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: first pos %ld is too big zone\n", fPos));
577
252
    return false;
578
252
  }
579
580
13.9k
  MWAWInputStreamPtr input=MWAWInputStream::get(data, false);
581
13.9k
  if (!input) {
582
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find my input\n"));
583
0
    return false;
584
0
  }
585
13.9k
  libmwaw::DebugFile asciiFile(input);
586
587
#ifdef DEBUG_WITH_FILES
588
  if (fPos==0) {
589
    static int tId=0;
590
    std::stringstream s;
591
    s << "Text" << tId++;
592
    asciiFile.open(s.str());
593
  }
594
#endif
595
596
13.9k
  bool isMain = zone.m_type==HanMacWrdJTextInternal::TextZone::T_Main;
597
13.9k
  bool charOneIsEnd = zone.m_type==HanMacWrdJTextInternal::TextZone::T_Footnote ||
598
12.4k
                      zone.m_type==HanMacWrdJTextInternal::TextZone::T_Table;
599
600
13.9k
  long cPos=fPos, endCPos=-1;
601
13.9k
  int actPage = 1, actCol = 0, numCol=1, actSection = 1;
602
13.9k
  if (isMain)
603
5.63k
    m_mainParser->newPage(1);
604
13.9k
  if (isMain && !m_state->m_sectionList.size()) {
605
3.99k
    MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find section 0\n"));
606
3.99k
  }
607
9.97k
  else if (isMain) {
608
1.63k
    auto sec = m_state->m_sectionList[0];
609
1.63k
    if (sec.m_numCols >= 1 && sec.m_colWidth.size() > 0) {
610
1.63k
      if (listener->isSectionOpened())
611
0
        listener->closeSection();
612
1.63k
      listener->openSection(sec.getSection());
613
1.63k
      numCol = listener->getSection().numColumns();
614
1.63k
    }
615
1.63k
  }
616
13.9k
  long pos = 2*fPos;
617
13.9k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
618
13.9k
  libmwaw::DebugStream f;
619
13.9k
  f << "Entries(TextData):";
620
621
91.5k
  while (true) {
622
91.5k
    if (cPos!=fPos) {
623
77.5k
      asciiFile.addPos(pos);
624
77.5k
      asciiFile.addNote(f.str().c_str());
625
77.5k
      f.str("");
626
77.5k
      f << "TextData:";
627
77.5k
      pos = input->tell();
628
77.5k
    }
629
91.5k
    auto plcIt=zone.m_PLCMap.find(cPos);
630
91.5k
    int expectedChar=0;
631
91.5k
    if (plcIt != zone.m_PLCMap.end()) {
632
190k
      while (plcIt != zone.m_PLCMap.end() && plcIt->first == cPos) {
633
113k
        auto const &plc = plcIt++->second;
634
113k
        f << "[" << plc << "]";
635
113k
        switch (plc.m_type) {
636
41.3k
        case HanMacWrdJTextInternal::CHAR: {
637
41.3k
          if (plc.m_id < 0 || plc.m_id >= static_cast<int>(m_state->m_fontList.size())) {
638
20.3k
            MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find font\n"));
639
20.3k
            f << "[###font]";
640
20.3k
            break;
641
20.3k
          }
642
20.9k
          listener->setFont(m_state->m_fontList[size_t(plc.m_id)]);
643
20.9k
          break;
644
41.3k
        }
645
23.2k
        case HanMacWrdJTextInternal::RULER: {
646
23.2k
          if (plc.m_id < 0 || plc.m_id >= static_cast<int>(m_state->m_paragraphList.size())) {
647
8.77k
            MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find paragraph\n"));
648
8.77k
            f << "[###paragraph]";
649
8.77k
            break;
650
8.77k
          }
651
14.4k
          auto const &para=m_state->m_paragraphList[size_t(plc.m_id)];
652
14.4k
          if (isMain && para.m_addPageBreak)
653
57
            m_mainParser->newPage(++actPage);
654
14.4k
          listener->setParagraph(para);
655
14.4k
          break;
656
23.2k
        }
657
2.18k
        case HanMacWrdJTextInternal::TOKEN: {
658
2.18k
          if (plc.m_id < 0 || plc.m_id >= static_cast<int>(zone.m_tokenList.size())) {
659
0
            MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find token\n"));
660
0
            f << "[###token]";
661
0
            break;
662
0
          }
663
2.18k
          auto const &tkn=zone.m_tokenList[size_t(plc.m_id)];
664
2.18k
          switch (tkn.m_type) {
665
4
          case 1:
666
4
            expectedChar=0x1;
667
4
            if (withLocalListener) {
668
0
              MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: unexpected token type=1 in graphic\n"));
669
0
              break;
670
0
            }
671
4
            m_mainParser->sendZone(tkn.m_id);
672
4
            break;
673
2.07k
          case 2: {
674
2.07k
            expectedChar=0x11;
675
2.07k
            if (withLocalListener) {
676
0
              MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not insert footnote in graphic\n"));
677
0
              break;
678
0
            }
679
2.07k
            if (tkn.m_localId < 0 || tkn.m_localId >= int(m_state->m_ftnFirstPosList.size())) {
680
283
              MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find footnote\n"));
681
283
              f << "[###ftnote]";
682
283
              break;
683
283
            }
684
1.79k
            MWAWSubDocumentPtr subdoc
685
1.79k
            (new HanMacWrdJTextInternal::SubDocument
686
1.79k
             (*this, input, m_state->m_ftnTextId,
687
1.79k
              m_state->m_ftnFirstPosList[size_t(tkn.m_localId)]));
688
1.79k
            m_parserState->m_textListener->insertNote(MWAWNote(MWAWNote::FootNote),subdoc);
689
1.79k
            break;
690
2.07k
          }
691
0
          case 8: // TOC, ok to ignore
692
0
            break;
693
8
          case 0x20:
694
8
            if (withLocalListener) {
695
0
              MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not insert bookmark in graphic\n"));
696
0
              break;
697
0
            }
698
8
            else {
699
8
              MWAWSubDocumentPtr subdoc(new HanMacWrdJTextInternal::SubDocument(*this, input, tkn.m_bookmark));
700
8
              m_parserState->m_textListener->insertComment(subdoc);
701
8
              break;
702
8
            }
703
100
          default:
704
100
            MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not send token with type %d\n", tkn.m_type));
705
100
            break;
706
2.18k
          }
707
708
2.18k
          break;
709
2.18k
        }
710
46.9k
        case HanMacWrdJTextInternal::LINE:
711
46.9k
        case HanMacWrdJTextInternal::Unknown:
712
#if !defined(__clang__)
713
        default:
714
#endif
715
46.9k
          break;
716
113k
        }
717
113k
      }
718
77.0k
      endCPos = (plcIt != zone.m_PLCMap.end()) ? plcIt->first : -1;
719
77.0k
    }
720
91.5k
    if (input->isEnd())
721
8.86k
      break;
722
82.6k
    if (expectedChar) {
723
2.07k
      if (static_cast<int>(input->readULong(1))==expectedChar) {
724
82
        cPos++;
725
82
        input->seek(1, librevenge::RVNG_SEEK_CUR);
726
82
      }
727
1.99k
      else {
728
1.99k
        MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find expected char token\n"));
729
1.99k
        input->seek(-1, librevenge::RVNG_SEEK_CUR);
730
1.99k
        f << "###";
731
1.99k
      }
732
2.07k
    }
733
4.71M
    while (endCPos<0 || cPos < endCPos) {
734
4.64M
      cPos++;
735
4.64M
      if (input->isEnd())
736
3.40k
        break;
737
4.64M
      auto c = static_cast<int>(input->readULong(2));
738
4.64M
      if (c==0) {
739
114k
        if (input->isEnd())
740
5.36k
          break;
741
109k
        f << "#[0]";
742
109k
        continue;
743
114k
      }
744
4.52M
      if (c==1 && charOneIsEnd)
745
5.10k
        return true;
746
4.52M
      switch (c) {
747
2.81k
      case 0x1000:
748
2.81k
        f << "[pgNum]";
749
2.81k
        listener->insertField(MWAWField(MWAWField::PageNumber));
750
2.81k
        break;
751
2.59k
      case 0x1001:
752
2.59k
        f << "[pgCount]";
753
2.59k
        listener->insertField(MWAWField(MWAWField::PageCount));
754
2.59k
        break;
755
2.93k
      case 0x1002: {
756
2.93k
        f << "[date]";
757
2.93k
        MWAWField field(MWAWField::Date);
758
2.93k
        field.m_DTFormat="%A, %b %d, %Y";
759
2.93k
        listener->insertField(field);
760
2.93k
        break;
761
0
      }
762
1.59k
      case 0x1003: {
763
1.59k
        f << "[time]";
764
1.59k
        MWAWField field(MWAWField::Time);
765
1.59k
        field.m_DTFormat="%I:%M %p";
766
1.59k
        listener->insertField(field);
767
1.59k
        break;
768
0
      }
769
1.83k
      case 0x1004:
770
1.83k
        f << "[title]";
771
1.83k
        listener->insertField(MWAWField(MWAWField::Title));
772
1.83k
        break;
773
2.49k
      case 0x1005: {
774
2.49k
        std::stringstream s;
775
2.49k
        f << "[section]";
776
2.49k
        s << actSection;
777
2.49k
        listener->insertUnicodeString(librevenge::RVNGString(s.str().c_str()));
778
2.49k
        break;
779
0
      }
780
13.2k
      case 2:
781
13.2k
        f << "[colBreak]";
782
13.2k
        if (!isMain) {
783
1.77k
          MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: find column break in auxilliary block\n"));
784
1.77k
          break;
785
1.77k
        }
786
11.4k
        if (actCol < numCol-1 && numCol > 1) {
787
2.37k
          listener->insertBreak(MWAWTextListener::ColumnBreak);
788
2.37k
          actCol++;
789
2.37k
        }
790
9.11k
        else {
791
9.11k
          actCol = 0;
792
9.11k
          m_mainParser->newPage(++actPage);
793
9.11k
        }
794
11.4k
        break;
795
9.00k
      case 3:
796
9.00k
        f << "[pageBreak]";
797
9.00k
        if (isMain) {
798
8.17k
          m_mainParser->newPage(++actPage);
799
8.17k
          actCol = 0;
800
8.17k
        }
801
9.00k
        break;
802
12.4k
      case 4:
803
12.4k
        f << "[sectionBreak]";
804
12.4k
        if (!isMain) {
805
1.56k
          MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: find section in auxilliary block\n"));
806
1.56k
          break;
807
1.56k
        }
808
10.8k
        if (size_t(actSection) >= m_state->m_sectionList.size()) {
809
10.1k
          MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: can not find section %d\n", actSection));
810
10.1k
          break;
811
10.1k
        }
812
732
        else {
813
732
          auto const &sec = m_state->m_sectionList[size_t(actSection++)];
814
732
          actCol = 0;
815
732
          if (listener->isSectionOpened())
816
732
            listener->closeSection();
817
732
          m_mainParser->newPage(++actPage);
818
732
          listener->openSection(sec.getSection());
819
732
          numCol = listener->getSection().numColumns();
820
732
        }
821
732
        break;
822
4.33k
      case 9:
823
4.33k
        f << char(c);
824
4.33k
        listener->insertTab();
825
4.33k
        break;
826
11.7k
      case 0xd:
827
11.7k
        f << char(c);
828
11.7k
        listener->insertEOL();
829
11.7k
        break;
830
4.45M
      default: {
831
4.45M
        if (c >= 0x1100 && c <= 0x11ff) // ok a footnote
832
39.9k
          break;
833
4.41M
        if (c <= 0x1f || c >= 0x100) {
834
4.19M
          f << "#[" << std::hex << c << std::dec << "]";
835
4.19M
          MWAW_DEBUG_MSG(("HanMacWrdJText::sendText: find a odd char %x\n", static_cast<unsigned int>(c)));
836
4.19M
          break;
837
4.19M
        }
838
224k
        f << char(c);
839
224k
        listener->insertCharacter(static_cast<unsigned char>(c), input);
840
224k
        break;
841
4.41M
      }
842
4.52M
      }
843
4.52M
    }
844
82.6k
  }
845
8.86k
  return true;
846
13.9k
}
847
848
int HanMacWrdJText::computeNumPages(HanMacWrdJTextInternal::TextZone const &zone)
849
6.38k
{
850
6.38k
  if (zone.m_type!=HanMacWrdJTextInternal::TextZone::T_Main)
851
0
    return 1;
852
6.38k
  if (!zone.m_entry.valid())
853
764
    return 0;
854
5.61k
  librevenge::RVNGBinaryData data;
855
5.61k
  if (!m_mainParser->decodeZone(zone.m_entry, data) || !data.size())
856
3
    return 0;
857
858
5.61k
  MWAWInputStreamPtr input=MWAWInputStream::get(data, false);
859
5.61k
  if (!input)
860
0
    return 0;
861
5.61k
  int nPages = 1, actCol = 0, numCol=1, actSection = 1;
862
863
5.61k
  if (m_state->m_sectionList.size()) {
864
1.63k
    auto const &sec = m_state->m_sectionList[0];
865
1.63k
    if (sec.m_numCols >= 1)
866
1.63k
      numCol = sec.m_numCols;
867
1.63k
  }
868
5.61k
  input->seek(0, librevenge::RVNG_SEEK_SET);
869
4.33M
  while (!input->isEnd()) {
870
4.32M
    auto c = static_cast<int>(input->readULong(2));
871
4.32M
    switch (c) {
872
11.4k
    case 2:
873
11.4k
      if (actCol < numCol-1 && numCol > 1)
874
2.43k
        actCol++;
875
9.04k
      else {
876
9.04k
        actCol = 0;
877
9.04k
        nPages++;
878
9.04k
      }
879
11.4k
      break;
880
8.17k
    case 3:
881
8.17k
      actCol = 0;
882
8.17k
      nPages++;
883
8.17k
      break;
884
10.8k
    case 4: {
885
10.8k
      if (size_t(actSection) >= m_state->m_sectionList.size())
886
10.1k
        break;
887
732
      actCol = 0;
888
732
      nPages++;
889
732
      auto const &sec = m_state->m_sectionList[size_t(actSection++)];
890
732
      numCol = sec.m_numCols >= 1 ? sec.m_numCols : 1;
891
732
      break;
892
10.8k
    }
893
4.29M
    default:
894
4.29M
      break;
895
4.32M
    }
896
4.32M
  }
897
5.61k
  return nPages;
898
5.61k
}
899
900
void HanMacWrdJText::updateTextZoneTypes(std::map<long, int> const &idTypeMap)
901
12.5k
{
902
12.5k
  auto numZones = static_cast<int>(m_state->m_textZoneList.size());
903
22.9k
  for (auto const &it : idTypeMap) {
904
22.9k
    if (m_state->m_idTextZoneMap.find(it.first)==m_state->m_idTextZoneMap.end()) {
905
7.31k
      MWAW_DEBUG_MSG(("HanMacWrdJText::updateTextZoneTypes: can not find text zone with id %lx\n", static_cast<long unsigned int>(it.first)));
906
7.31k
      continue;
907
7.31k
    }
908
15.6k
    int zId = m_state->m_idTextZoneMap.find(it.first)->second;
909
15.6k
    if (zId < 0 || zId >= numZones)
910
0
      continue;
911
15.6k
    m_state->m_textZoneList[size_t(zId)].m_type=
912
15.6k
      HanMacWrdJTextInternal::TextZone::Type(it.second);
913
15.6k
  }
914
12.5k
}
915
916
void HanMacWrdJText::updateFootnoteInformations(long const &textZId, std::vector<long> const &fPosList)
917
4.92k
{
918
4.92k
  m_state->m_ftnTextId = textZId;
919
4.92k
  m_state->m_ftnFirstPosList = fPosList;
920
4.92k
}
921
922
bool HanMacWrdJText::readTextZonesList(MWAWEntry const &entry)
923
7.17k
{
924
7.17k
  if (!entry.valid()) {
925
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: called without any entry\n"));
926
0
    return false;
927
0
  }
928
7.17k
  if (entry.length() == 8) {
929
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: find an empty zone\n"));
930
0
    entry.setParsed(true);
931
0
    return true;
932
0
  }
933
7.17k
  if (entry.length() < 12) {
934
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: the entry seems too short\n"));
935
0
    return false;
936
0
  }
937
7.17k
  if (m_state->m_textZoneList.size()) {
938
1.57k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: oops the text zone list os ,not empty\n"));
939
1.57k
  }
940
7.17k
  long pos = entry.begin()+8; // skip header
941
7.17k
  long endPos = entry.end();
942
943
7.17k
  MWAWInputStreamPtr input = m_parserState->m_input;
944
7.17k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
945
7.17k
  libmwaw::DebugStream f;
946
7.17k
  entry.setParsed(true);
947
7.17k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
948
  // first read the header
949
7.17k
  f << entry.name() << "[header]:";
950
7.17k
  HanMacWrdJZoneHeader mainHeader(true);
951
7.17k
  if (!m_mainParser->readClassicHeader(mainHeader,endPos) || mainHeader.m_fieldSize!=4) {
952
608
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: can not read an entry\n"));
953
608
    f << "###sz=" << mainHeader.m_length;
954
608
    asciiFile.addPos(pos);
955
608
    asciiFile.addNote(f.str().c_str());
956
608
    return false;
957
608
  }
958
6.57k
  long headerEnd=pos+4+mainHeader.m_length;
959
6.57k
  f << mainHeader;
960
6.57k
  long val;
961
6.57k
  f << "listId=[" << std::hex;
962
6.57k
  std::vector<long> listIds;
963
160k
  for (int i = 0; i < mainHeader.m_n; i++) {
964
153k
    val = long(input->readULong(4));
965
153k
    m_state->m_idTextZoneMap[val]=i;
966
153k
    listIds.push_back(val);
967
153k
    f << val << ",";
968
153k
  }
969
6.57k
  f << std::dec << "],";
970
6.57k
  asciiFile.addPos(pos);
971
6.57k
  asciiFile.addNote(f.str().c_str());
972
6.57k
  if (input->tell()!=headerEnd) {
973
6.54k
    asciiFile.addDelimiter(input->tell(),'|');
974
6.54k
    input->seek(headerEnd, librevenge::RVNG_SEEK_SET);
975
6.54k
  }
976
6.57k
  m_state->m_textZoneList.resize(size_t(mainHeader.m_n));
977
6.57k
  if (mainHeader.m_n)
978
6.50k
    m_state->m_textZoneList[0].m_type=HanMacWrdJTextInternal::TextZone::T_Main;
979
24.1k
  for (int i = 0; i < mainHeader.m_n; i++) {
980
19.8k
    auto &zone=m_state->m_textZoneList[size_t(i)];
981
19.8k
    zone.m_id = listIds[size_t(i)];
982
    // first a field of size 0x26
983
19.8k
    pos = input->tell();
984
19.8k
    f.str("");
985
19.8k
    f << entry.name() << "-A" << i << ":";
986
19.8k
    f << "id=" << std::hex << listIds[size_t(i)] << std::dec << ",";
987
988
19.8k
    long dataSz = (pos+4>endPos) ? 0: long(input->readULong(4));
989
19.8k
    long zoneEnd=pos+4+dataSz;
990
19.8k
    if (zoneEnd > endPos) {
991
888
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: can not read first zone size for id=%d\n",i));
992
888
      f << "###sz=" << dataSz;
993
888
      asciiFile.addPos(pos);
994
888
      asciiFile.addNote(f.str().c_str());
995
888
      return false;
996
888
    }
997
19.0k
    if (dataSz < 38) {
998
449
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: first zone size for id=%d seems very short\n",i));
999
449
      f << "###";
1000
449
    }
1001
18.5k
    else {
1002
18.5k
      int sel[3];
1003
55.6k
      for (auto &s : sel) s = static_cast<int>(input->readLong(4));
1004
18.5k
      if (sel[0] || sel[1] || sel[2]) {
1005
18.5k
        f << "select=" << sel[1] << "x" << sel[0];
1006
18.5k
        if (sel[1] != sel[2])
1007
601
          f << "[" << sel[2] << "]";
1008
18.5k
        f << ",";
1009
18.5k
      }
1010
18.5k
      f << "listIds=[" << std::hex; // 5 or 6 id
1011
129k
      for (int j = 0; j < 6; j++) {
1012
111k
        val = long(input->readULong(4));
1013
111k
        if (val)
1014
95.3k
          f << val << ",";
1015
15.9k
        else
1016
15.9k
          f << "_,";
1017
111k
      }
1018
18.5k
      f << std::dec << "],";
1019
18.5k
      auto N1 = static_cast<int>(input->readULong(2)); // correspond to next N1
1020
18.5k
      f << "N=" << N1 << ",";
1021
18.5k
    }
1022
19.0k
    asciiFile.addPos(pos);
1023
19.0k
    asciiFile.addNote(f.str().c_str());
1024
1025
19.0k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1026
19.0k
    f.str("");
1027
19.0k
    f << entry.name() << "-B" << i << ":";
1028
19.0k
    f << "id=" << std::hex << listIds[size_t(i)] << std::dec << ",";
1029
1030
19.0k
    pos = input->tell();
1031
19.0k
    HanMacWrdJZoneHeader header(false);
1032
19.0k
    if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=4) {
1033
2.04k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: can not read second zone %d\n", i));
1034
2.04k
      f << "###" << header;
1035
2.04k
      asciiFile.addPos(pos);
1036
2.04k
      asciiFile.addNote(f.str().c_str());
1037
2.04k
      if (header.m_length<16 || pos+4+header.m_length>endPos)
1038
1.47k
        return false;
1039
573
      input->seek(pos+4+header.m_length, librevenge::RVNG_SEEK_SET);
1040
573
      continue;
1041
2.04k
    }
1042
16.9k
    zoneEnd=pos+4+header.m_length;
1043
16.9k
    f << header;
1044
    /* h0,h1,h2 seems to correspond to freeBlock, 0, 8[totalblock=8*..], h3=1*/
1045
16.9k
    f << "listId?=[" << std::hex;
1046
42.8k
    for (int j = 0; j < header.m_n; j++) {
1047
25.9k
      val = long(input->readULong(4));
1048
25.9k
      f << val << ",";
1049
25.9k
    }
1050
16.9k
    f << std::dec << "],";
1051
16.9k
    asciiFile.addPos(pos);
1052
16.9k
    asciiFile.addNote(f.str().c_str());
1053
16.9k
    if (input->tell()!=zoneEnd)
1054
16.9k
      asciiFile.addDelimiter(input->tell(),'|');
1055
16.9k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1056
16.9k
  }
1057
1058
4.21k
  pos = input->tell();
1059
4.21k
  if (pos!=endPos) {
1060
82
    f.str("");
1061
82
    f << entry.name() << "[last]:###";
1062
82
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZonesList: find unexpected end of data\n"));
1063
82
    asciiFile.addPos(pos);
1064
82
    asciiFile.addNote(f.str().c_str());
1065
82
  }
1066
1067
4.21k
  return true;
1068
6.57k
}
1069
1070
bool HanMacWrdJText::readTextZone(MWAWEntry const &entry, int actZone)
1071
17.4k
{
1072
17.4k
  if (!entry.valid()) {
1073
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: called without any entry\n"));
1074
0
    return false;
1075
0
  }
1076
17.4k
  if (entry.length() < 8+20*3) {
1077
83
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: the entry seems too short\n"));
1078
83
    return false;
1079
83
  }
1080
1081
17.3k
  MWAWInputStreamPtr input = m_parserState->m_input;
1082
17.3k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1083
17.3k
  libmwaw::DebugStream f;
1084
17.3k
  entry.setParsed(true);
1085
1086
17.3k
  long pos = entry.begin()+8; // skip header
1087
17.3k
  long endPos = entry.end();
1088
17.3k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1089
1090
17.3k
  if (actZone >= static_cast<int>(m_state->m_textZoneList.size()) || actZone < 0) {
1091
3.60k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: find an unexpected zone\n"));
1092
3.60k
    if (actZone < 0)
1093
0
      actZone = static_cast<int>(m_state->m_textZoneList.size());
1094
3.60k
    m_state->m_textZoneList.resize(size_t(actZone)+1);
1095
3.60k
  }
1096
17.3k
  auto &zone = m_state->m_textZoneList[size_t(actZone)];
1097
17.3k
  long val;
1098
1099
  // first read the char properties list
1100
17.3k
  std::vector<HanMacWrdJTextInternal::PLC> cPLCList;
1101
17.3k
  std::vector<MWAWVec2i> cPLCPosList; // 0:line, 1:char
1102
1103
17.3k
  f.str("");
1104
17.3k
  f << entry.name() << "-char:";
1105
1106
17.3k
  pos = input->tell();
1107
17.3k
  HanMacWrdJZoneHeader header(false);
1108
17.3k
  bool ok = true;
1109
17.3k
  if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=8) {
1110
2.78k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: can not read zone the char plc list\n"));
1111
2.78k
    f << "###";
1112
2.78k
    asciiFile.addPos(pos);
1113
2.78k
    asciiFile.addNote(f.str().c_str());
1114
2.78k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1115
2.78k
    ok = false;
1116
2.78k
  }
1117
14.5k
  else {
1118
14.5k
    f << header;
1119
14.5k
    long zoneEnd=pos+4+header.m_length;
1120
14.5k
    asciiFile.addPos(pos);
1121
14.5k
    asciiFile.addNote(f.str().c_str());
1122
1123
112k
    for (int j = 0; j < header.m_n; j++) {
1124
98.3k
      pos = input->tell();
1125
98.3k
      f.str("");
1126
98.3k
      MWAWVec2i cPos;
1127
98.3k
      cPos[0] = static_cast<int>(input->readLong(2));
1128
98.3k
      cPos[1] = static_cast<int>(input->readLong(2));
1129
98.3k
      HanMacWrdJTextInternal::PLC plc;
1130
98.3k
      plc.m_type = HanMacWrdJTextInternal::CHAR;
1131
98.3k
      plc.m_id = static_cast<int>(input->readLong(2));
1132
98.3k
      val = long(input->readULong(2)); // 0|1|4|5|f|26|2d|42|4e|4f|..|6a|6e|7a|7d
1133
98.3k
      if (val) f << "#f0=" << std::hex << val << std::dec << ",";
1134
98.3k
      plc.m_extra = f.str();
1135
98.3k
      cPLCPosList.push_back(cPos);
1136
98.3k
      cPLCList.push_back(plc);
1137
1138
98.3k
      f.str("");
1139
98.3k
      f << entry.name() << "-Char" << j << "]:lcPos=" << cPos << "," << plc;
1140
98.3k
      asciiFile.addPos(pos);
1141
98.3k
      asciiFile.addNote(f.str().c_str());
1142
98.3k
      input->seek(pos+header.m_fieldSize, librevenge::RVNG_SEEK_SET);
1143
98.3k
    }
1144
1145
14.5k
    if (input->tell() != zoneEnd) { // junk ?
1146
14.5k
      asciiFile.addDelimiter(input->tell(),'|');
1147
14.5k
      input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1148
14.5k
    }
1149
14.5k
  }
1150
1151
  // second read the ruler list
1152
17.3k
  std::map<int, HanMacWrdJTextInternal::PLC> rLineRulerMap;
1153
1154
17.3k
  f.str("");
1155
17.3k
  f << entry.name() << "-ruler:";
1156
1157
17.3k
  pos = input->tell();
1158
17.3k
  header=HanMacWrdJZoneHeader(false);
1159
17.3k
  if (!ok) {
1160
2.78k
  }
1161
14.5k
  else if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=8) {
1162
2.50k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: can not read zone the ruler plc list\n"));
1163
2.50k
    f << "###";
1164
2.50k
    asciiFile.addPos(pos);
1165
2.50k
    asciiFile.addNote(f.str().c_str());
1166
2.50k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1167
2.50k
    ok = false;
1168
2.50k
  }
1169
12.0k
  else {
1170
12.0k
    f << header;
1171
12.0k
    long zoneEnd=pos+4+header.m_length;
1172
12.0k
    asciiFile.addPos(pos);
1173
12.0k
    asciiFile.addNote(f.str().c_str());
1174
1175
55.1k
    for (int j = 0; j < header.m_n; j++) {
1176
43.0k
      pos = input->tell();
1177
43.0k
      f.str("");
1178
43.0k
      auto line = static_cast<int>(input->readLong(2));
1179
43.0k
      HanMacWrdJTextInternal::PLC plc;
1180
43.0k
      plc.m_type = HanMacWrdJTextInternal::RULER;
1181
43.0k
      plc.m_id = static_cast<int>(input->readLong(2));
1182
1183
43.0k
      val = long(input->readULong(4)); // find 0,000008a0, 023ddd20, 0046ddbb, 5808001d, 5808004e
1184
43.0k
      if (val) f << "#f0=" << std::hex << val << std::dec << ",";
1185
43.0k
      plc.m_extra = f.str();
1186
43.0k
      if (rLineRulerMap.find(line) !=  rLineRulerMap.end()) {
1187
2.15k
        MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: already find a ruler for line=%d\n",line));
1188
2.15k
        f << "###";
1189
2.15k
      }
1190
40.8k
      else
1191
40.8k
        rLineRulerMap[line]=plc;
1192
1193
43.0k
      f.str("");
1194
43.0k
      f << entry.name() << "-Ruler" << j << "]:line=" << line << "," << plc;
1195
43.0k
      asciiFile.addPos(pos);
1196
43.0k
      asciiFile.addNote(f.str().c_str());
1197
43.0k
      input->seek(pos+header.m_fieldSize, librevenge::RVNG_SEEK_SET);
1198
43.0k
    }
1199
1200
12.0k
    if (input->tell() != zoneEnd) { // junk ?
1201
12.0k
      asciiFile.addDelimiter(input->tell(),'|');
1202
12.0k
      input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1203
12.0k
    }
1204
12.0k
  }
1205
1206
  // now we can read the line position
1207
17.3k
  std::vector<long> linePosList;
1208
1209
17.3k
  f.str("");
1210
17.3k
  f << entry.name() << "-line:";
1211
17.3k
  pos = input->tell();
1212
17.3k
  header=HanMacWrdJZoneHeader(false);
1213
17.3k
  if (!ok) {
1214
5.29k
  }
1215
12.0k
  else if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=4) {
1216
1.13k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: can not read zone the line plc list\n"));
1217
1.13k
    f << "###";
1218
1.13k
    asciiFile.addPos(pos);
1219
1.13k
    asciiFile.addNote(f.str().c_str());
1220
1.13k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1221
1.13k
    ok = false;
1222
1.13k
  }
1223
10.9k
  else {
1224
10.9k
    f << header;
1225
10.9k
    long zoneEnd=pos+4+header.m_length;
1226
10.9k
    asciiFile.addPos(pos);
1227
10.9k
    asciiFile.addNote(f.str().c_str());
1228
10.9k
    HanMacWrdJTextInternal::PLC plc;
1229
10.9k
    plc.m_type = HanMacWrdJTextInternal::LINE;
1230
1231
10.9k
    f << "linePos=[" << std::hex;
1232
80.6k
    for (int j = 0; j < header.m_n; j++) {
1233
69.6k
      long linePos = input->readLong(4);
1234
69.6k
      linePosList.push_back(linePos);
1235
69.6k
      plc.m_id = j;
1236
69.6k
      zone.m_PLCMap.insert
1237
69.6k
      (std::multimap<long, HanMacWrdJTextInternal::PLC>::value_type(linePos, plc));
1238
69.6k
      f << linePos << ",";
1239
69.6k
    }
1240
10.9k
    f << std::dec << "],";
1241
10.9k
    asciiFile.addPos(pos);
1242
10.9k
    asciiFile.addNote(f.str().c_str());
1243
1244
10.9k
    if (input->tell() != zoneEnd) { // junk ?
1245
10.9k
      asciiFile.addDelimiter(input->tell(),'|');
1246
10.9k
      input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1247
10.9k
    }
1248
10.9k
  }
1249
1250
  // ok, we can now update the plc
1251
17.3k
  if (ok) {
1252
10.9k
    auto nLines = int(linePosList.size());
1253
36.6k
    for (auto const &rIt : rLineRulerMap) {
1254
36.6k
      int line = rIt.first;
1255
36.6k
      if (line < 0 || line >= nLines) {
1256
3.03k
        MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: build rule plc, can not find line %d\n", line));
1257
3.03k
        continue;
1258
1259
3.03k
      }
1260
33.5k
      zone.m_PLCMap.insert
1261
33.5k
      (std::multimap<long, HanMacWrdJTextInternal::PLC>::value_type(linePosList[size_t(line)], rIt.second));
1262
33.5k
    }
1263
10.9k
    size_t numCProp = cPLCPosList.size();
1264
10.9k
    if (numCProp != cPLCList.size()) {
1265
0
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: cPLCPosList and cPLCList have not the same size\n"));
1266
0
      if (numCProp > cPLCList.size())
1267
0
        numCProp = cPLCList.size();
1268
0
    }
1269
68.2k
    for (size_t i = 0; i < numCProp; i++) {
1270
57.3k
      int line = cPLCPosList[i][0];
1271
57.3k
      if (line < 0 || line >= nLines) {
1272
4.33k
        MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: build char plc, can not find line %d\n", line));
1273
4.33k
        continue;
1274
4.33k
      }
1275
52.9k
      long cPos = linePosList[size_t(line)]+long(cPLCPosList[i][1]);
1276
52.9k
      zone.m_PLCMap.insert
1277
52.9k
      (std::multimap<long, HanMacWrdJTextInternal::PLC>::value_type(cPos, cPLCList[i]));
1278
52.9k
    }
1279
10.9k
  }
1280
17.3k
  asciiFile.addPos(endPos);
1281
17.3k
  asciiFile.addNote("_");
1282
1283
  // now potentially a token zone, called with endPos-1 to avoid reading the last text zone
1284
17.3k
  readTextToken(endPos-1, zone);
1285
1286
17.3k
  pos = input->tell();
1287
17.3k
  if (pos==endPos) {
1288
17
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: can not read find the last zone\n"));
1289
1290
17
    return true;
1291
17
  }
1292
1293
  // normally now the text data but check if there remains some intermediar unparsed zone
1294
17.3k
  auto dataSz = long(input->readULong(4));
1295
21.1k
  while (dataSz>0 && pos+4+dataSz < endPos) {
1296
3.80k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: find some unparsed zone\n"));
1297
3.80k
    f.str("");
1298
3.80k
    f << entry.name() << "-###:";
1299
3.80k
    asciiFile.addPos(pos);
1300
3.80k
    asciiFile.addNote(f.str().c_str());
1301
1302
3.80k
    pos = pos+4+dataSz;
1303
3.80k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1304
3.80k
    dataSz = long(input->readULong(4));
1305
3.80k
  }
1306
17.3k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1307
1308
  // the text data
1309
17.3k
  f.str("");
1310
17.3k
  f << entry.name() << "-text:";
1311
17.3k
  dataSz = long(input->readULong(4));
1312
17.3k
  if (pos+4+dataSz>endPos) {
1313
1.11k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readTextZone: can not read last zone size\n"));
1314
1.11k
    f << "###sz=" << dataSz;
1315
1.11k
    asciiFile.addPos(pos);
1316
1.11k
    asciiFile.addNote(f.str().c_str());
1317
1.11k
    return false;
1318
1.11k
  }
1319
1320
16.2k
  asciiFile.addPos(pos);
1321
16.2k
  asciiFile.addNote(f.str().c_str());
1322
1323
16.2k
  zone.m_entry.setBegin(pos);
1324
16.2k
  zone.m_entry.setEnd(endPos);
1325
16.2k
  zone.m_entry.setName(entry.name());
1326
1327
16.2k
  return true;
1328
17.3k
}
1329
1330
bool HanMacWrdJText::readTextToken(long endPos, HanMacWrdJTextInternal::TextZone &zone)
1331
17.3k
{
1332
17.3k
  MWAWInputStreamPtr input = m_parserState->m_input;
1333
17.3k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1334
17.3k
  libmwaw::DebugStream f;
1335
17.3k
  long pos=input->tell();
1336
17.3k
  if (pos+4>=endPos)
1337
36
    return true;
1338
1339
17.3k
  f << "Entries(TextToken):";
1340
17.3k
  HanMacWrdJZoneHeader header(false);
1341
17.3k
  if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=16 ||
1342
14.8k
      16+16*header.m_n+4 > header.m_length) {
1343
14.8k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1344
14.8k
    return true;
1345
14.8k
  }
1346
2.45k
  int val;
1347
7.37k
  for (int i = 0; i < 2; i++) { // always 0?
1348
4.91k
    val = static_cast<int>(input->readLong(2));
1349
4.91k
    if (val) f << "f" << i << "=" << val << ",";
1350
4.91k
  }
1351
2.45k
  f << header;
1352
2.45k
  long zoneEnd=pos+4+header.m_length;
1353
2.45k
  asciiFile.addPos(pos);
1354
2.45k
  asciiFile.addNote(f.str().c_str());
1355
1356
2.45k
  HanMacWrdJTextInternal::PLC plc(HanMacWrdJTextInternal::TOKEN);
1357
2.45k
  std::vector<int> bkmIdList;
1358
5.13k
  for (int i = 0; i < header.m_n; i++) {
1359
2.68k
    pos = input->tell();
1360
2.68k
    f.str("");
1361
2.68k
    HanMacWrdJTextInternal::Token tkn;
1362
2.68k
    long fPos = input->readLong(4);
1363
1364
2.68k
    val = static_cast<int>(input->readLong(2)); // always 0 ?
1365
2.68k
    if (val) f << "f0=" << val << ",";
1366
2.68k
    tkn.m_length=static_cast<int>(input->readLong(2));
1367
2.68k
    tkn.m_id = long(input->readULong(4));
1368
1369
2.68k
    tkn.m_type=static_cast<int>(input->readLong(1));
1370
8.04k
    for (int j=0; j < 2; j++) { // f1=0, f2=0|1[field]|11[footnote]
1371
5.36k
      val = static_cast<int>(input->readLong(1));
1372
5.36k
      if (val) f << "f" << j+1 << "=" << val << ",";
1373
5.36k
    }
1374
2.68k
    tkn.m_localId = static_cast<int>(input->readLong(1));
1375
2.68k
    tkn.m_extra = f.str();
1376
2.68k
    zone.m_tokenList.push_back(tkn);
1377
2.68k
    if (tkn.m_type==0x20)
1378
13
      bkmIdList.push_back(i);
1379
2.68k
    plc.m_id = i;
1380
2.68k
    zone.m_PLCMap.insert(std::multimap<long, HanMacWrdJTextInternal::PLC>::value_type(fPos, plc));
1381
1382
2.68k
    f.str("");
1383
2.68k
    f << "TextToken-" << i << ":";
1384
2.68k
    if (fPos) f << "fPos=" << std::hex << fPos << std::dec << ",";
1385
2.68k
    f << tkn;
1386
2.68k
    asciiFile.addPos(pos);
1387
2.68k
    asciiFile.addNote(f.str().c_str());
1388
2.68k
    input->seek(pos+16, librevenge::RVNG_SEEK_SET);
1389
2.68k
  }
1390
1391
2.45k
  if (input->tell() != zoneEnd) {
1392
2.44k
    asciiFile.addDelimiter(input->tell(),'|');
1393
2.44k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1394
2.44k
  }
1395
1396
2.45k
  pos = input->tell();
1397
  // next: we can find potential bookmark zone
1398
2.46k
  for (size_t i=0; i < bkmIdList.size(); i++) {
1399
13
    pos = input->tell();
1400
13
    auto dataSz = long(input->readULong(4));
1401
13
    zoneEnd = pos+4+dataSz;
1402
13
    if (input->isEnd() || dataSz<0 || zoneEnd >= endPos) {
1403
11
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextToken: can not find bookmark text %d\n", int(i)));
1404
11
      break;
1405
11
    }
1406
1407
2
    f.str("");
1408
2
    f << "TextToken-data" << i << ":";
1409
2
    asciiFile.addPos(pos);
1410
2
    asciiFile.addNote(f.str().c_str());
1411
2
    auto fSz=static_cast<int>(input->readULong(1));
1412
2
    if (fSz == dataSz-2 || fSz==dataSz-1) {
1413
1
      std::string bkmark("");
1414
1
      for (int c=0; c < fSz; c++)
1415
0
        bkmark+=char(input->readULong(1));
1416
1
      f << bkmark;
1417
1418
1
      zone.m_tokenList[size_t(bkmIdList[i])].m_bookmark=bkmark;
1419
1
    }
1420
1
    else {
1421
1
      MWAW_DEBUG_MSG(("HanMacWrdJText::readTextToken: can not read bookmark text %d\n", int(i)));
1422
1
      f << "###";
1423
1
    }
1424
2
    asciiFile.addPos(pos);
1425
2
    asciiFile.addNote(f.str().c_str());
1426
1427
2
    pos = zoneEnd;
1428
2
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
1429
2
  }
1430
2.45k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1431
2.45k
  return true;
1432
17.3k
}
1433
1434
////////////////////////////////////////////////////////////
1435
//     Fonts
1436
////////////////////////////////////////////////////////////
1437
1438
// a single font
1439
bool HanMacWrdJText::readFont(MWAWFont &font, long endPos)
1440
73.8k
{
1441
73.8k
  font = MWAWFont(-1, -1);
1442
1443
73.8k
  MWAWInputStreamPtr input = m_parserState->m_input;
1444
73.8k
  long pos = input->tell(), debPos=pos;
1445
73.8k
  if (endPos <= 0) {
1446
73.8k
    auto dataSz=long(input->readULong(4));
1447
73.8k
    pos+=4;
1448
73.8k
    endPos=pos+dataSz;
1449
73.8k
    if (!input->checkPosition(endPos)) {
1450
1.90k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readFont: pb reading font size\n"));
1451
1.90k
      input->seek(debPos, librevenge::RVNG_SEEK_SET);
1452
1.90k
      return false;
1453
1.90k
    }
1454
73.8k
  }
1455
71.9k
  long len=endPos-pos;
1456
71.9k
  if (len < 24) {
1457
609
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFont: the zone is too short\n"));
1458
609
    input->seek(debPos, librevenge::RVNG_SEEK_SET);
1459
609
    return false;
1460
609
  }
1461
1462
71.3k
  libmwaw::DebugStream f;
1463
71.3k
  font.setId(static_cast<int>(input->readLong(2)));
1464
71.3k
  auto val = static_cast<int>(input->readLong(2));
1465
71.3k
  if (val) f << "#f1=" << val << ",";
1466
71.3k
  font.setSize(float(input->readLong(4))/65536.f);
1467
71.3k
  float expand = float(input->readLong(4))/65536.f;
1468
71.3k
  if (expand < 0 || expand > 0)
1469
735
    font.setDeltaLetterSpacing(expand*font.size());
1470
71.3k
  float xScale = float(input->readLong(4))/65536.f;
1471
71.3k
  if (xScale < 1 || xScale > 1)
1472
2.09k
    font.setWidthStreching(xScale);
1473
1474
71.3k
  auto flag =static_cast<int>(input->readULong(2));
1475
71.3k
  uint32_t flags=0;
1476
71.3k
  if (flag&1) {
1477
134
    font.setUnderlineStyle(MWAWFont::Line::Simple);
1478
134
    font.setUnderlineType(MWAWFont::Line::Double);
1479
134
  }
1480
71.3k
  if (flag&2)
1481
170
    font.setUnderlineStyle(MWAWFont::Line::Dot);
1482
71.3k
  if (flag&4) {
1483
269
    font.setUnderlineStyle(MWAWFont::Line::Dot);
1484
269
    font.setUnderlineWidth(2.0);
1485
269
  }
1486
71.3k
  if (flag&8)
1487
424
    font.setUnderlineStyle(MWAWFont::Line::Dash);
1488
71.3k
  if (flag&0x10)
1489
1.06k
    font.setStrikeOutStyle(MWAWFont::Line::Simple);
1490
71.3k
  if (flag&0x20) {
1491
1.08k
    font.setStrikeOutStyle(MWAWFont::Line::Simple);
1492
1.08k
    font.setStrikeOutType(MWAWFont::Line::Double);
1493
1.08k
  }
1494
71.3k
  if (flag&0xFFC0)
1495
1.35k
    f << "#flag0=" << std::hex << (flag&0xFFF2) << std::dec << ",";
1496
71.3k
  flag =static_cast<int>(input->readULong(2));
1497
71.3k
  if (flag&1) flags |= MWAWFont::boldBit;
1498
71.3k
  if (flag&0x2) flags |= MWAWFont::italicBit;
1499
71.3k
  if (flag&0x4) flags |= MWAWFont::outlineBit;
1500
71.3k
  if (flag&0x8) flags |= MWAWFont::shadowBit;
1501
71.3k
  if (flag&0x10) flags |= MWAWFont::reverseVideoBit;
1502
71.3k
  if (flag&0x20) font.set(MWAWFont::Script::super100());
1503
71.3k
  if (flag&0x40) font.set(MWAWFont::Script::sub100());
1504
71.3k
  if (flag&0x80) {
1505
4.62k
    if (flag&0x20)
1506
671
      font.set(MWAWFont::Script(48,librevenge::RVNG_PERCENT,58));
1507
3.95k
    else if (flag&0x40)
1508
3.91k
      font.set(MWAWFont::Script(16,librevenge::RVNG_PERCENT,58));
1509
39
    else
1510
39
      font.set(MWAWFont::Script::super());
1511
4.62k
  }
1512
71.3k
  if (flag&0x100) {
1513
3.92k
    font.setOverlineStyle(MWAWFont::Line::Dot);
1514
3.92k
    font.setOverlineWidth(2.0);
1515
3.92k
  }
1516
71.3k
  if (flag&0x200) flags |= MWAWFont::boxedBit;
1517
71.3k
  if (flag&0x400) flags |= MWAWFont::boxedRoundedBit;
1518
71.3k
  if (flag&0x800) {
1519
4.55k
    font.setUnderlineStyle(MWAWFont::Line::Simple);
1520
4.55k
    font.setUnderlineWidth(0.5);
1521
4.55k
  }
1522
71.3k
  if (flag&0x1000) font.setUnderlineStyle(MWAWFont::Line::Simple);
1523
71.3k
  if (flag&0x2000) {
1524
1.03k
    font.setUnderlineStyle(MWAWFont::Line::Simple);
1525
1.03k
    font.setUnderlineWidth(2.0);
1526
1.03k
  }
1527
71.3k
  if (flag&0x4000) {
1528
731
    font.setUnderlineStyle(MWAWFont::Line::Simple);
1529
731
    font.setUnderlineWidth(3.0);
1530
731
  }
1531
1532
71.3k
  if (flag&0x8000) {
1533
685
    font.setUnderlineStyle(MWAWFont::Line::Simple);
1534
685
    font.setUnderlineType(MWAWFont::Line::Double);
1535
685
    font.setUnderlineWidth(0.5);
1536
685
  }
1537
71.3k
  auto color = static_cast<int>(input->readLong(2));
1538
71.3k
  MWAWColor col;
1539
71.3k
  if (color && m_mainParser->getColor(color, 1, col))
1540
80
    font.setColor(col);
1541
71.2k
  else if (color)
1542
1.29k
    f << "##fColor=" << color << ",";
1543
71.3k
  val = static_cast<int>(input->readLong(2));
1544
71.3k
  if (val) f << "#unk=" << val << ",";
1545
71.3k
  if (len >= 28) {
1546
213k
    for (int i = 0; i < 2; i++) {
1547
142k
      val = static_cast<int>(input->readLong(2));
1548
142k
      if (val) f << "#g" << i << "=" << val << ",";
1549
142k
    }
1550
71.2k
  }
1551
71.3k
  if (len >= 36) {
1552
71.1k
    color = static_cast<int>(input->readLong(2));
1553
71.1k
    auto pattern = static_cast<int>(input->readLong(2));
1554
71.1k
    if ((color || pattern) && m_mainParser->getColor(color, pattern, col))
1555
142
      font.setBackgroundColor(col);
1556
70.9k
    else if (color || pattern)
1557
1.30k
      f << "#backColor=" << color << ", #pattern=" << pattern << ",";
1558
71.1k
  }
1559
71.3k
  if (input->tell() != endPos)
1560
71.2k
    m_parserState->m_asciiFile.addDelimiter(input->tell(),'|');
1561
71.3k
  font.setFlags(flags);
1562
71.3k
  font.m_extra = f.str();
1563
1564
71.3k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1565
71.3k
  return true;
1566
71.9k
}
1567
1568
bool HanMacWrdJText::readFonts(MWAWEntry const &entry)
1569
14.3k
{
1570
14.3k
  if (!entry.valid()) {
1571
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFonts: called without any entry\n"));
1572
0
    return false;
1573
0
  }
1574
14.3k
  if (entry.length() <= 8) {
1575
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFonts: the entry seems too short\n"));
1576
0
    return false;
1577
0
  }
1578
14.3k
  if (m_state->m_fontList.size()) {
1579
993
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFonts: oops the font list is not empty\n"));
1580
993
    m_state->m_fontList.resize(0);
1581
993
  }
1582
14.3k
  MWAWInputStreamPtr input = m_parserState->m_input;
1583
14.3k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1584
14.3k
  libmwaw::DebugStream f;
1585
14.3k
  entry.setParsed(true);
1586
1587
14.3k
  long pos = entry.begin()+8; // skip header
1588
14.3k
  long endPos = entry.end();
1589
14.3k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1590
1591
  // first read the header
1592
14.3k
  f << entry.name() << "[header]:";
1593
14.3k
  HanMacWrdJZoneHeader mainHeader(false);
1594
14.3k
  if (!m_mainParser->readClassicHeader(mainHeader,endPos) || mainHeader.m_fieldSize!=8) {
1595
8.16k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFonts: can not read the header\n"));
1596
8.16k
    f << "###sz=" << mainHeader.m_length;
1597
8.16k
    asciiFile.addPos(pos);
1598
8.16k
    asciiFile.addNote(f.str().c_str());
1599
8.16k
    return false;
1600
8.16k
  }
1601
6.20k
  long headerEnd=pos+4+mainHeader.m_length;
1602
6.20k
  f << mainHeader;
1603
6.20k
  f << "unk=[";
1604
115k
  for (int i = 0; i < mainHeader.m_n; i++) {
1605
109k
    f << "[";
1606
109k
    long val = input->readLong(2); // always -2 ?
1607
109k
    if (val!=-2)
1608
6.87k
      f << val << ",";
1609
102k
    else
1610
102k
      f << "_,";
1611
109k
    val = long(input->readULong(2)); // 0 or 5020 : junk?
1612
109k
    if (val)
1613
102k
      f << std::hex << val << std::dec << ",";
1614
6.80k
    else
1615
6.80k
      f << "_,";
1616
109k
    val = long(input->readULong(4)); // id
1617
109k
    f << std::hex << val << std::dec;
1618
109k
    f << "]";
1619
109k
  }
1620
6.20k
  f << "],";
1621
6.20k
  if (input->tell()!=headerEnd) {
1622
6.20k
    asciiFile.addDelimiter(input->tell(),'|');
1623
6.20k
    input->seek(headerEnd, librevenge::RVNG_SEEK_SET);
1624
6.20k
  }
1625
6.20k
  asciiFile.addPos(pos);
1626
6.20k
  asciiFile.addNote(f.str().c_str());
1627
1628
77.3k
  for (int i = 0; i < mainHeader.m_n; i++) {
1629
73.8k
    pos = input->tell();
1630
73.8k
    f.str("");
1631
73.8k
    f << entry.name() << "-" << i << ":";
1632
73.8k
    MWAWFont font(-1, -1);
1633
73.8k
    if (!readFont(font) || input->tell() > endPos) {
1634
2.66k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readFonts: can not read font %d\n", i));
1635
2.66k
      f << "###";
1636
2.66k
      asciiFile.addPos(pos);
1637
2.66k
      asciiFile.addNote(f.str().c_str());
1638
2.66k
      return false;
1639
2.66k
    }
1640
71.1k
    f << font.getDebugString(m_parserState->m_fontConverter) << ",";
1641
71.1k
    m_state->m_fontList.push_back(font);
1642
71.1k
    asciiFile.addPos(pos);
1643
71.1k
    asciiFile.addNote(f.str().c_str());
1644
71.1k
  }
1645
3.54k
  asciiFile.addPos(endPos);
1646
3.54k
  asciiFile.addNote("_");
1647
3.54k
  return true;
1648
6.20k
}
1649
1650
// the list of fonts
1651
bool HanMacWrdJText::readFontNames(MWAWEntry const &entry)
1652
2.29k
{
1653
2.29k
  if (!entry.valid()) {
1654
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: called without any entry\n"));
1655
0
    return false;
1656
0
  }
1657
2.29k
  if (entry.length() < 28) {
1658
72
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: the entry seems too short\n"));
1659
72
    return false;
1660
72
  }
1661
2.22k
  MWAWInputStreamPtr input = m_parserState->m_input;
1662
2.22k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1663
2.22k
  libmwaw::DebugStream f;
1664
2.22k
  entry.setParsed(true);
1665
1666
2.22k
  f << entry.name() << "[data]:";
1667
1668
2.22k
  long pos = entry.begin()+8; // skip header
1669
2.22k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1670
2.22k
  int N, val;
1671
2.22k
  auto readDataSz = long(input->readULong(4));
1672
2.22k
  if (readDataSz+12 != entry.length()) {
1673
163
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: the data size seems odd\n"));
1674
163
    f << "##dataSz=" << readDataSz << ",";
1675
163
  }
1676
2.22k
  N = static_cast<int>(input->readLong(2));
1677
2.22k
  f << "N=" << N << ",";
1678
2.22k
  auto fieldSz = long(input->readULong(4));
1679
2.22k
  if (fieldSz != 68) {
1680
166
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: the field size seems odd\n"));
1681
166
    f << "##fieldSz=" << fieldSz << ",";
1682
166
  }
1683
8.89k
  for (int i = 0; i < 3; i++) { //f1=f2=1
1684
6.66k
    val = static_cast<int>(input->readLong(2));
1685
6.66k
    if (val) f << "f" << i << "=" << val << ",";
1686
6.66k
  }
1687
2.22k
  auto id = long(input->readULong(4));
1688
2.22k
  if (id) f << "id=" << std::hex << id << std::dec << ",";
1689
1690
2.22k
  long expectedSz = N*68+28;
1691
2.22k
  if (expectedSz != entry.length() && expectedSz+1 != entry.length()) {
1692
162
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: the entry size seems odd\n"));
1693
162
    return false;
1694
162
  }
1695
2.06k
  asciiFile.addPos(pos);
1696
2.06k
  asciiFile.addNote(f.str().c_str());
1697
1698
4.12k
  for (int i = 0; i < N; i++) {
1699
2.05k
    pos = input->tell();
1700
2.05k
    f.str("");
1701
2.05k
    f << entry.name() << "-" << i << ":";
1702
2.05k
    auto fId = static_cast<int>(input->readLong(2));
1703
2.05k
    f << "fId=" << fId << ",";
1704
2.05k
    val = static_cast<int>(input->readLong(2));
1705
2.05k
    if (val != fId)
1706
41
      f << "#fId2=" << val << ",";
1707
2.05k
    auto fSz = static_cast<int>(input->readULong(1));
1708
2.05k
    if (fSz+5 > 68) {
1709
35
      f << "###fSz";
1710
35
      MWAW_DEBUG_MSG(("HanMacWrdJText::readFontNames: can not read a font\n"));
1711
35
    }
1712
2.02k
    else {
1713
2.02k
      std::string name("");
1714
14.4k
      for (int c = 0; c < fSz; c++)
1715
12.4k
        name += char(input->readULong(1));
1716
2.02k
      f << name;
1717
2.02k
      m_parserState->m_fontConverter->setCorrespondance(fId, name);
1718
2.02k
    }
1719
2.05k
    asciiFile.addPos(pos);
1720
2.05k
    asciiFile.addNote(f.str().c_str());
1721
2.05k
    input->seek(pos+68, librevenge::RVNG_SEEK_SET);
1722
2.05k
  }
1723
2.06k
  asciiFile.addPos(entry.end());
1724
2.06k
  asciiFile.addNote("_");
1725
2.06k
  return true;
1726
2.22k
}
1727
1728
////////////////////////////////////////////////////////////
1729
//     Style
1730
////////////////////////////////////////////////////////////
1731
bool HanMacWrdJText::readStyles(MWAWEntry const &entry)
1732
9.35k
{
1733
9.35k
  if (!entry.valid()) {
1734
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readStyles: called without any zone\n"));
1735
0
    return false;
1736
0
  }
1737
1738
9.35k
  long dataSz = entry.length();
1739
9.35k
  if (dataSz < 4) {
1740
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readStyles: the zone seems too short\n"));
1741
0
    return false;
1742
0
  }
1743
9.35k
  MWAWInputStreamPtr input = m_parserState->m_input;
1744
9.35k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1745
9.35k
  libmwaw::DebugStream f;
1746
9.35k
  entry.setParsed(true);
1747
1748
9.35k
  f << entry.name() << "[header]:";
1749
1750
9.35k
  long pos = entry.begin()+8; // skip header
1751
9.35k
  long endPos = entry.end();
1752
9.35k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1753
1754
9.35k
  HanMacWrdJZoneHeader mainHeader(false);
1755
9.35k
  if (!m_mainParser->readClassicHeader(mainHeader,endPos) || mainHeader.m_fieldSize!=4) {
1756
1.34k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readStyles: can not read the header\n"));
1757
1.34k
    f << "###sz=" << mainHeader.m_length;
1758
1.34k
    asciiFile.addPos(pos);
1759
1.34k
    asciiFile.addNote(f.str().c_str());
1760
1.34k
    return false;
1761
1.34k
  }
1762
8.01k
  long headerEnd=pos+4+mainHeader.m_length;
1763
8.01k
  f << mainHeader;
1764
1765
8.01k
  f << "listIds=[" << std::hex;
1766
148k
  for (int i = 0; i < mainHeader.m_n; i++)
1767
140k
    f << input->readULong(4) << ",";
1768
8.01k
  f << std::dec << "],";
1769
8.01k
  input->seek(headerEnd, librevenge::RVNG_SEEK_SET);
1770
8.01k
  asciiFile.addPos(pos);
1771
8.01k
  asciiFile.addNote(f.str().c_str());
1772
1773
113k
  for (int i = 0; i < mainHeader.m_n; i++) {
1774
108k
    f.str("");
1775
108k
    f << entry.name() << "-" << i << ":";
1776
108k
    pos = input->tell();
1777
108k
    long fieldSz = long(input->readULong(4))+4;
1778
108k
    if (fieldSz < 0x1bc || pos+fieldSz > endPos) {
1779
3.13k
      f << "###";
1780
3.13k
      asciiFile.addPos(pos);
1781
3.13k
      asciiFile.addNote(f.str().c_str());
1782
1783
3.13k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readStyles: can not read field %d\n", i));
1784
3.13k
      return true;
1785
3.13k
    }
1786
105k
    auto val = static_cast<int>(input->readULong(1));
1787
105k
    if (val != i) f << "#id=" << val << ",";
1788
1789
    // f0=c2|c6, f2=0|44, f3=1|14|15|16: fontId?
1790
633k
    for (int j=0; j < 5; j++) {
1791
527k
      val = static_cast<int>(input->readULong(1));
1792
527k
      if (val)
1793
211k
        f << "f" << j << "=" << std::hex << val << std::dec << ",";
1794
527k
    }
1795
    /* g1=9|a|c|e|12|18: size ?, g5=1, g8=0|1, g25=0|18|30|48, g31=1, g35=0|1 */
1796
3.58M
    for (int j=0; j < 33; j++) {
1797
3.48M
      val = static_cast<int>(input->readULong(2));
1798
3.48M
      if (val)
1799
524k
        f << "g" << j << "=" << val  << ",";
1800
3.48M
    }
1801
527k
    for (int j=0; j < 4; j++) { // b,b,b,0
1802
422k
      val = static_cast<int>(input->readULong(1));
1803
422k
      if ((j < 3 && val != 0xb) || (j==3 && val))
1804
1.92k
        f << "h" << j << "=" << val  << ",";
1805
422k
    }
1806
1807
1.89M
    for (int j=0; j < 17; j++) { // always 0
1808
1.79M
      val = static_cast<int>(input->readULong(2));
1809
1.79M
      if (val)
1810
10.1k
        f << "l" << j << "=" << val  << ",";
1811
1.79M
    }
1812
105k
    asciiFile.addPos(pos);
1813
105k
    asciiFile.addNote(f.str().c_str());
1814
105k
    long pos2 = input->tell();
1815
105k
    f.str("");
1816
105k
    f << entry.name() << "-" << i << "[B]:";
1817
    // checkme probably f15=numTabs  ..
1818
5.38M
    for (int j = 0; j < 50; j++) {
1819
5.27M
      val = static_cast<int>(input->readULong(2));
1820
5.27M
      if ((j < 5 && val != 1) || (j >= 5 && val))
1821
11.8k
        f << "f" << j << "=" << val  << ",";
1822
5.27M
    }
1823
5.38M
    for (int j = 0; j < 50; j++) {
1824
5.27M
      val = static_cast<int>(input->readULong(2));
1825
5.27M
      if (val)
1826
4.38k
        f << "g" << j << "=" << val  << ",";
1827
5.27M
    }
1828
4.64M
    for (int j = 0; j < 43; j++) {
1829
4.53M
      val = static_cast<int>(input->readULong(2));
1830
4.53M
      if (val)
1831
8.92k
        f << "h" << j << "=" << val  << ",";
1832
4.53M
    }
1833
105k
    asciiFile.addPos(pos2);
1834
105k
    asciiFile.addNote(f.str().c_str());
1835
1836
105k
    pos2 = input->tell();
1837
105k
    f.str("");
1838
105k
    f << entry.name() << "-" << i << "[C]:";
1839
105k
    val = static_cast<int>(input->readLong(2));
1840
105k
    if (val != -1) f << "unkn=" << val << ",";
1841
105k
    val  = static_cast<int>(input->readLong(2));
1842
105k
    if (val != i) f << "#id" << val << ",";
1843
527k
    for (int j = 0; j < 4; j++) {
1844
422k
      val = static_cast<int>(input->readLong(2));
1845
422k
      if (val) f << "f" << j << "=" << val << ",";
1846
422k
    }
1847
105k
    auto fSz = static_cast<int>(input->readULong(1));
1848
105k
    if (input->tell()+fSz > pos+fieldSz) {
1849
180
      MWAW_DEBUG_MSG(("HanMacWrdJText::readStyles: can not read styleName\n"));
1850
180
      f << "###";
1851
180
    }
1852
105k
    else {
1853
105k
      std::string name("");
1854
797k
      for (int j = 0; j < fSz; j++)
1855
692k
        name +=char(input->readULong(1));
1856
105k
      f << name;
1857
105k
    }
1858
105k
    asciiFile.addPos(pos2);
1859
105k
    asciiFile.addNote(f.str().c_str());
1860
105k
    if (input->tell() != pos+fieldSz)
1861
105k
      asciiFile.addDelimiter(input->tell(),'|');
1862
1863
105k
    input->seek(pos+fieldSz, librevenge::RVNG_SEEK_SET);
1864
105k
  }
1865
1866
4.87k
  if (!input->isEnd()) {
1867
4.87k
    asciiFile.addPos(input->tell());
1868
4.87k
    asciiFile.addNote("_");
1869
4.87k
  }
1870
4.87k
  return true;
1871
8.01k
}
1872
1873
////////////////////////////////////////////////////////////
1874
//     Paragraph
1875
////////////////////////////////////////////////////////////
1876
bool HanMacWrdJText::readParagraph(HanMacWrdJTextInternal::Paragraph &para, long endPos)
1877
52.9k
{
1878
52.9k
  para = HanMacWrdJTextInternal::Paragraph();
1879
1880
52.9k
  MWAWInputStreamPtr input = m_parserState->m_input;
1881
52.9k
  long pos = input->tell(), debPos=pos;
1882
52.9k
  if (endPos <= 0) {
1883
52.9k
    auto dataSz=long(input->readULong(4));
1884
52.9k
    pos+=4;
1885
52.9k
    endPos=pos+dataSz;
1886
52.9k
    if (!input->checkPosition(endPos)) {
1887
1.43k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraph: pb reading para size\n"));
1888
1.43k
      input->seek(debPos, librevenge::RVNG_SEEK_SET);
1889
1.43k
      return false;
1890
1.43k
    }
1891
52.9k
  }
1892
51.5k
  long len=endPos-pos;
1893
51.5k
  if (len < 102) {
1894
715
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraph: the zone is too short\n"));
1895
715
    input->seek(debPos, librevenge::RVNG_SEEK_SET);
1896
715
    return false;
1897
715
  }
1898
1899
50.8k
  libmwaw::DebugStream f;
1900
50.8k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
1901
50.8k
  auto flags = static_cast<int>(input->readULong(1));
1902
50.8k
  if (flags&0x80)
1903
76
    para.m_breakStatus = para.m_breakStatus.get()|MWAWParagraph::NoBreakWithNextBit;
1904
50.8k
  if (flags&0x40)
1905
199
    para.m_breakStatus = para.m_breakStatus.get()|MWAWParagraph::NoBreakBit;
1906
50.8k
  if (flags&0x2)
1907
148
    para.m_addPageBreak = true;
1908
50.8k
  if (flags&0x4)
1909
81
    f << "linebreakByWord,";
1910
1911
50.8k
  if (flags & 0x39) f << "#fl=" << std::hex << (flags&0x39) << std::dec << ",";
1912
1913
50.8k
  auto val = static_cast<int>(input->readLong(2));
1914
50.8k
  if (val) f << "#f0=" << val << ",";
1915
50.8k
  val = static_cast<int>(input->readULong(2));
1916
50.8k
  switch (val&3) {
1917
35.2k
  case 0:
1918
35.2k
    para.m_justify = MWAWParagraph::JustificationLeft;
1919
35.2k
    break;
1920
5.19k
  case 1:
1921
5.19k
    para.m_justify = MWAWParagraph::JustificationRight;
1922
5.19k
    break;
1923
5.32k
  case 2:
1924
5.32k
    para.m_justify = MWAWParagraph::JustificationCenter;
1925
5.32k
    break;
1926
5.05k
  case 3:
1927
5.05k
    para.m_justify = MWAWParagraph::JustificationFull;
1928
5.05k
    break;
1929
0
  default:
1930
0
    break;
1931
50.8k
  }
1932
50.8k
  if (val&0xFFFC) f << "#f1=" << val << ",";
1933
50.8k
  val = static_cast<int>(input->readLong(1));
1934
50.8k
  if (val) f << "#f2=" << val << ",";
1935
50.8k
  para.m_type = static_cast<int>(input->readLong(2));
1936
1937
50.8k
  float dim[3];
1938
152k
  for (auto &d : dim) d = float(input->readLong(4))/65536.0f;
1939
50.8k
  para.m_marginsUnit = librevenge::RVNG_POINT;
1940
50.8k
  para.m_margins[0]=double(dim[1]);
1941
50.8k
  para.m_margins[1]=double(dim[0]);
1942
50.8k
  para.m_margins[2]=double(dim[2]); // ie. distance to right border - ...
1943
1944
50.8k
  for (auto &spacing : para.m_spacings)
1945
152k
    spacing = double(input->readLong(4))/65536.0;
1946
50.8k
  int spacingsUnit[3]; // 1=mm, ..., 4=pt, b=line
1947
152k
  for (auto &s : spacingsUnit) s= static_cast<int>(input->readULong(1));
1948
50.8k
  if (spacingsUnit[0]==0xb)
1949
46.5k
    para.m_spacingsInterlineUnit = librevenge::RVNG_PERCENT;
1950
4.32k
  else
1951
4.32k
    para.m_spacingsInterlineUnit = librevenge::RVNG_POINT;
1952
152k
  for (int i = 1; i < 3; i++) // convert point|line -> inches
1953
101k
    para.m_spacings[i]= ((spacingsUnit[i]==0xb) ? 12.0 : 1.0)*(para.m_spacings[i].get())/72.0;
1954
1955
50.8k
  val = static_cast<int>(input->readLong(1));
1956
50.8k
  if (val) f << "#f3=" << val << ",";
1957
152k
  for (int i = 0;  i< 2; i++) { // one time f4=8000
1958
101k
    val = static_cast<int>(input->readULong(2));
1959
101k
    if (val) f << "#f" << i+4 << "=" << std::hex << val << std::dec << ",";
1960
101k
  }
1961
  // the borders
1962
50.8k
  char const *wh[5] = { "T", "L", "B", "R", "VSep" };
1963
50.8k
  MWAWBorder borders[5];
1964
254k
  for (auto &border : borders) border.m_width = double(input->readLong(4))/65536.;
1965
304k
  for (int d=0; d < 5; d++) {
1966
254k
    val = static_cast<int>(input->readULong(1));
1967
254k
    switch (val) {
1968
252k
    case 0: // normal
1969
252k
      break;
1970
450
    case 1:
1971
450
      borders[d].m_type = MWAWBorder::Double;
1972
450
      break;
1973
122
    case 2:
1974
122
      borders[d].m_type = MWAWBorder::Double;
1975
122
      f << "bord" << wh[d] << "[ext=2],";
1976
122
      break;
1977
211
    case 3:
1978
211
      borders[d].m_type = MWAWBorder::Double;
1979
211
      f << "bord" << wh[d] << "[int=2],";
1980
211
      break;
1981
562
    default:
1982
562
      f << "#bord" << wh[d] << "[style=" << val << "],";
1983
562
      break;
1984
254k
    }
1985
254k
  }
1986
50.8k
  int color[5], pattern[5];
1987
254k
  for (auto &c : color) c = static_cast<int>(input->readULong(1));
1988
254k
  for (auto &p : pattern) p= static_cast<int>(input->readULong(2));
1989
304k
  for (int d=0; d < 5; d++) {
1990
254k
    if (!color[d] && !pattern[d])
1991
2.64k
      continue;
1992
251k
    MWAWColor col;
1993
251k
    if (m_mainParser->getColor(color[d], pattern[d], col))
1994
248k
      borders[d].m_color = col;
1995
3.19k
    else
1996
3.19k
      f << "#bord" << wh[d] << "[col=" << color[d] << ",pat=" << pattern[d] << "],";
1997
251k
  }
1998
  // update the paragraph
1999
50.8k
  para.resizeBorders(6);
2000
50.8k
  libmwaw::Position const which[5] = {
2001
50.8k
    libmwaw::Top, libmwaw::Left, libmwaw::Bottom, libmwaw::Right,
2002
50.8k
    libmwaw::VMiddle
2003
50.8k
  };
2004
304k
  for (int d=0; d < 5; d++) {
2005
254k
    if (borders[d].m_width <= 0)
2006
252k
      continue;
2007
1.34k
    para.m_borders[which[d]]=borders[d];
2008
1.34k
  }
2009
50.8k
  val = static_cast<int>(input->readLong(1));
2010
50.8k
  if (val) f << "#f6=" << val << ",";
2011
50.8k
  double bMargins[5]= {0,0,0,0,0};
2012
304k
  for (int d = 0; d < 5; d++) {
2013
254k
    bMargins[d] =  double(input->readLong(4))/256./65536./72.;
2014
254k
    if (bMargins[d] > 0 || bMargins[d] < 0)
2015
9.84k
      f << "bordMarg" << wh[d] << "=" << bMargins[d] << ",";
2016
254k
  }
2017
50.8k
  auto nTabs = static_cast<int>(input->readULong(1));
2018
50.8k
  if (input->tell()+2+nTabs*12 > endPos) {
2019
111
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraph: can not read numbers of tab\n"));
2020
111
    input->seek(debPos, librevenge::RVNG_SEEK_SET);
2021
111
    return false;
2022
111
  }
2023
50.7k
  val = static_cast<int>(input->readULong(2));
2024
50.7k
  if (val) f << "#h3=" << val << ",";
2025
50.7k
  para.m_extra=f.str();
2026
50.7k
  f.str("");
2027
50.7k
  f << "Ruler:" << para;
2028
2029
50.7k
  asciiFile.addPos(debPos);
2030
50.7k
  asciiFile.addNote(f.str().c_str());
2031
106k
  for (int i = 0; i < nTabs; i++) {
2032
55.8k
    pos = input->tell();
2033
55.8k
    f.str("");
2034
55.8k
    f << "Ruler[Tabs-" << i << "]:";
2035
2036
55.8k
    MWAWTabStop tab;
2037
55.8k
    val = static_cast<int>(input->readULong(1));
2038
55.8k
    switch (val) {
2039
26.5k
    case 0:
2040
26.5k
      break;
2041
10.3k
    case 1:
2042
10.3k
      tab.m_alignment = MWAWTabStop::CENTER;
2043
10.3k
      break;
2044
3.59k
    case 2:
2045
3.59k
      tab.m_alignment = MWAWTabStop::RIGHT;
2046
3.59k
      break;
2047
10.6k
    case 3:
2048
10.6k
      tab.m_alignment = MWAWTabStop::DECIMAL;
2049
10.6k
      break;
2050
173
    case 4:
2051
173
      tab.m_alignment = MWAWTabStop::BAR;
2052
173
      break;
2053
4.52k
    default:
2054
4.52k
      f << "#type=" << val << ",";
2055
4.52k
      break;
2056
55.8k
    }
2057
55.8k
    val = static_cast<int>(input->readULong(1));
2058
55.8k
    if (val) f << "barType=" << val << ",";
2059
55.8k
    val = static_cast<int>(input->readULong(2));
2060
55.8k
    if (val) {
2061
15.5k
      int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(val));
2062
15.5k
      if (unicode==-1)
2063
4.29k
        tab.m_decimalCharacter = uint16_t(val);
2064
11.2k
      else
2065
11.2k
        tab.m_decimalCharacter = uint16_t(unicode);
2066
15.5k
    }
2067
55.8k
    val = static_cast<int>(input->readULong(2));
2068
55.8k
    if (val) {
2069
5.02k
      int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(val));
2070
5.02k
      if (unicode==-1)
2071
4.19k
        tab.m_leaderCharacter = uint16_t(val);
2072
835
      else
2073
835
        tab.m_leaderCharacter = uint16_t(unicode);
2074
5.02k
    }
2075
55.8k
    val = static_cast<int>(input->readULong(2)); // 0|73|74|a044|f170|f1e0|f590
2076
55.8k
    if (val) f << "f0=" << std::hex << val << std::dec << ",";
2077
2078
55.8k
    tab.m_position = double(input->readLong(4))/65536./72.;
2079
55.8k
    para.m_tabs->push_back(tab);
2080
55.8k
    f << tab;
2081
2082
55.8k
    asciiFile.addPos(pos);
2083
55.8k
    asciiFile.addNote(f.str().c_str());
2084
55.8k
    input->seek(pos+12, librevenge::RVNG_SEEK_SET);
2085
55.8k
  }
2086
50.7k
  if (input->tell()!=endPos) {
2087
50.7k
    asciiFile.addDelimiter(input->tell(),'|');
2088
50.7k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
2089
50.7k
  }
2090
50.7k
  return true;
2091
50.7k
}
2092
2093
bool HanMacWrdJText::readParagraphs(MWAWEntry const &entry)
2094
6.92k
{
2095
6.92k
  if (!entry.valid()) {
2096
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraphs: called without any entry\n"));
2097
0
    return false;
2098
0
  }
2099
6.92k
  if (entry.length() <= 8) {
2100
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraphs: the entry seems too short\n"));
2101
0
    return false;
2102
0
  }
2103
6.92k
  if (m_state->m_paragraphList.size()) {
2104
328
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraphs: oops the paragraph list is not empty\n"));
2105
328
    m_state->m_paragraphList.resize(0);
2106
328
  }
2107
2108
6.92k
  MWAWInputStreamPtr input = m_parserState->m_input;
2109
6.92k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
2110
6.92k
  libmwaw::DebugStream f;
2111
6.92k
  entry.setParsed(true);
2112
2113
6.92k
  long pos = entry.begin()+8; // skip header
2114
6.92k
  long endPos = entry.end();
2115
6.92k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2116
2117
  // first read the header
2118
6.92k
  f << entry.name() << "[header]:";
2119
6.92k
  HanMacWrdJZoneHeader mainHeader(false);
2120
6.92k
  if (!m_mainParser->readClassicHeader(mainHeader,endPos) || mainHeader.m_fieldSize!=12) {
2121
1.38k
    MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraphs: can not read the header\n"));
2122
1.38k
    f << "###sz=" << mainHeader.m_length;
2123
1.38k
    asciiFile.addPos(pos);
2124
1.38k
    asciiFile.addNote(f.str().c_str());
2125
1.38k
    return false;
2126
1.38k
  }
2127
5.54k
  long headerEnd=pos+4+mainHeader.m_length;
2128
5.54k
  f << mainHeader;
2129
2130
5.54k
  f << "unk=[";
2131
71.2k
  for (int i = 0; i < mainHeader.m_n; i++) {
2132
65.7k
    f << "[";
2133
65.7k
    long val = input->readLong(2); // always -2 ?
2134
65.7k
    if (val!=-2)
2135
745
      f << "unkn0=" << val << ",";
2136
65.7k
    val = long(input->readULong(2)); // 0|1|2|5
2137
65.7k
    if (val)
2138
11.0k
      f << "type=" << val << ",";
2139
65.7k
    val = long(input->readULong(4)); // a id
2140
65.7k
    if (val)
2141
65.5k
      f << "id1=" << std::hex << val << std::dec << ",";
2142
65.7k
    val = long(input->readULong(4));
2143
65.7k
    if (val)
2144
16.6k
      f << "id2=" << std::hex << val << std::dec << ",";
2145
65.7k
    f << "]";
2146
65.7k
  }
2147
5.54k
  f << "],";
2148
5.54k
  if (input->tell()!=headerEnd) {
2149
89
    asciiFile.addDelimiter(input->tell(),'|');
2150
89
    input->seek(headerEnd, librevenge::RVNG_SEEK_SET);
2151
89
  }
2152
5.54k
  asciiFile.addPos(pos);
2153
5.54k
  asciiFile.addNote(f.str().c_str());
2154
2155
55.7k
  for (int i = 0; i < mainHeader.m_n; i++) {
2156
52.9k
    pos = input->tell();
2157
52.9k
    HanMacWrdJTextInternal::Paragraph paragraph;
2158
52.9k
    if (!readParagraph(paragraph) || input->tell() > endPos) {
2159
2.81k
      MWAW_DEBUG_MSG(("HanMacWrdJText::readParagraphs: can not read paragraph %d\n", i));
2160
2.81k
      asciiFile.addPos(pos);
2161
2.81k
      asciiFile.addNote("Ruler###");
2162
2.81k
      return false;
2163
2.81k
    }
2164
50.1k
    m_state->m_paragraphList.push_back(paragraph);
2165
50.1k
  }
2166
2.73k
  asciiFile.addPos(endPos);
2167
2.73k
  asciiFile.addNote("_");
2168
2.73k
  return true;
2169
5.54k
}
2170
2171
////////////////////////////////////////////////////////////
2172
//     the sections/footnotes
2173
////////////////////////////////////////////////////////////
2174
bool HanMacWrdJText::readSections(MWAWEntry const &entry)
2175
2.35k
{
2176
2.35k
  if (!entry.valid()) {
2177
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: called without any entry\n"));
2178
0
    return false;
2179
0
  }
2180
2.35k
  if (entry.length() < 20) {
2181
31
    MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: the entry seems too short\n"));
2182
31
    return false;
2183
31
  }
2184
2.32k
  if (m_state->m_sectionList.size()) {
2185
6
    MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: the list of section is not empty\n"));
2186
6
    m_state->m_sectionList.resize(0);
2187
6
  }
2188
2.32k
  long pos = entry.begin()+8; // skip header
2189
2.32k
  long endPos = entry.end();
2190
2191
2.32k
  MWAWInputStreamPtr input = m_parserState->m_input;
2192
2.32k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
2193
2.32k
  libmwaw::DebugStream f;
2194
2.32k
  entry.setParsed(true);
2195
2.32k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2196
2.32k
  f << entry.name() << "[header]:";
2197
2.32k
  long val;
2198
6.97k
  for (int i = 0; i < 2; i++) { // fl0=0|0
2199
4.65k
    val = long(input->readULong(1));
2200
4.65k
    if (val) f << "fl" << i << "=" << std::hex << val << std::hex << ",";
2201
4.65k
  }
2202
9.30k
  for (int i = 0; i < 3; i++) { // f0=1, f1=N, f2=0
2203
6.97k
    val = input->readLong(2);
2204
6.97k
    if (val) f << "f" << i << "=" << val << ",";
2205
6.97k
  }
2206
2.32k
  asciiFile.addPos(pos);
2207
2.32k
  asciiFile.addNote(f.str().c_str());
2208
2209
2.32k
  auto dataSz = long(input->readULong(4));
2210
2.32k
  if (!dataSz) return true;
2211
2212
2.21k
  input->seek(-4, librevenge::RVNG_SEEK_CUR);
2213
2.21k
  pos = input->tell();
2214
2.21k
  f.str("");
2215
2.21k
  f << entry.name() << ":";
2216
2.21k
  HanMacWrdJZoneHeader header(false);
2217
2.21k
  if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=0x5c) {
2218
200
    MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: can not read second zone\n"));
2219
200
    f << "###" << header;
2220
200
    asciiFile.addPos(pos);
2221
200
    asciiFile.addNote(f.str().c_str());
2222
200
    return false;
2223
200
  }
2224
2.01k
  f << header;
2225
2.01k
  long zoneEnd=pos+4+header.m_length;
2226
2.01k
  asciiFile.addPos(pos);
2227
2.01k
  asciiFile.addNote(f.str().c_str());
2228
2229
6.02k
  for (int i = 0; i < header.m_n; i++) {
2230
4.01k
    pos = input->tell();
2231
4.01k
    f.str("");
2232
4.01k
    HanMacWrdJTextInternal::Section sec;
2233
4.01k
    sec.m_id= input->readLong(2);
2234
4.01k
    val = input->readLong(2); // almost alway=id, but not always
2235
4.01k
    if (val != sec.m_id)
2236
222
      f << "#id2=" << val << ",";
2237
4.01k
    val = input->readLong(2); // 0|1
2238
4.01k
    if (val) f << "f0=" << val << ",";
2239
4.01k
    val = long(input->readULong(2));
2240
4.01k
    auto numCol = int(val >> 12);
2241
4.01k
    if (numCol<=0 || numCol > 8) {
2242
130
      MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: can not determine the num of columns\n"));
2243
130
      f << "#numCols=" << numCol << ",";
2244
130
      numCol = 1;
2245
130
    }
2246
3.88k
    else
2247
3.88k
      sec.m_numCols=numCol;
2248
4.01k
    bool differentWidth=(val & 0xFFF) == 0;
2249
4.01k
    if (val & 0x7FF)
2250
79
      f << "#fl=" << std::hex << (val & 0xFFF) << ",";
2251
4.01k
    if (differentWidth) {
2252
375
      for (int j = 0; j < numCol; j++) {
2253
239
        sec.m_colWidth.push_back(double(input->readLong(4))/65536);
2254
239
        sec.m_colSep.push_back(double(input->readLong(4))/65536);
2255
239
      }
2256
136
    }
2257
3.87k
    else {
2258
3.87k
      sec.m_colWidth.push_back(double(input->readLong(4))/65536);
2259
3.87k
      sec.m_colSep.push_back(double(input->readLong(4))/65536);
2260
3.87k
    }
2261
4.01k
    sec.m_extra = f.str();
2262
4.01k
    m_state->m_sectionList.push_back(sec);
2263
2264
4.01k
    f.str("");
2265
4.01k
    f << entry.name() << "-" << i << ":" << sec;
2266
2267
4.01k
    asciiFile.addDelimiter(input->tell(), '|');
2268
4.01k
    asciiFile.addPos(pos);
2269
4.01k
    asciiFile.addNote(f.str().c_str());
2270
4.01k
    input->seek(pos+0x5c, librevenge::RVNG_SEEK_SET);
2271
4.01k
  }
2272
2.01k
  input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
2273
2274
2.01k
  pos = input->tell();
2275
2.01k
  if (pos!=endPos) {
2276
47
    MWAW_DEBUG_MSG(("HanMacWrdJText::readSections: find unexpected end data\n"));
2277
47
    f.str("");
2278
47
    f << entry.name() << "###:";
2279
47
    asciiFile.addPos(pos);
2280
47
    asciiFile.addNote(f.str().c_str());
2281
47
  }
2282
2.01k
  return true;
2283
2.21k
}
2284
2285
bool HanMacWrdJText::readFtnPos(MWAWEntry const &entry)
2286
2.19k
{
2287
2.19k
  if (!entry.valid()) {
2288
0
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFtnPos: called without any entry\n"));
2289
0
    return false;
2290
0
  }
2291
2.19k
  if (entry.length() < 16) {
2292
21
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFtnPos: the entry seems too short\n"));
2293
21
    return false;
2294
21
  }
2295
2.17k
  long pos = entry.begin()+8; // skip header
2296
2.17k
  long endPos = entry.end();
2297
2298
2.17k
  MWAWInputStreamPtr input = m_parserState->m_input;
2299
2.17k
  libmwaw::DebugFile &asciiFile = m_parserState->m_asciiFile;
2300
2.17k
  libmwaw::DebugStream f;
2301
2.17k
  entry.setParsed(true);
2302
2.17k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
2303
2.17k
  f << entry.name() << "[header]:";
2304
2.17k
  auto val = long(input->readULong(2)); // always 0x200
2305
2.17k
  if (val!=0x2000)
2306
106
    f << "f0=" << std::hex << val << std::dec << ",";
2307
2.17k
  val = input->readLong(2); // always 1 ?
2308
2.17k
  if (val != 1)
2309
83
    f << "f1=" << val << ",";
2310
2.17k
  asciiFile.addPos(pos);
2311
2.17k
  asciiFile.addNote(f.str().c_str());
2312
2313
2.17k
  auto dataSz = long(input->readULong(4));
2314
2.17k
  if (!dataSz) return true;
2315
2316
2.11k
  input->seek(-4, librevenge::RVNG_SEEK_CUR);
2317
2.11k
  pos = input->tell();
2318
2.11k
  f.str("");
2319
2.11k
  f << entry.name() << ":";
2320
2.11k
  HanMacWrdJZoneHeader header(false);
2321
2.11k
  if (!m_mainParser->readClassicHeader(header,endPos) || header.m_fieldSize!=20||
2322
1.96k
      16+20*header.m_n+28 > header.m_length) {
2323
162
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFtnPos: can not read second zone\n"));
2324
162
    f << "###" << header;
2325
162
    asciiFile.addPos(pos);
2326
162
    asciiFile.addNote(f.str().c_str());
2327
162
    return false;
2328
162
  }
2329
1.95k
  f << header;
2330
1.95k
  long zoneEnd=pos+4+header.m_length;
2331
1.95k
  asciiFile.addDelimiter(input->tell(),'|');
2332
1.95k
  asciiFile.addPos(pos);
2333
1.95k
  asciiFile.addNote(f.str().c_str());
2334
2335
1.95k
  input->seek(28, librevenge::RVNG_SEEK_CUR);
2336
3.69k
  for (int i = 0; i < header.m_n; i++) {
2337
1.74k
    pos = input->tell();
2338
1.74k
    f.str("");
2339
1.74k
    f << entry.name() << "-" << i << ":";
2340
1.74k
    val = long(input->readULong(1));
2341
1.74k
    if (val!=0x11) {
2342
1
      MWAW_DEBUG_MSG(("HanMacWrdJText::readFtnPos: find unexpected type\n"));
2343
1
      f << "#type=" << std::hex << val << std::dec << ",";
2344
1
    }
2345
1.74k
    f << "id=" << input->readLong(1) << ",";
2346
10.4k
    for (int j = 0; j < 5; j++) { // always 0?
2347
8.70k
      val = input->readLong(2);
2348
8.70k
      if (val) f << "f" << j << "=" << val << ",";
2349
8.70k
    }
2350
    // the text id
2351
1.74k
    f << "zId[text]=" << std::hex << input->readULong(4) << std::dec << ",";
2352
    // the footnote id
2353
1.74k
    f << "zId[footnote]=" << std::hex << input->readULong(4) << std::dec << ",";
2354
1.74k
    asciiFile.addPos(pos);
2355
1.74k
    asciiFile.addNote(f.str().c_str());
2356
1.74k
    input->seek(pos+20, librevenge::RVNG_SEEK_SET);
2357
1.74k
  }
2358
1.95k
  input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
2359
2360
1.95k
  pos = input->tell();
2361
1.95k
  if (pos!=endPos) {
2362
30
    MWAW_DEBUG_MSG(("HanMacWrdJText::readFtnPos: find unexpected end data\n"));
2363
30
    f.str("");
2364
30
    f << entry.name() << "###:";
2365
30
    asciiFile.addPos(pos);
2366
30
    asciiFile.addNote(f.str().c_str());
2367
30
  }
2368
1.95k
  return true;
2369
2.11k
}
2370
////////////////////////////////////////////////////////////
2371
//
2372
// Low level
2373
//
2374
////////////////////////////////////////////////////////////
2375
2376
//! send data to the listener
2377
2378
void HanMacWrdJText::flushExtra()
2379
0
{
2380
0
  if (!m_parserState->m_textListener) return;
2381
2382
#ifdef DEBUG
2383
  for (auto &zone : m_state->m_textZoneList) {
2384
    if (zone.m_parsed)
2385
      continue;
2386
2387
    static bool first = true;
2388
    if (first) {
2389
      MWAW_DEBUG_MSG(("HanMacWrdJText::flushExtra: find some unsent zone\n"));
2390
      first = false;
2391
    }
2392
    sendText(zone,0);
2393
    m_parserState->m_textListener->insertEOL();
2394
  }
2395
#endif
2396
0
}
2397
2398
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: