Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MsWrdParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cstring>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <map>
39
#include <set>
40
#include <sstream>
41
42
#include <librevenge/librevenge.h>
43
44
#include "MWAWTextListener.hxx"
45
#include "MWAWFont.hxx"
46
#include "MWAWFontConverter.hxx"
47
#include "MWAWHeader.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWPictMac.hxx"
50
#include "MWAWPrinter.hxx"
51
#include "MWAWSubDocument.hxx"
52
53
#include "MsWrdParser.hxx"
54
55
#include "MsWrdText.hxx"
56
57
/** Internal: the structures of a MsWrdParser */
58
namespace MsWrdParserInternal
59
{
60
////////////////////////////////////////
61
//! Internal: the object of MsWrdParser
62
struct Object {
63
  Object()
64
1.98M
    : m_textPos(-1)
65
1.98M
    , m_pos()
66
1.98M
    , m_name("")
67
1.98M
    , m_id(-1)
68
1.98M
    , m_annotation()
69
1.98M
    , m_extra("")
70
1.98M
  {
71
3.97M
    for (auto &id : m_ids) id=-1;
72
3.97M
    for (auto &idFlag : m_idsFlag) idFlag=0;
73
3.97M
    for (auto &flag : m_flags) flag=0;
74
1.98M
  }
75
76
  MsWrdEntry getEntry() const
77
93.1k
  {
78
93.1k
    MsWrdEntry res;
79
93.1k
    res.setBegin(m_pos.begin());
80
93.1k
    res.setEnd(m_pos.end());
81
93.1k
    res.setType("ObjectData");
82
93.1k
    res.setId(m_id);
83
93.1k
    return res;
84
93.1k
  }
85
86
  //! operator<<
87
  friend std::ostream &operator<<(std::ostream &o, Object const &obj)
88
0
  {
89
0
    if (obj.m_textPos >= 0)
90
0
      o << std::hex << "textPos?=" << obj.m_textPos << std::dec << ",";
91
0
    if (obj.m_id >= 0) o << "Obj" << obj.m_id << ",";
92
0
    if (obj.m_name.length()) o << obj.m_name << ",";
93
0
    for (int st = 0; st < 2; st++) {
94
0
      if (obj.m_ids[st] == -1 && obj.m_idsFlag[st] == 0) continue;
95
0
      o << "id" << st << "=" << obj.m_ids[st];
96
0
      if (obj.m_idsFlag[st]) o << ":" << std::hex << obj.m_idsFlag[st] << std::dec << ",";
97
0
    }
98
0
    for (int st = 0; st < 2; st++) {
99
0
      if (obj.m_flags[st])
100
0
        o << "fl" << st << "=" << std::hex << obj.m_flags[st] << std::dec << ",";
101
0
    }
102
0
103
0
    if (obj.m_extra.length()) o << "extras=[" << obj.m_extra << "],";
104
0
    return o;
105
0
  }
106
  //! the text position
107
  long m_textPos;
108
109
  //! the object entry
110
  MWAWEntry m_pos;
111
112
  //! the object name
113
  std::string m_name;
114
115
  //! the id
116
  int m_id;
117
118
  //! some others id?
119
  int m_ids[2];
120
121
  //! some flags link to m_ids
122
  int m_idsFlag[2];
123
124
  //! some flags
125
  int m_flags[2];
126
127
  //! the annotation entry
128
  MWAWEntry m_annotation;
129
130
  //! some extra data
131
  std::string m_extra;
132
};
133
134
////////////////////////////////////////
135
//! Internal: the picture of a MsWrdParser
136
struct Picture {
137
  struct Zone;
138
  Picture()
139
73.2k
    : m_dim()
140
73.2k
    , m_picturesList()
141
73.2k
    , m_flag(0)
142
73.2k
  {
143
73.2k
  }
144
  //! operator<<
145
  friend std::ostream &operator<<(std::ostream &o, Picture const &pict)
146
0
  {
147
0
    o << "dim=" << pict.m_dim << ",";
148
0
    if (pict.m_flag) o << "f0=" << std::hex << pict.m_flag << std::dec << ",";
149
0
    return o;
150
0
  }
151
152
  //! the dimension
153
  MWAWBox2i m_dim;
154
  //! the list of picture
155
  std::vector<Zone> m_picturesList;
156
  //! an unknown flag
157
  int m_flag;
158
159
  // ! a small zone
160
  struct Zone {
161
    Zone()
162
37.4k
      : m_pos()
163
37.4k
      , m_dim()
164
37.4k
    {
165
112k
      for (auto &fl : m_flags) fl=0;
166
37.4k
    }
167
    //! operator<<
168
    friend std::ostream &operator<<(std::ostream &o, Zone const &pict)
169
0
    {
170
0
      o << "dim=" << pict.m_dim << ",";
171
0
      if (pict.m_flags[0] != 8) o << "f0=" << pict.m_flags[0] << ",";
172
0
      if (pict.m_flags[1]) o << "f1=" << pict.m_flags[1] << ",";
173
0
      if (pict.m_flags[2] != 1) o << "f2=" << pict.m_flags[2] << ","; // or 0
174
0
      return o;
175
0
    }
176
    //! the position in file
177
    MWAWEntry m_pos;
178
    //! the dimension
179
    MWAWBox2i m_dim;
180
    //! three unknown flags
181
    int m_flags[3];
182
  };
183
184
};
185
186
////////////////////////////////////////
187
//! Internal: the state of a MsWrdParser
188
struct State {
189
  //! constructor
190
  State()
191
374k
    : m_bot(-1)
192
374k
    , m_eot(-1)
193
374k
    , m_endNote(false)
194
374k
    , m_picturesMap()
195
374k
    , m_posToCommentMap()
196
374k
    , m_actPage(0)
197
374k
    , m_numPages(0)
198
374k
    , m_headersId()
199
374k
    , m_footersId()
200
374k
    , m_metaData()
201
374k
  {
202
374k
  }
203
204
  //! the begin of the text
205
  long m_bot;
206
  //! end of the text
207
  long m_eot;
208
  //! a flag to know if we must place the note at the end or in the foot part
209
  bool m_endNote;
210
  //! the map filePos -> Picture
211
  std::map<long, Picture> m_picturesMap;
212
  //! the map textPos -> comment entry
213
  std::map<long, MWAWEntry> m_posToCommentMap;
214
215
  //! the list of object ( mainZone, other zone)
216
  std::vector<Object> m_objectList[2];
217
218
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
219
220
  /** the list of header id which corresponds to each page */
221
  std::vector<int> m_headersId;
222
  /** the list of footer id which corresponds to each page */
223
  std::vector<int> m_footersId;
224
  /** the meta data */
225
  librevenge::RVNGPropertyList m_metaData;
226
};
227
228
////////////////////////////////////////
229
//! Internal: the subdocument of a MsWrdParser
230
class SubDocument final : public MWAWSubDocument
231
{
232
public:
233
  //! constructor for footnote, comment
234
  SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, int id, libmwaw::SubDocumentType type)
235
15.2k
    : MWAWSubDocument(&pars, input, MWAWEntry())
236
15.2k
    , m_id(id)
237
15.2k
    , m_type(type)
238
15.2k
    , m_pictFPos(-1)
239
15.2k
    , m_pictCPos(-1)
240
15.2k
  {
241
15.2k
  }
242
  //! constructor for header/footer
243
  SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry, libmwaw::SubDocumentType type)
244
7.57k
    : MWAWSubDocument(&pars, input, entry)
245
7.57k
    , m_id(-1)
246
7.57k
    , m_type(type)
247
7.57k
    , m_pictFPos(-1)
248
7.57k
    , m_pictCPos(-1)
249
7.57k
  {
250
7.57k
  }
251
  //! constructor for picture
252
  SubDocument(MsWrdParser &pars, MWAWInputStreamPtr const &input, long fPos, int cPos)
253
12.3k
    : MWAWSubDocument(&pars, input, MWAWEntry())
254
12.3k
    , m_id(-1)
255
12.3k
    , m_type(libmwaw::DOC_NONE)
256
12.3k
    , m_pictFPos(fPos)
257
12.3k
    , m_pictCPos(cPos)
258
12.3k
  {
259
12.3k
  }
260
261
  //! destructor
262
0
  ~SubDocument() final {}
263
264
  //! operator!=
265
  bool operator!=(MWAWSubDocument const &doc) const final;
266
267
  //! the parser function
268
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
269
270
protected:
271
  //! the subdocument id
272
  int m_id;
273
  //! the subdocument type
274
  libmwaw::SubDocumentType m_type;
275
  //! the picture file position
276
  long m_pictFPos;
277
  //! the picture char position
278
  int m_pictCPos;
279
};
280
281
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type)
282
28.2k
{
283
28.2k
  if (!listener.get()) {
284
0
    MWAW_DEBUG_MSG(("MsWrdParserInternal::SubDocument::parse: no listener\n"));
285
0
    return;
286
0
  }
287
28.2k
  auto *parser=dynamic_cast<MsWrdParser *>(m_parser);
288
28.2k
  if (!parser) {
289
0
    MWAW_DEBUG_MSG(("MsWrdParserInternal::SubDocument::parse: no parser\n"));
290
0
    return;
291
0
  }
292
293
28.2k
  long pos = m_input->tell();
294
28.2k
  if (m_type == libmwaw::DOC_NONE && m_pictCPos >= 0 && m_pictFPos > 0)
295
12.3k
    parser->sendPicture(m_pictFPos, m_pictCPos, MWAWPosition::Frame);
296
15.8k
  else if (m_type == libmwaw::DOC_HEADER_FOOTER)
297
7.57k
    parser->send(m_zone);
298
8.28k
  else if (m_type == libmwaw::DOC_COMMENT_ANNOTATION)
299
0
    parser->sendSimpleTextZone(listener, m_zone);
300
8.28k
  else
301
8.28k
    parser->send(m_id, type);
302
28.2k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
303
28.2k
}
304
305
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
306
3.43k
{
307
3.43k
  if (MWAWSubDocument::operator!=(doc)) return true;
308
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
309
0
  if (!sDoc) return true;
310
0
  if (m_id != sDoc->m_id) return true;
311
0
  if (m_type != sDoc->m_type) return true;
312
0
  if (m_pictFPos != sDoc->m_pictFPos) return true;
313
0
  if (m_pictCPos != sDoc->m_pictCPos) return true;
314
0
  return false;
315
0
}
316
}
317
318
////////////////////////////////////////////////////////////
319
// MsWrdEntry
320
////////////////////////////////////////////////////////////
321
MsWrdEntry::~MsWrdEntry()
322
13.3M
{
323
13.3M
}
324
325
std::ostream &operator<<(std::ostream &o, MsWrdEntry const &entry)
326
0
{
327
0
  if (entry.type().length()) {
328
0
    o << entry.type();
329
0
    if (entry.m_id >= 0) o << "[" << entry.m_id << "]";
330
0
    o << "=";
331
0
  }
332
0
  return o;
333
0
}
334
335
////////////////////////////////////////////////////////////
336
// constructor/destructor, ...
337
////////////////////////////////////////////////////////////
338
MsWrdParser::MsWrdParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
339
155k
  : MWAWTextParser(input, rsrcParser, header)
340
155k
  , m_state()
341
155k
  , m_entryMap()
342
155k
  , m_textParser()
343
155k
{
344
155k
  init();
345
155k
}
346
347
MsWrdParser::~MsWrdParser()
348
155k
{
349
155k
}
350
351
void MsWrdParser::init()
352
155k
{
353
155k
  resetTextListener();
354
155k
  setAsciiName("main-1");
355
356
155k
  m_state.reset(new MsWrdParserInternal::State);
357
358
  // reduce the margin (in case, the page is not defined)
359
155k
  getPageSpan().setMargins(0.1);
360
361
155k
  m_textParser.reset(new MsWrdText(*this));
362
155k
}
363
364
////////////////////////////////////////////////////////////
365
// new page and color
366
////////////////////////////////////////////////////////////
367
void MsWrdParser::newPage(int number)
368
68.2k
{
369
68.2k
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
370
0
    return;
371
372
136k
  while (m_state->m_actPage < number) {
373
68.2k
    m_state->m_actPage++;
374
68.2k
    if (!getTextListener() || m_state->m_actPage == 1)
375
4.15k
      continue;
376
64.1k
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
377
64.1k
  }
378
68.2k
}
379
380
bool MsWrdParser::getColor(int id, MWAWColor &col) const
381
38.6k
{
382
38.6k
  switch (id) {
383
0
  case 0:
384
0
    col=MWAWColor(0,0,0);
385
0
    break; // black
386
2.88k
  case 1:
387
2.88k
    col=MWAWColor(0,0,255);
388
2.88k
    break; // blue
389
3.45k
  case 2:
390
3.45k
    col=MWAWColor(0, 255,255);
391
3.45k
    break; // cyan
392
2.08k
  case 3:
393
2.08k
    col=MWAWColor(0,255,0);
394
2.08k
    break; // green
395
13.3k
  case 4:
396
13.3k
    col=MWAWColor(255,0,255);
397
13.3k
    break; // magenta
398
457
  case 5:
399
457
    col=MWAWColor(255,0,0);
400
457
    break; // red
401
3.39k
  case 6:
402
3.39k
    col=MWAWColor(255,255,0);
403
3.39k
    break; // yellow
404
909
  case 7:
405
909
    col=MWAWColor(255,255,255);
406
909
    break; // white
407
12.1k
  default:
408
12.1k
    MWAW_DEBUG_MSG(("MsWrdParser::getColor: unknown color=%d\n", id));
409
12.1k
    return false;
410
38.6k
  }
411
26.4k
  return true;
412
38.6k
}
413
414
void MsWrdParser::sendSimpleTextZone(MWAWListenerPtr &listener, MWAWEntry const &entry)
415
0
{
416
0
  if (!listener || !entry.valid()) return;
417
0
  auto input=getInput();
418
0
  if (input->size()<entry.end()) {
419
0
    MWAW_DEBUG_MSG(("MsWrdParser::sendSimpleTextZone: entry seems bad\n"));
420
0
    return;
421
0
  }
422
0
  long pos=input->tell();
423
424
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
425
0
  for (long i=0; i<entry.length(); ++i) {
426
0
    char c=char(input->readULong(1));
427
0
    switch (c) {
428
0
    case 0x9:
429
0
      listener->insertTab();
430
0
      break;
431
0
    case 0xd: // line break hard
432
0
      if (i+1!=entry.length())
433
0
        listener->insertEOL();
434
0
      break;
435
0
    default: // asume basic caracter, ie. will not works if Chinese, ...
436
0
      listener->insertCharacter(static_cast<unsigned char>(c));
437
0
      break;
438
0
    }
439
0
  }
440
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
441
0
}
442
443
void MsWrdParser::sendFootnote(int id)
444
15.2k
{
445
15.2k
  if (!getTextListener()) return;
446
447
15.2k
  MWAWSubDocumentPtr subdoc(new MsWrdParserInternal::SubDocument(*this, getInput(), id, libmwaw::DOC_NOTE));
448
15.2k
  getTextListener()->insertNote
449
15.2k
  (MWAWNote(m_state->m_endNote ? MWAWNote::EndNote : MWAWNote::FootNote), subdoc);
450
15.2k
}
451
452
void MsWrdParser::sendFieldComment(int id)
453
0
{
454
0
  if (!getTextListener()) return;
455
456
0
  MWAWSubDocumentPtr subdoc(new MsWrdParserInternal::SubDocument(*this, getInput(), id, libmwaw::DOC_COMMENT_ANNOTATION));
457
0
  getTextListener()->insertComment(subdoc);
458
0
}
459
460
void MsWrdParser::send(MWAWEntry const &entry)
461
7.57k
{
462
7.57k
  m_textParser->sendText(entry, false);
463
7.57k
}
464
465
void MsWrdParser::send(int id, libmwaw::SubDocumentType type)
466
8.28k
{
467
8.28k
  if (type==libmwaw::DOC_COMMENT_ANNOTATION)
468
0
    m_textParser->sendFieldComment(id);
469
8.28k
  else if (type==libmwaw::DOC_NOTE)
470
8.28k
    m_textParser->sendFootnote(id);
471
0
  else {
472
0
    MWAW_DEBUG_MSG(("MsWrdParser::send: find unexpected type\n"));
473
0
  }
474
8.28k
}
475
476
////////////////////////////////////////////////////////////
477
// the parser
478
////////////////////////////////////////////////////////////
479
void MsWrdParser::parse(librevenge::RVNGTextInterface *docInterface)
480
63.9k
{
481
63.9k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
482
63.9k
  bool ok = true;
483
63.9k
  try {
484
    // create the asciiFile
485
63.9k
    ascii().setStream(getInput());
486
63.9k
    ascii().open(asciiName());
487
488
63.9k
    checkHeader(nullptr);
489
63.9k
    ascii().addPos(getInput()->tell());
490
63.9k
    ascii().addNote("_");
491
492
63.9k
    ok = createZones();
493
63.9k
    if (ok) {
494
63.6k
      createDocument(docInterface);
495
63.6k
      m_textParser->sendMainText();
496
497
63.6k
      m_textParser->flushExtra();
498
63.6k
    }
499
500
63.9k
    ascii().reset();
501
63.9k
  }
502
63.9k
  catch (...) {
503
0
    MWAW_DEBUG_MSG(("MsWrdParser::parse: exception catched when parsing\n"));
504
0
    ok = false;
505
0
  }
506
507
63.9k
  resetTextListener();
508
63.9k
  if (!ok) throw(libmwaw::ParseException());
509
63.9k
}
510
511
////////////////////////////////////////////////////////////
512
// create the document
513
////////////////////////////////////////////////////////////
514
void MsWrdParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
515
63.6k
{
516
63.6k
  if (!documentInterface) return;
517
63.6k
  if (getTextListener()) {
518
0
    MWAW_DEBUG_MSG(("MsWrdParser::createDocument: listener already exist\n"));
519
0
    return;
520
0
  }
521
522
  // update the page
523
63.6k
  m_state->m_actPage = 0;
524
525
  // create the page list
526
63.6k
  MWAWPageSpan ps(getPageSpan());
527
63.6k
  MWAWEntry entry = m_textParser->getHeader();
528
63.6k
  if (entry.valid()) {
529
4.41k
    MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
530
4.41k
    header.m_subDocument.reset
531
4.41k
    (new MsWrdParserInternal::SubDocument(*this, getInput(), entry, libmwaw::DOC_HEADER_FOOTER));
532
4.41k
    ps.setHeaderFooter(header);
533
4.41k
  }
534
63.6k
  entry = m_textParser->getFooter();
535
63.6k
  if (entry.valid()) {
536
3.15k
    MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
537
3.15k
    footer.m_subDocument.reset
538
3.15k
    (new MsWrdParserInternal::SubDocument(*this, getInput(), entry, libmwaw::DOC_HEADER_FOOTER));
539
3.15k
    ps.setHeaderFooter(footer);
540
3.15k
  }
541
63.6k
  int numPage = 1;
542
63.6k
  if (m_textParser->numPages() > numPage)
543
6.03k
    numPage = m_textParser->numPages();
544
63.6k
  m_state->m_numPages = numPage;
545
546
63.6k
  ps.setPageSpan(m_state->m_numPages+1);
547
63.6k
  std::vector<MWAWPageSpan> pageList(1,ps);
548
  //
549
63.6k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
550
63.6k
  setTextListener(listen);
551
63.6k
  if (!m_state->m_metaData.empty())
552
2.43k
    listen->setDocumentMetaData(m_state->m_metaData);
553
63.6k
  listen->startDocument();
554
63.6k
}
555
556
557
////////////////////////////////////////////////////////////
558
//
559
// Intermediate level
560
//
561
////////////////////////////////////////////////////////////
562
563
////////////////////////////////////////////////////////////
564
// try to find the different zone
565
////////////////////////////////////////////////////////////
566
bool MsWrdParser::createZones()
567
63.9k
{
568
63.9k
  if (!readZoneList()) return false;
569
63.6k
  MWAWInputStreamPtr input = getInput();
570
63.6k
  long pos = input->tell();
571
63.6k
  if (pos != m_state->m_bot) {
572
50.2k
    ascii().addPos(pos);
573
50.2k
    ascii().addNote("_");
574
50.2k
  }
575
63.6k
  libmwaw::DebugStream f;
576
63.6k
  ascii().addPos(m_state->m_eot);
577
63.6k
  ascii().addNote("_");
578
579
63.6k
  auto it = m_entryMap.find("PrintInfo");
580
63.6k
  if (it != m_entryMap.end())
581
6.91k
    readPrintInfo(it->second);
582
583
63.6k
  it = m_entryMap.find("DocSum");
584
63.6k
  if (it != m_entryMap.end())
585
5.35k
    readDocSum(it->second);
586
587
63.6k
  it = m_entryMap.find("Printer");
588
63.6k
  if (it != m_entryMap.end())
589
4.63k
    readPrinter(it->second);
590
591
63.6k
  readObjects();
592
593
63.6k
  bool ok = m_textParser->createZones(m_state->m_bot);
594
595
63.6k
  it = m_entryMap.find("DocumentInfo");
596
63.6k
  if (it != m_entryMap.end())
597
4.27k
    readDocumentInfo(it->second);
598
599
63.6k
  it = m_entryMap.find("Zone17");
600
63.6k
  if (it != m_entryMap.end())
601
2.86k
    readZone17(it->second);
602
603
63.6k
  it = m_entryMap.find("Picture");
604
106k
  while (it != m_entryMap.end()) {
605
44.6k
    if (!it->second.hasType("Picture")) break;
606
42.9k
    MsWrdEntry &entry=it++->second;
607
42.9k
    readPicture(entry);
608
42.9k
  }
609
610
365k
  for (auto const &fIt : m_entryMap) {
611
365k
    MsWrdEntry const &entry = fIt.second;
612
365k
    if (entry.isParsed()) continue;
613
88.2k
    ascii().addPos(entry.begin());
614
88.2k
    f.str("");
615
88.2k
    f << entry;
616
88.2k
    ascii().addNote(f.str().c_str());
617
88.2k
    ascii().addPos(entry.end());
618
88.2k
    ascii().addNote("_");
619
620
88.2k
  }
621
63.6k
  return ok;
622
63.9k
}
623
624
////////////////////////////////////////////////////////////
625
// read the zone list ( FIB )
626
////////////////////////////////////////////////////////////
627
bool MsWrdParser::readZoneList()
628
63.9k
{
629
63.9k
  MWAWInputStreamPtr input = getInput();
630
63.9k
  int const vers = version();
631
63.9k
  getInput()->seek(vers <= 3 ? 30 : 64, librevenge::RVNG_SEEK_SET);
632
63.9k
  int numData = vers <= 3 ? 15: 20;
633
63.9k
  std::stringstream s;
634
1.17M
  for (int i = 0; i < numData; i++) {
635
1.11M
    switch (i) {
636
    // the first two zone are often simillar : even/odd header/footer ?
637
63.9k
    case 0: // original styles zone, often invalid
638
63.9k
      readEntry("Styles", 0);
639
63.9k
      break;
640
63.9k
    case 1: // STSH
641
63.9k
      readEntry("Styles", 1);
642
63.9k
      break;
643
63.9k
    case 2: // FFNDRef
644
63.9k
      readEntry("FootnotePos");
645
63.9k
      break;
646
63.9k
    case 3: // FFNDText
647
63.9k
      readEntry("FootnoteDef");
648
63.9k
      break;
649
63.9k
    case 4: // SED
650
63.9k
      readEntry("Section");
651
63.9k
      break;
652
63.9k
    case 5: //
653
63.9k
      readEntry("PageBreak");
654
63.9k
      break;
655
63.9k
    case 6: // fandRef
656
63.9k
      readEntry("FieldName");
657
63.9k
      break;
658
63.9k
    case 7: // fandText
659
63.9k
      readEntry("FieldPos");
660
63.9k
      break;
661
63.9k
    case 8: // Hdd
662
63.9k
      readEntry("HeaderFooter");
663
63.9k
      break;
664
63.9k
    case 9: // BteChpx
665
63.9k
      readEntry("CharList", 0);
666
63.9k
      break;
667
63.9k
    case 10: // BtePapx
668
63.9k
      readEntry("ParagList", 1);
669
63.9k
      break;
670
63.9k
    case 12: // SttbfFfn
671
63.9k
      readEntry("FontIds");
672
63.9k
      break;
673
63.9k
    case 13: // PrDrvr: checkme: is it ok also for v3 file ?
674
63.9k
      readEntry("PrintInfo");
675
63.9k
      break;
676
63.9k
    case 14: // Clx/Phe
677
63.9k
      readEntry(vers <= 3 ? "TextStruct" : "ParaInfo");
678
63.9k
      break;
679
31.0k
    case 15: // Dop?
680
31.0k
      readEntry("DocumentInfo");
681
31.0k
      break;
682
31.0k
    case 16:
683
31.0k
      readEntry("Printer");
684
31.0k
      break;
685
31.0k
    case 18: // Clx (ie. a list of Pcd )
686
31.0k
      readEntry("TextStruct");
687
31.0k
      break;
688
31.0k
    case 19:
689
31.0k
      readEntry("FootnoteData");
690
31.0k
      break;
691
95.0k
    default:
692
95.0k
      s.str("");
693
95.0k
      s << "Zone" << i;
694
95.0k
      if (i < 4) s << "_";
695
95.0k
      readEntry(s.str());
696
95.0k
      break;
697
1.11M
    }
698
1.11M
  }
699
700
63.9k
  if (vers <= 3) return true;
701
31.0k
  long pos = input->tell();
702
31.0k
  libmwaw::DebugStream f;
703
31.0k
  f << "Entries(ListZoneData)[0]:";
704
93.1k
  for (int i = 0; i < 2; i++) // two small int
705
62.0k
    f << "f" << i << "=" << input->readLong(2) << ",";
706
707
31.0k
  ascii().addPos(pos);
708
31.0k
  ascii().addNote(f.str().c_str());
709
31.0k
  if (vers <= 4) return true;
710
711
  // main
712
25.1k
  readEntry("ObjectName",0);
713
25.1k
  readEntry("FontNames");
714
25.1k
  readEntry("ObjectList",0);
715
25.1k
  readEntry("ObjectFlags",0);
716
25.1k
  readEntry("DocSum",0);
717
175k
  for (int i = 25; i < 31; i++) {
718
    /* check me: Zone25, Zone26, Zone27: also some object name, list, flags ? */
719
    // header/footer
720
150k
    if (i==28) readEntry("ObjectName",1);
721
125k
    else if (i==29) readEntry("ObjectList",1);
722
100k
    else if (i==30) readEntry("ObjectFlags",1);
723
75.3k
    else {
724
75.3k
      s.str("");
725
75.3k
      s << "Zone" << i;
726
75.3k
      readEntry(s.str());
727
75.3k
    }
728
150k
  }
729
730
25.1k
  pos = input->tell();
731
25.1k
  f.str("");
732
25.1k
  f << "ListZoneData[1]:";
733
734
25.1k
  long val = input->readLong(2);
735
25.1k
  if (val) f << "unkn=" << val << ",";
736
25.1k
  ascii().addPos(pos);
737
25.1k
  ascii().addNote(f.str().c_str());
738
739
25.1k
  if (input->isEnd()) {
740
374
    MWAW_DEBUG_MSG(("MsWrdParser::readZoneList: can not read list zone\n"));
741
374
    return false;
742
374
  }
743
24.7k
  return true;
744
25.1k
}
745
746
////////////////////////////////////////////////////////////
747
//
748
// Low level
749
//
750
////////////////////////////////////////////////////////////
751
752
753
754
////////////////////////////////////////////////////////////
755
// read the header
756
////////////////////////////////////////////////////////////
757
bool MsWrdParser::checkHeader(MWAWHeader *header, bool strict)
758
219k
{
759
219k
  *m_state = MsWrdParserInternal::State();
760
761
219k
  MWAWInputStreamPtr input = getInput();
762
219k
  if (!input || !input->hasDataFork())
763
0
    return false;
764
765
219k
  libmwaw::DebugStream f;
766
219k
  int headerSize=64;
767
219k
  if (!input->checkPosition(0x88)) {
768
587
    MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: file is too short\n"));
769
587
    return false;
770
587
  }
771
218k
  long pos = 0;
772
218k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
773
218k
  auto val = static_cast<int>(input->readULong(2));
774
218k
  switch (val) {
775
104k
  case 0xfe34:
776
104k
    switch (input->readULong(2)) {
777
104k
    case 0x0:
778
104k
      headerSize = 30;
779
104k
      setVersion(3);
780
104k
      break;
781
0
    default:
782
0
      return false;
783
104k
    }
784
104k
    break;
785
113k
  case 0xfe37:
786
113k
    switch (input->readULong(2)) {
787
24.1k
    case 0x1c:
788
24.1k
      setVersion(4);
789
24.1k
      break;
790
89.6k
    case 0x23:
791
89.6k
      setVersion(5);
792
89.6k
      break;
793
0
    default:
794
0
      return false;
795
113k
    }
796
113k
    break;
797
113k
  default:
798
7
    return false;
799
218k
  }
800
801
218k
  int const vers = version();
802
218k
  f << "FileHeader:";
803
218k
  val = static_cast<int>(input->readULong(1)); // v1: ab other 0 ?
804
218k
  if (val) f << "f0=" << val << ",";
805
655k
  for (int i = 1; i < 3; i++) { // always 0
806
437k
    val = static_cast<int>(input->readLong(2));
807
437k
    if (val) f << "f" << i << "=" << val << ",";
808
437k
  }
809
218k
  if (vers > 3) {
810
    // find 4, 8, c, 24, 2c
811
113k
    val = static_cast<int>(input->readLong(2));
812
113k
    if (val)
813
96.7k
      f << "unkn=" << std::hex << val << std::dec << ",";
814
    // 0,0,0x19,0
815
569k
    for (int i = 4; i < 8; i++) {
816
455k
      val = static_cast<int>(input->readLong(1));
817
455k
      if (val) f << "f" << i << "=" << val << ",";
818
455k
    }
819
113k
  }
820
821
1.31M
  for (int i = 0; i < 5; i++) { // always 0 ?
822
1.09M
    val = static_cast<int>(input->readLong(1));
823
1.09M
    if (val) f << "g" << i << "=" << val << ",";
824
1.09M
  }
825
826
218k
  m_state->m_bot = vers <= 3 ? 0x100 : long(input->readULong(4));
827
218k
  m_state->m_eot = long(input->readULong(4));
828
218k
  f << "text=" << std::hex << m_state->m_bot << "<->" << m_state->m_eot << ",";
829
218k
  if (m_state->m_bot > m_state->m_eot) {
830
69.1k
    f << "#text,";
831
69.1k
    if (0x100 <= m_state->m_eot) {
832
31.6k
      MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: problem with text position: reset begin to default\n"));
833
31.6k
      m_state->m_bot = 0x100;
834
31.6k
    }
835
37.5k
    else {
836
37.5k
      MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: problem with text position: reset to empty\n"));
837
37.5k
      m_state->m_bot = m_state->m_eot = 0x100;
838
37.5k
    }
839
69.1k
  }
840
841
218k
  if (vers <= 3) { // always 0
842
733k
    for (int i = 0; i < 6; i++) {
843
628k
      val = static_cast<int>(input->readLong(2));
844
628k
      if (val) f << "h" << i << "=" << val << ",";
845
628k
    }
846
104k
    ascii().addPos(pos);
847
104k
    ascii().addNote(f.str().c_str());
848
104k
    if (!readHeaderEndV3())
849
365
      return false;
850
104k
    if (header)
851
38.4k
      header->reset(MWAWDocument::MWAW_T_MICROSOFTWORD, vers);
852
104k
    return true;
853
104k
  }
854
855
113k
  auto endOfData = long(input->readULong(4));
856
113k
  f << "eof=" << std::hex << endOfData << std::dec << ",";
857
113k
  if (endOfData < 100 || !input->checkPosition(endOfData)) {
858
63.6k
    MWAW_DEBUG_MSG(("MsWrdParser::checkHeader: end of file pos is too small\n"));
859
63.6k
    if (endOfData < m_state->m_eot || strict)
860
16.9k
      return false;
861
46.7k
    f << "#endOfData,";
862
46.7k
  }
863
96.9k
  ascii().addPos(endOfData);
864
96.9k
  ascii().addNote("Entries(End)");
865
866
96.9k
  val = static_cast<int>(input->readLong(4)); // always 0 ?
867
96.9k
  if (val) f << "unkn2=" << val << ",";
868
96.9k
  ascii().addPos(pos);
869
96.9k
  ascii().addNote(f.str().c_str());
870
871
96.9k
  if (!m_textParser->readHeaderTextLength())
872
0
    return false;
873
874
96.9k
  pos = input->tell();
875
96.9k
  f.str("");
876
96.9k
  f << "FileHeader[A]:";
877
872k
  for (int i = 0; i < 8; i++) {
878
775k
    val = static_cast<int>(input->readLong(2));
879
775k
    if (val) f << "f" << i << "=" << val << ",";
880
775k
  }
881
882
  // ok, we can finish initialization
883
96.9k
  if (header)
884
34.8k
    header->reset(MWAWDocument::MWAW_T_MICROSOFTWORD, vers);
885
886
96.9k
  if (long(input->tell()) != headerSize)
887
0
    ascii().addDelimiter(input->tell(), '|');
888
889
96.9k
  ascii().addPos(pos);
890
96.9k
  ascii().addNote(f.str().c_str());
891
892
96.9k
  return true;
893
96.9k
}
894
895
////////////////////////////////////////////////////////////
896
// try to the end of the header
897
////////////////////////////////////////////////////////////
898
bool MsWrdParser::readHeaderEndV3()
899
104k
{
900
104k
  MWAWInputStreamPtr input = getInput();
901
104k
  if (!input->checkPosition(0xb8))
902
365
    return false;
903
104k
  libmwaw::DebugStream f;
904
104k
  input->seek(0x78, librevenge::RVNG_SEEK_SET);
905
104k
  long pos = input->tell();
906
104k
  long val = input->readLong(4); // normally 0x100
907
104k
  if (val != 0x100)
908
101k
    f << "FileHeader[A]:" << std::hex << val << std::dec << ",";
909
2.65k
  else
910
2.65k
    f << "_";
911
104k
  ascii().addPos(pos);
912
104k
  ascii().addNote(f.str().c_str());
913
104k
  if (!m_textParser->readHeaderTextLength())
914
0
    return false;
915
104k
  pos = input->tell();
916
104k
  f << "FileHeader[B]:";
917
1.98M
  for (int i = 0; i < 18; i++) { // always 0 ?
918
1.87M
    val = input->readLong(2);
919
1.87M
    if (val)
920
1.29M
      f << "f" << i << "=" << val << ",";
921
1.87M
  }
922
104k
  float dim[6]; // H, W+margin T, L, B, R
923
626k
  for (auto &d : dim) d = float(input->readLong(2))/1440.0f;
924
925
104k
  f << "page=" << dim[1] << "x" << dim[0] << ",";
926
104k
  f << "margins=" << dim[3] << "x" << dim[2] << "-" << dim[5] << "x" << dim[4] << ",";
927
104k
  bool dimOk = true;
928
104k
  if (dim[0]>0 && dim[1]>0) {
929
187k
    for (int i = 2; i < 6; i++)
930
150k
      if (dim[i] < 0) dimOk = false;
931
37.5k
    if (2*(dim[3]+dim[5]) > dim[1] || 2*(dim[2]+dim[4]) > dim[0]) dimOk = false;
932
37.5k
    if (!dimOk) {
933
34.3k
      f << "###";
934
34.3k
      MWAW_DEBUG_MSG(("MsWrdParser::readHeaderEndV3: page dimensions seem bad\n"));
935
34.3k
    }
936
3.26k
    else {
937
3.26k
      getPageSpan().setMarginTop(double(dim[2]));
938
3.26k
      getPageSpan().setMarginLeft(double(dim[3]));
939
3.26k
      getPageSpan().setMarginBottom((dim[4]< 0.5f) ? 0.0 : double(dim[4])-0.5);
940
3.26k
      getPageSpan().setMarginRight((dim[5]< 0.5f) ? 0.0 : double(dim[5])-0.5);
941
3.26k
      getPageSpan().setFormLength(double(dim[0]));
942
3.26k
      getPageSpan().setFormWidth(double(dim[1]));
943
3.26k
    }
944
37.5k
  }
945
66.7k
  else
946
66.7k
    dimOk = false;
947
104k
  ascii().addPos(pos);
948
104k
  ascii().addNote(f.str().c_str());
949
950
104k
  pos = input->tell();
951
104k
  f.str("");
952
104k
  f << "FileHeader[C]:";
953
104k
  val = input->readLong(2); // always 0 ?
954
104k
  if (val)
955
66.0k
    f << "margins[binding]=" << float(val)/1440.f << ",";
956
104k
  val = input->readLong(2);
957
104k
  f << "defTabs=" << float(val)/1440.f << ",";
958
104k
  auto flags = static_cast<int>(input->readULong(1));
959
104k
  if (flags & 0x80) // page vis a vis
960
14.0k
    f << "facingpage,";
961
104k
  if (flags & 0x40) // ligne creuse
962
20.3k
    f << "defTabs[emptyline],";
963
104k
  switch ((flags>>1) & 0x3) {
964
63.4k
  case 0:
965
63.4k
    if (dimOk) m_state->m_endNote = true;
966
63.4k
    f << "endnote,";
967
63.4k
    break;
968
9.28k
  case 1:
969
9.28k
    f << "footnote,";
970
9.28k
    break;
971
12.2k
  case 2:
972
12.2k
    f << "footnote[undertext],";
973
12.2k
    break;
974
19.3k
  default:
975
19.3k
    f << "#notepos=3,";
976
19.3k
    break;
977
104k
  }
978
104k
  if (flags&1) {
979
32.0k
    f << "landscape,";
980
32.0k
    if (dimOk)
981
611
      getPageSpan().setFormOrientation(MWAWPageSpan::LANDSCAPE);
982
32.0k
  }
983
104k
  flags &= 0x38;
984
104k
  if (flags)
985
42.1k
    f << "#flags=" << std::hex << flags << std::dec << ",";
986
104k
  flags = static_cast<int>(input->readULong(1));
987
104k
  if (flags) // always 1
988
55.6k
    f << "fl1=" << std::hex << flags << std::dec << ",";
989
104k
  char const *wh[] = { "note", "line", "page" };
990
313k
  for (auto const *what : wh) {
991
313k
    val = long(input->readULong(2));
992
313k
    if (val == 1) continue;
993
298k
    if (val & 0x8000)
994
49.0k
      f << what << "[firstNumber]=" << (val&0x7FFF) << "[auto],";
995
249k
    else
996
249k
      f << what << "[firstNumber]=" << val << ",";
997
298k
  }
998
313k
  for (int i = 0; i < 2; i++) { // first flags often 0x40, second?
999
208k
    flags = static_cast<int>(input->readULong(1));
1000
208k
    if (flags) // always 1
1001
104k
      f << "fl" << 2+i << "=" << std::hex << flags << std::dec << ",";
1002
208k
  }
1003
1.46M
  for (int i = 0; i < 13; i++) { // always 0?
1004
1.35M
    val = input->readLong(2);
1005
1.35M
    if (val)
1006
819k
      f << "f" << i << "=" << val << ",";
1007
1.35M
  }
1008
104k
  ascii().addPos(pos);
1009
104k
  ascii().addNote(f.str().c_str());
1010
1011
104k
  pos = input->tell();
1012
104k
  f.str("");
1013
104k
  f << "FileHeader[D]:";
1014
104k
  auto sz = static_cast<int>(input->readULong(1));
1015
104k
  if (sz == 0) {
1016
50.7k
    ascii().addPos(pos);
1017
50.7k
    ascii().addNote("_");
1018
50.7k
    return true;
1019
50.7k
  }
1020
53.5k
  if (sz > 31) {
1021
29.7k
    f << "###";
1022
29.7k
    MWAW_DEBUG_MSG(("MsWrdParser::readHeaderEndV3: next filename seems bad\n"));
1023
29.7k
  }
1024
23.8k
  else {
1025
23.8k
    std::string fName("");
1026
316k
    for (int i = 0; i < sz; i++)
1027
292k
      fName += char(input->readULong(1));
1028
23.8k
    f << "nextFile=" << fName;
1029
23.8k
  }
1030
53.5k
  ascii().addPos(pos);
1031
53.5k
  ascii().addNote(f.str().c_str());
1032
53.5k
  input->seek(0x100, librevenge::RVNG_SEEK_SET);
1033
53.5k
  return true;
1034
104k
}
1035
1036
////////////////////////////////////////////////////////////
1037
// try to read an entry
1038
////////////////////////////////////////////////////////////
1039
MsWrdEntry MsWrdParser::readEntry(std::string type, int id)
1040
1.39M
{
1041
1.39M
  MWAWInputStreamPtr input = getInput();
1042
1.39M
  MsWrdEntry entry;
1043
1.39M
  entry.setType(type);
1044
1.39M
  entry.setId(id);
1045
1.39M
  long pos = input->tell();
1046
1.39M
  libmwaw::DebugStream f;
1047
1048
1.39M
  auto debPos = long(input->readULong(4));
1049
1.39M
  auto sz = long(input->readULong(2));
1050
1.39M
  if (id >= 0) f << "Entries(" << type << ")[" << id << "]:";
1051
959k
  else f << "Entries(" << type << "):";
1052
1.39M
  if (sz == 0) {
1053
481k
    ascii().addPos(pos);
1054
481k
    ascii().addNote("_");
1055
481k
    return entry;
1056
481k
  }
1057
909k
  if (!input->checkPosition(debPos+sz)) {
1058
680k
    MWAW_DEBUG_MSG(("MsWrdParser::readEntry: problem reading entry: %s\n", type.c_str()));
1059
680k
    f << "#";
1060
680k
    ascii().addPos(pos);
1061
680k
    ascii().addNote(f.str().c_str());
1062
680k
    return entry;
1063
680k
  }
1064
1065
229k
  entry.setBegin(debPos);
1066
229k
  entry.setLength(sz);
1067
229k
  m_entryMap.insert
1068
229k
  (std::multimap<std::string, MsWrdEntry>::value_type(type, entry));
1069
1070
229k
  f << std::hex << debPos << "[" << sz << "],";
1071
229k
  ascii().addPos(pos);
1072
229k
  ascii().addNote(f.str().c_str());
1073
1074
229k
  return entry;
1075
909k
}
1076
1077
////////////////////////////////////////////////////////////
1078
// read the document information
1079
////////////////////////////////////////////////////////////
1080
bool MsWrdParser::readDocumentInfo(MsWrdEntry &entry)
1081
4.27k
{
1082
4.27k
  if (entry.length() != 0x20) {
1083
2.34k
    MWAW_DEBUG_MSG(("MsWrdParser::readDocumentInfo: the zone size seems odd\n"));
1084
2.34k
    return false;
1085
2.34k
  }
1086
1.92k
  MWAWInputStreamPtr input = getInput();
1087
1.92k
  long pos = entry.begin();
1088
1.92k
  entry.setParsed(true);
1089
1.92k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1090
1.92k
  libmwaw::DebugStream f;
1091
1.92k
  f << "DocumentInfo:";
1092
1093
1.92k
  float dim[2];
1094
3.85k
  for (float &i : dim) i =  float(input->readLong(2))/1440.f;
1095
1.92k
  f << "dim?=" << dim[1] << "x" << dim[0] << ",";
1096
1097
1.92k
  float margin[4];
1098
1.92k
  f << ",marg=["; // top, left?, bottom, right?
1099
7.71k
  for (auto &marg : margin) {
1100
7.71k
    marg = float(input->readLong(2))/1440.f;
1101
7.71k
    f << marg << ",";
1102
7.71k
    if (marg < 0) marg *= -1.0f;
1103
7.71k
  }
1104
1.92k
  f << "],";
1105
1106
1.92k
  if (dim[0] > margin[0]+margin[2] && dim[1] > margin[1]+margin[3]) {
1107
1.31k
    getPageSpan().setMarginTop(double(margin[0]));
1108
1.31k
    getPageSpan().setMarginLeft(double(margin[1]));
1109
    /* decrease a little the right/bottom margin to allow fonts discrepancy*/
1110
1.31k
    getPageSpan().setMarginBottom((margin[2]< 0.5f) ? 0.0 : double(margin[2])-0.5);
1111
1.31k
    getPageSpan().setMarginRight((margin[3]< 0.5f) ? 0.0 : double(margin[3])-0.5);
1112
1113
1.31k
    getPageSpan().setFormLength(double(dim[0]));
1114
1.31k
    getPageSpan().setFormWidth(double(dim[1]));
1115
1.31k
  }
1116
615
  else {
1117
615
    MWAW_DEBUG_MSG(("MsWrdParser::readDocumentInfo: the page dimensions seems odd\n"));
1118
615
  }
1119
1120
1.92k
  auto val = static_cast<int>(input->readLong(2)); // always 0 ?
1121
1.92k
  if (val) f << "unkn=" << val << ",";
1122
1.92k
  val = static_cast<int>(input->readLong(2)); // 0x2c5 or 0x2d0?
1123
1.92k
  f << "f0=" << val << ",";
1124
9.64k
  for (int i = 0; i < 4; i++) { //[a|12|40|42|4a|52|54|d2],0,0|80,1
1125
7.71k
    val = static_cast<int>(input->readULong(1));
1126
7.71k
    if (val) f << "fl" << i << "=" << std::hex << val << std::dec << ",";
1127
7.71k
  }
1128
1.92k
  val = static_cast<int>(input->readLong(2)); // always 1 ?
1129
1.92k
  if (val != 1) f << "f1=" << val << ",";
1130
  // a small number between 0 and 77
1131
1.92k
  f << "f2=" << static_cast<int>(input->readLong(2)) << ",";
1132
9.64k
  for (int i = 0; i < 4; i++) { //[0|2|40|42|44|46|48|58],0|64,0|10|80,[0|2|5]
1133
7.71k
    val = static_cast<int>(input->readULong(1));
1134
7.71k
    if (val) f << "flA" << i << "=" << std::hex << val << std::dec << ",";
1135
7.71k
  }
1136
1.92k
  val = static_cast<int>(input->readLong(2)); // always 0 ?
1137
1.92k
  if (val != 1) f << "f3=" << val << ",";
1138
1.92k
  val = static_cast<int>(input->readLong(2)); // 0, 48, 50
1139
1.92k
  if (val) f << "f4=" << val << ",";
1140
1141
1.92k
  ascii().addPos(entry.begin());
1142
1.92k
  ascii().addNote(f.str().c_str());
1143
1.92k
  ascii().addPos(entry.end());
1144
1.92k
  ascii().addNote("_");
1145
1.92k
  return true;
1146
4.27k
}
1147
1148
////////////////////////////////////////////////////////////
1149
// read the zone 17
1150
////////////////////////////////////////////////////////////
1151
bool MsWrdParser::readZone17(MsWrdEntry &entry)
1152
2.86k
{
1153
2.86k
  if (entry.length() != 0x2a) {
1154
1.08k
    MWAW_DEBUG_MSG(("MsWrdParser::readZone17: the zone size seems odd\n"));
1155
1.08k
    return false;
1156
1.08k
  }
1157
1.77k
  MWAWInputStreamPtr input = getInput();
1158
1.77k
  long pos = entry.begin();
1159
1.77k
  entry.setParsed(true);
1160
1.77k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1161
1.77k
  libmwaw::DebugStream f;
1162
1.77k
  f << "Zone17:";
1163
1.77k
  if (version() < 5) {
1164
21
    f << "bdbox?=[";
1165
105
    for (int i = 0; i < 4; i++)
1166
84
      f << input->readLong(2) << ",";
1167
21
    f << "],";
1168
21
    f << "bdbox2?=[";
1169
105
    for (int i = 0; i < 4; i++)
1170
84
      f << input->readLong(2) << ",";
1171
21
    f << "],";
1172
21
  }
1173
1174
  /*
1175
    f0=0, 80, 82, 84, b0, b4, c2, c4, f0, f2 : type and ?
1176
    f1=0|1|8|34|88 */
1177
1.77k
  int val;
1178
5.32k
  for (int i = 0; i < 2; i++) {
1179
3.54k
    val = static_cast<int>(input->readULong(1));
1180
3.54k
    if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1181
3.54k
  }
1182
  // 0 or 1, followed by 0
1183
5.32k
  for (int i = 2; i < 4; i++) {
1184
3.54k
    val = static_cast<int>(input->readLong(1));
1185
3.54k
    if (val) f << "f" << i << "=" << val << ",";
1186
3.54k
  }
1187
1.77k
  auto ptr = long(input->readULong(4)); // a text ptr ( often near to textLength )
1188
1.77k
  f << "textPos[sel?]=" << std::hex << ptr << std::dec << ",";
1189
1.77k
  val  = static_cast<int>(input->readULong(4)); // almost always ptr
1190
1.77k
  if (val != ptr)
1191
822
    f << "textPos1=" << std::hex << val << std::dec << ",";
1192
  // a small int between 6 and b
1193
1.77k
  val = static_cast<int>(input->readLong(2));
1194
1.77k
  if (val) f << "f4=" << val << ",";
1195
1196
5.32k
  for (int i = 5; i < 7; i++) { // 0,0 or 3,5 or 8000, 8000
1197
3.54k
    val = static_cast<int>(input->readULong(2));
1198
3.54k
    if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1199
3.54k
  }
1200
1.77k
  val  = static_cast<int>(input->readULong(4)); // almost always ptr
1201
1.77k
  if (val != ptr)
1202
680
    f << "textPos2=" << std::hex << val << std::dec << ",";
1203
  /* g0=[0,1,5,c], g1=[0,1,3,4] */
1204
5.32k
  for (int i = 0; i < 2; i++) {
1205
3.54k
    val = static_cast<int>(input->readLong(2));
1206
3.54k
    if (val) f << "g" << i << "=" << val << ",";
1207
3.54k
  }
1208
1.77k
  if (version() == 5) {
1209
1.75k
    f << "bdbox?=[";
1210
8.76k
    for (int i = 0; i < 4; i++)
1211
7.01k
      f << input->readLong(2) << ",";
1212
1.75k
    f << "],";
1213
1.75k
    f << "bdbox2?=[";
1214
8.76k
    for (int i = 0; i < 4; i++)
1215
7.01k
      f << input->readLong(2) << ",";
1216
1.75k
    f << "],";
1217
1.75k
  }
1218
1.77k
  ascii().addPos(pos);
1219
1.77k
  ascii().addNote(f.str().c_str());
1220
1.77k
  ascii().addPos(entry.end());
1221
1.77k
  ascii().addNote("_");
1222
1.77k
  return true;
1223
2.86k
}
1224
1225
////////////////////////////////////////////////////////////
1226
// read the printer name
1227
////////////////////////////////////////////////////////////
1228
bool MsWrdParser::readPrinter(MsWrdEntry &entry)
1229
4.63k
{
1230
4.63k
  if (entry.length() < 2) {
1231
159
    MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: the zone seems to short\n"));
1232
159
    return false;
1233
159
  }
1234
1235
4.47k
  MWAWInputStreamPtr input = getInput();
1236
4.47k
  long pos = entry.begin();
1237
4.47k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1238
4.47k
  libmwaw::DebugStream f;
1239
4.47k
  f << "Printer:";
1240
4.47k
  auto sz = static_cast<int>(input->readULong(2));
1241
4.47k
  if (sz > entry.length()) {
1242
2.52k
    MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: the zone seems to short\n"));
1243
2.52k
    return false;
1244
2.52k
  }
1245
1.95k
  auto strSz = static_cast<int>(input->readULong(1));
1246
1.95k
  if (strSz+2> sz) {
1247
352
    MWAW_DEBUG_MSG(("MsWrdParser::readPrinter: name seems to big\n"));
1248
352
    return false;
1249
352
  }
1250
1.60k
  std::string name("");
1251
39.9k
  for (int i = 0; i < strSz; i++)
1252
38.3k
    name+=char(input->readLong(1));
1253
1.60k
  f << name << ",";
1254
1.60k
  int i= 0;
1255
1.14M
  while (long(input->tell())+2 <= entry.end()) { // almost always a,0,0
1256
1.14M
    auto val = static_cast<int>(input->readLong(2));
1257
1.14M
    if (val) f << "f" << i << "=" << val << ",";
1258
1.14M
    i++;
1259
1.14M
  }
1260
1.60k
  if (long(input->tell()) != entry.end())
1261
210
    ascii().addDelimiter(input->tell(), '|');
1262
1263
1.60k
  entry.setParsed(true);
1264
1.60k
  ascii().addPos(pos);
1265
1.60k
  ascii().addNote(f.str().c_str());
1266
1267
1.60k
  ascii().addPos(entry.end());
1268
1.60k
  ascii().addNote("_");
1269
1.60k
  return true;
1270
1.95k
}
1271
1272
////////////////////////////////////////////////////////////
1273
// read the document summary
1274
////////////////////////////////////////////////////////////
1275
bool MsWrdParser::readDocSum(MsWrdEntry &entry)
1276
5.35k
{
1277
5.35k
  MWAWInputStreamPtr input = getInput();
1278
5.35k
  if (entry.length() < 8 || !input->checkPosition(entry.end())) {
1279
246
    MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: the zone seems to short\n"));
1280
246
    return false;
1281
246
  }
1282
1283
5.11k
  long pos = entry.begin();
1284
5.11k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1285
5.11k
  libmwaw::DebugStream f;
1286
5.11k
  f << "DocSum:";
1287
5.11k
  auto sz = static_cast<int>(input->readULong(2));
1288
5.11k
  if (sz > entry.length()) {
1289
1.60k
    MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: the zone seems to short\n"));
1290
1.60k
    return false;
1291
1.60k
  }
1292
3.51k
  entry.setParsed(true);
1293
1294
3.51k
  if (sz != entry.length()) f << "#";
1295
3.51k
  char const *what[] = { "title", "subject","author","version","keyword",
1296
3.51k
                         "creator", "author1", "author2" // unsure why there are 4 authors...
1297
3.51k
                       };
1298
3.51k
  char const *attribNames[] = { "dc:title", "dc:subject", "meta:initial-creator", nullptr,
1299
3.51k
                                "meta:keywords", "dc:creator", nullptr, nullptr
1300
3.51k
                              };
1301
3.51k
  auto fontConverter = getFontConverter();
1302
26.8k
  for (int i = 0; i < 8; i++) {
1303
24.7k
    long actPos = input->tell();
1304
24.7k
    if (actPos == entry.end()) break;
1305
1306
24.0k
    sz = static_cast<int>(input->readULong(1));
1307
24.0k
    if (sz == 0 || sz == 0xFF) continue;
1308
1309
9.28k
    if (actPos+1+sz > entry.end()) {
1310
723
      MWAW_DEBUG_MSG(("MsWrdParser::readDocSum: string %d to short...\n", i));
1311
723
      f << "#";
1312
723
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
1313
723
      break;
1314
723
    }
1315
8.55k
    librevenge::RVNGString s;
1316
323k
    for (int j = 0; j < sz; j++) {
1317
314k
      auto c= static_cast<unsigned char>(input->readULong(1));
1318
      // assume standart encoding here
1319
314k
      int unicode = fontConverter ? fontConverter->unicode(3, c) : -1;
1320
314k
      if (unicode!=-1)
1321
174k
        libmwaw::appendUnicode(uint32_t(unicode), s);
1322
140k
      else if (c<0x20)
1323
140k
        f << "##" << int(c);
1324
0
      else
1325
0
        s.append(char(c));
1326
314k
    }
1327
8.55k
    if (!s.empty() && attribNames[i]!=nullptr)
1328
5.01k
      m_state->m_metaData.insert(attribNames[i],s);
1329
8.55k
    f << what[i] << "=" <<  s.cstr() << ",";
1330
8.55k
  }
1331
1332
3.51k
  ascii().addPos(pos);
1333
3.51k
  ascii().addNote(f.str().c_str());
1334
1335
3.51k
  if (long(input->tell()) != entry.end())
1336
2.84k
    ascii().addDelimiter(input->tell(), '|');
1337
1338
3.51k
  ascii().addPos(entry.end());
1339
3.51k
  ascii().addNote("_");
1340
3.51k
  return true;
1341
5.11k
}
1342
1343
////////////////////////////////////////////////////////////
1344
// read  a list of strings zone
1345
////////////////////////////////////////////////////////////
1346
bool MsWrdParser::readStringsZone(MsWrdEntry &entry, std::vector<std::string> &list)
1347
6.88k
{
1348
6.88k
  list.resize(0);
1349
6.88k
  MWAWInputStreamPtr input = getInput();
1350
6.88k
  if (entry.length() < 2 || !input->checkPosition(entry.end())) {
1351
491
    MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: the zone seems to short\n"));
1352
491
    return false;
1353
491
  }
1354
1355
6.39k
  long pos = entry.begin();
1356
6.39k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1357
6.39k
  libmwaw::DebugStream f;
1358
6.39k
  f << entry;
1359
6.39k
  auto sz = static_cast<int>(input->readULong(2));
1360
6.39k
  if (sz > entry.length()) {
1361
2.09k
    MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: the zone seems to short\n"));
1362
2.09k
    return false;
1363
2.09k
  }
1364
4.30k
  ascii().addPos(entry.begin());
1365
4.30k
  ascii().addNote(f.str().c_str());
1366
1367
4.30k
  int id = 0;
1368
2.38M
  while (long(input->tell()) != entry.end()) {
1369
2.37M
    pos = input->tell();
1370
2.37M
    auto strSz = static_cast<int>(input->readULong(1));
1371
2.37M
    if (pos+strSz+1> entry.end()) {
1372
2.93k
      MWAW_DEBUG_MSG(("MsWrdParser::readStringsZone: a string seems to big\n"));
1373
2.93k
      f << "#";
1374
2.93k
      break;
1375
2.93k
    }
1376
2.37M
    std::string name("");
1377
24.0M
    for (int i = 0; i < strSz; i++)
1378
21.6M
      name+=char(input->readLong(1));
1379
2.37M
    list.push_back(name);
1380
2.37M
    f.str("");
1381
2.37M
    f << entry << "id" << id++ << "," << name << ",";
1382
2.37M
    ascii().addPos(pos);
1383
2.37M
    ascii().addNote(f.str().c_str());
1384
2.37M
  }
1385
1386
4.30k
  if (long(input->tell()) != entry.end()) {
1387
2.83k
    ascii().addPos(input->tell());
1388
2.83k
    f.str("");
1389
2.83k
    f << entry << "#";
1390
2.83k
    ascii().addNote(f.str().c_str());
1391
2.83k
  }
1392
1393
4.30k
  entry.setParsed(true);
1394
1395
4.30k
  ascii().addPos(entry.end());
1396
4.30k
  ascii().addNote("_");
1397
4.30k
  return true;
1398
6.39k
}
1399
1400
////////////////////////////////////////////////////////////
1401
// read the objects
1402
////////////////////////////////////////////////////////////
1403
bool MsWrdParser::readObjects()
1404
63.6k
{
1405
63.6k
  MWAWInputStreamPtr input = getInput();
1406
1407
63.6k
  auto it = m_entryMap.find("ObjectList");
1408
72.4k
  while (it != m_entryMap.end()) {
1409
16.0k
    if (!it->second.hasType("ObjectList")) break;
1410
8.86k
    MsWrdEntry &entry=it++->second;
1411
8.86k
    readObjectList(entry);
1412
8.86k
  }
1413
1414
63.6k
  it = m_entryMap.find("ObjectFlags");
1415
70.5k
  while (it != m_entryMap.end()) {
1416
12.8k
    if (!it->second.hasType("ObjectFlags")) break;
1417
6.91k
    MsWrdEntry &entry=it++->second;
1418
6.91k
    readObjectFlags(entry);
1419
6.91k
  }
1420
1421
63.6k
  it = m_entryMap.find("ObjectName");
1422
70.4k
  while (it != m_entryMap.end()) {
1423
12.5k
    if (!it->second.hasType("ObjectName")) break;
1424
6.88k
    MsWrdEntry &entry=it++->second;
1425
6.88k
    std::vector<std::string> list;
1426
6.88k
    readStringsZone(entry, list);
1427
1428
6.88k
    if (entry.id() < 0 || entry.id() > 1) {
1429
0
      MWAW_DEBUG_MSG(("MsWrdParser::readObjects: unexpected entry id: %d\n", entry.id()));
1430
0
      continue;
1431
0
    }
1432
6.88k
    auto &listObject = m_state->m_objectList[entry.id()];
1433
6.88k
    size_t numObjects = listObject.size();
1434
6.88k
    if (list.size() != numObjects) {
1435
4.27k
      MWAW_DEBUG_MSG(("MsWrdParser::readObjects: unexpected number of name\n"));
1436
4.27k
      if (list.size() < numObjects) numObjects = list.size();
1437
4.27k
    }
1438
326k
    for (size_t i = 0; i < numObjects; i++)
1439
319k
      listObject[i].m_name = list[i];
1440
6.88k
  }
1441
1442
63.6k
  std::map<long, MWAWEntry> posToComments;
1443
127k
  for (auto &listObject : m_state->m_objectList) {
1444
1.98M
    for (auto &obj : listObject) {
1445
1.98M
      readObject(obj);
1446
1.98M
      if (obj.m_annotation.valid() && obj.m_textPos>=0)
1447
0
        posToComments[obj.m_textPos]=obj.m_annotation;
1448
1.98M
    }
1449
127k
  }
1450
63.6k
  m_state->m_posToCommentMap=posToComments;
1451
63.6k
  return true;
1452
63.6k
}
1453
1454
bool MsWrdParser::readObjectList(MsWrdEntry &entry)
1455
8.86k
{
1456
8.86k
  if (entry.id() < 0 || entry.id() > 1) {
1457
0
    MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: unexpected entry id: %d\n", entry.id()));
1458
0
    return false;
1459
0
  }
1460
8.86k
  std::vector<MsWrdParserInternal::Object> &listObject = m_state->m_objectList[entry.id()];
1461
8.86k
  listObject.resize(0);
1462
8.86k
  if (entry.length() < 4 || (entry.length()%18) != 4) {
1463
1.83k
    MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: the zone size seems odd\n"));
1464
1.83k
    return false;
1465
1.83k
  }
1466
7.02k
  MWAWInputStreamPtr input = getInput();
1467
7.02k
  long pos = entry.begin();
1468
7.02k
  entry.setParsed(true);
1469
7.02k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1470
7.02k
  libmwaw::DebugStream f;
1471
7.02k
  f << "ObjectList[" << entry.id() << "]:";
1472
7.02k
  auto N=int(entry.length()/18);
1473
1474
7.02k
  auto &plcMap=m_textParser->getTextPLCMap();
1475
7.02k
  MsWrdText::PLC plc(MsWrdText::PLC::Object);
1476
7.02k
  std::vector<long> textPos; // checkme
1477
7.02k
  textPos.resize(size_t(N)+1);
1478
7.02k
  f << "[";
1479
1.99M
  for (int i = 0; i < N+1; i++) {
1480
1.99M
    auto tPos = long(input->readULong(4));
1481
1.99M
    textPos[size_t(i)] = tPos;
1482
1.99M
    f << std::hex << tPos << std::dec << ",";
1483
1.99M
    if (i == N)
1484
7.02k
      break;
1485
1.98M
    plc.m_id = i;
1486
1.98M
    plcMap.insert(std::multimap<long, MsWrdText::PLC>::value_type(tPos,plc));
1487
1.98M
  }
1488
7.02k
  f << "],";
1489
7.02k
  ascii().addPos(pos);
1490
7.02k
  ascii().addNote(f.str().c_str());
1491
1492
1.99M
  for (int i = 0; i < N; i++) {
1493
1.98M
    MsWrdParserInternal::Object object;
1494
1.98M
    object.m_textPos = textPos[size_t(i)];
1495
1.98M
    pos = input->tell();
1496
1.98M
    f.str("");
1497
1.98M
    object.m_id = static_cast<int>(input->readLong(2));
1498
    // id0=<small number>:[8|48], id1: <small number>:60->normal, :7c?, 0->annotation ?
1499
5.96M
    for (int st = 0; st < 2; st++) {
1500
3.97M
      object.m_ids[st] = static_cast<int>(input->readLong(2));
1501
3.97M
      object.m_idsFlag[st] = static_cast<int>(input->readULong(1));
1502
3.97M
    }
1503
1504
1.98M
    object.m_pos.setBegin(long(input->readULong(4)));
1505
1.98M
    auto val = static_cast<int>(input->readLong(2)); // always 0 ?
1506
1.98M
    if (val) f << "#f1=" << val << ",";
1507
1.98M
    object.m_extra = f.str();
1508
1.98M
    f.str("");
1509
1.98M
    f << "ObjectList-" << i << ":" << object;
1510
1.98M
    if (!input->checkPosition(object.m_pos.begin())) {
1511
1.13M
      MWAW_DEBUG_MSG(("MsWrdParser::readObjectList: pb with ptr\n"));
1512
1.13M
      f << "#ptr=" << std::hex << object.m_pos.begin() << std::dec << ",";
1513
1.13M
      object.m_pos.setBegin(0);
1514
1.13M
    }
1515
1516
1.98M
    listObject.push_back(object);
1517
1.98M
    ascii().addPos(pos);
1518
1.98M
    ascii().addNote(f.str().c_str());
1519
1.98M
  }
1520
1521
7.02k
  ascii().addPos(entry.end());
1522
7.02k
  ascii().addNote("_");
1523
7.02k
  return true;
1524
1525
8.86k
}
1526
1527
bool MsWrdParser::readObjectFlags(MsWrdEntry &entry)
1528
6.91k
{
1529
6.91k
  if (entry.id() < 0 || entry.id() > 1) {
1530
0
    MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: unexpected entry id: %d\n", entry.id()));
1531
0
    return false;
1532
0
  }
1533
6.91k
  std::vector<MsWrdParserInternal::Object> &listObject = m_state->m_objectList[entry.id()];
1534
6.91k
  auto numObject = static_cast<int>(listObject.size());
1535
6.91k
  if (entry.length() < 4 || (entry.length()%6) != 4) {
1536
2.30k
    MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: the zone size seems odd\n"));
1537
2.30k
    return false;
1538
2.30k
  }
1539
4.61k
  MWAWInputStreamPtr input = getInput();
1540
4.61k
  long pos = entry.begin();
1541
4.61k
  entry.setParsed(true);
1542
4.61k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1543
4.61k
  libmwaw::DebugStream f;
1544
4.61k
  f << "ObjectFlags[" << entry.id() << "]:";
1545
4.61k
  auto N=int(entry.length()/6);
1546
4.61k
  if (N != numObject) {
1547
3.00k
    MWAW_DEBUG_MSG(("MsWrdParser::readObjectFlags: unexpected number of object\n"));
1548
3.00k
  }
1549
1550
4.61k
  f << "[";
1551
1.81M
  for (int i = 0; i < N+1; i++) {
1552
1.80M
    auto textPos = long(input->readULong(4));
1553
1.80M
    if (i < numObject && textPos != listObject[size_t(i)].m_textPos && textPos != listObject[size_t(i)].m_textPos+1)
1554
65.0k
      f << "#";
1555
1.80M
    f << std::hex << textPos << std::dec << ",";
1556
1.80M
  }
1557
4.61k
  f << "],";
1558
4.61k
  ascii().addPos(pos);
1559
4.61k
  ascii().addNote(f.str().c_str());
1560
1561
1.80M
  for (int i = 0; i < N; i++) {
1562
1.80M
    pos = input->tell();
1563
1.80M
    int flags[2];
1564
3.60M
    for (auto &flag : flags) flag = static_cast<int>(input->readULong(1));
1565
1.80M
    f.str("");
1566
1.80M
    f << "ObjectFlags-" << i << ":";
1567
1.80M
    if (i < numObject) {
1568
1.50M
      for (int st = 0; st < 2; st++) listObject[size_t(i)].m_flags[st] = flags[st];
1569
501k
      f << "Obj" << listObject[size_t(i)].m_id << ",";
1570
501k
    }
1571
    // indentical to ObjectList id0[low] ?
1572
1.80M
    if (flags[0] != 0x48) f << "fl0="  << std::hex << flags[0] << std::dec << ",";
1573
1.80M
    if (flags[1]) f << "fl1="  << std::hex << flags[1] << std::dec << ",";
1574
1.80M
    ascii().addPos(pos);
1575
1.80M
    ascii().addNote(f.str().c_str());
1576
1.80M
  }
1577
1578
4.61k
  ascii().addPos(entry.end());
1579
4.61k
  ascii().addNote("_");
1580
4.61k
  return true;
1581
1582
6.91k
}
1583
1584
bool MsWrdParser::readObject(MsWrdParserInternal::Object &obj)
1585
1.98M
{
1586
1.98M
  MWAWInputStreamPtr input = getInput();
1587
1.98M
  libmwaw::DebugStream f;
1588
1589
1.98M
  long pos = obj.m_pos.begin(), beginPos = pos;
1590
1.98M
  if (!pos) return false;
1591
1592
445k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1593
445k
  auto sz = static_cast<int>(input->readULong(4));
1594
1595
445k
  f << "Entries(ObjectData):Obj" << obj.m_id << ",";
1596
445k
  if (!input->checkPosition(pos+sz) || sz < 6) {
1597
339k
    MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb finding object data sz\n"));
1598
339k
    f << "#";
1599
339k
    ascii().addPos(beginPos);
1600
339k
    ascii().addNote(f.str().c_str());
1601
339k
    return false;
1602
339k
  }
1603
105k
  obj.m_pos.setLength(sz);
1604
105k
  long endPos = obj.m_pos.end();
1605
105k
  ascii().addPos(endPos);
1606
105k
  ascii().addNote("_");
1607
1608
105k
  auto fSz = static_cast<int>(input->readULong(2));
1609
105k
  if (fSz < 0 || fSz+6 > sz) {
1610
12.7k
    MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the name\n"));
1611
12.7k
    f << "#";
1612
12.7k
    ascii().addPos(beginPos);
1613
12.7k
    ascii().addNote(f.str().c_str());
1614
12.7k
    return false;
1615
12.7k
  }
1616
93.1k
  MsWrdEntry fileEntry = obj.getEntry();
1617
93.1k
  fileEntry.setParsed(true);
1618
93.1k
  m_entryMap.insert
1619
93.1k
  (std::multimap<std::string, MsWrdEntry>::value_type(fileEntry.type(), fileEntry));
1620
1621
93.1k
  long zoneEnd = pos+6+fSz;
1622
93.1k
  std::string name(""); // first equation, second "" or Equation Word?
1623
86.5M
  while (long(input->tell()) != zoneEnd) {
1624
86.4M
    auto c = static_cast<int>(input->readULong(1));
1625
86.4M
    if (c == 0) {
1626
36.0M
      if (name.length()) f << name << ",";
1627
36.0M
      name = "";
1628
36.0M
      continue;
1629
36.0M
    }
1630
50.4M
    name += char(c);
1631
50.4M
  }
1632
93.1k
  if (name.length()) f << name << ",";
1633
1634
93.1k
  pos = input->tell();
1635
  // Equation Word? : often contains not other data
1636
93.1k
  if (pos==endPos) {
1637
2.48k
    ascii().addPos(beginPos);
1638
2.48k
    ascii().addNote(f.str().c_str());
1639
2.48k
    return true;
1640
2.48k
  }
1641
1642
  // 0 or a small size c for annotation an equivalent of file type?
1643
90.6k
  fSz = static_cast<int>(input->readULong(1));
1644
90.6k
  if (pos+fSz+1 > endPos) {
1645
3.87k
    MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the second field zone\n"));
1646
3.87k
    f << "#fSz=" << fSz;
1647
3.87k
    ascii().addPos(beginPos);
1648
3.87k
    ascii().addNote(f.str().c_str());
1649
3.87k
    return false;
1650
3.87k
  }
1651
86.7k
  int val;
1652
86.7k
  bool isAnnotation=false;
1653
86.7k
  if (fSz==12) { // possible annotation
1654
887
    f << "type=[";
1655
4.43k
    for (int i = 0; i < 4; i++) { // f0=f1=f2=0, f3=0x100
1656
3.54k
      val = static_cast<int>(input->readLong(2));
1657
3.54k
      if (val) f << "g0=" << std::hex << val << std::dec << ",";
1658
3.54k
    }
1659
887
    std::string type("");
1660
4.43k
    for (int i = 0; i < 4; i++)
1661
3.54k
      type += char(input->readULong(1));
1662
887
    f << type << "],";
1663
887
    isAnnotation=type=="ANOT";
1664
887
  }
1665
85.8k
  else if (fSz) {
1666
22.2k
    f << "##data2[sz]=" << fSz << ",";
1667
22.2k
    ascii().addDelimiter(input->tell(),'|');
1668
22.2k
    input->seek(pos+fSz+1, librevenge::RVNG_SEEK_SET);
1669
22.2k
    ascii().addDelimiter(input->tell(),'|');
1670
22.2k
  }
1671
86.7k
  pos = input->tell();
1672
86.7k
  if (pos+2>endPos) {
1673
2.61k
    if (pos!= endPos)
1674
1.48k
      f << "###";
1675
2.61k
    ascii().addPos(beginPos);
1676
2.61k
    ascii().addNote(f.str().c_str());
1677
2.61k
    return true;
1678
2.61k
  }
1679
84.1k
  val = static_cast<int>(input->readLong(2));
1680
84.1k
  if (val) f << "#f0=" << val << ",";
1681
1682
84.1k
  pos = input->tell();
1683
84.1k
  if (pos+4>endPos) {
1684
2.80k
    if (pos!= endPos)
1685
2.14k
      f << "##";
1686
2.80k
    ascii().addPos(beginPos);
1687
2.80k
    ascii().addNote(f.str().c_str());
1688
2.80k
    return true;
1689
2.80k
  }
1690
81.3k
  auto dataSz = long(input->readULong(4));
1691
81.3k
  pos = input->tell();
1692
81.3k
  if (pos+dataSz > endPos) {
1693
27.8k
    MWAW_DEBUG_MSG(("MsWrdParser::readObject: pb reading the last field size zone\n"));
1694
27.8k
    f << "#fSz[last]=" << dataSz;
1695
27.8k
    ascii().addPos(beginPos);
1696
27.8k
    ascii().addNote(f.str().c_str());
1697
27.8k
    return false;
1698
27.8k
  }
1699
53.5k
  if (isAnnotation && dataSz>9) {
1700
0
    f << "annot=[";
1701
0
    for (int i = 0; i < 3; i++) { // h0=1|2, h1,h2: big numbers
1702
0
      val = static_cast<int>(input->readULong(2));
1703
0
      if (val)
1704
0
        f << "h" << i << "=" << std::hex << val << std::dec << ",";
1705
0
    }
1706
0
    fSz = static_cast<int>(input->readULong(1));
1707
0
    bool ok=true;
1708
0
    if (fSz+7 > dataSz) {
1709
0
      MWAW_DEBUG_MSG(("MsWrdParser::readObject: can not read the annotation string\n"));
1710
0
      f << "###";
1711
0
      ok = false;
1712
0
    }
1713
0
    else {
1714
0
      std::string annotation("");
1715
0
      for (int i = 0; i < fSz; i++)
1716
0
        annotation += char(input->readULong(1));
1717
0
      if (!annotation.empty())
1718
0
        f << "annot[inText]=" << annotation << ",";
1719
0
    }
1720
1721
0
    if (ok) {
1722
0
      val = static_cast<int>(input->readULong(1)); // always 0
1723
0
      if (val)
1724
0
        f << "h3=" << std::hex << val << std::dec << ",";
1725
0
      fSz = static_cast<int>(input->readULong(1));
1726
0
    }
1727
0
    if (!ok) {
1728
0
    }
1729
0
    else if (fSz+9 > dataSz) {
1730
0
      MWAW_DEBUG_MSG(("MsWrdParser::readObject: can not read the annotation comment\n"));
1731
0
      f << "###";
1732
0
    }
1733
0
    else {
1734
      // store the comment
1735
0
      obj.m_annotation.setBegin(input->tell());
1736
0
      obj.m_annotation.setLength(fSz);
1737
0
      std::string annotation("");
1738
0
      for (int i = 0; i < fSz; i++)
1739
0
        annotation += char(input->readULong(1));
1740
0
      if (!annotation.empty())
1741
0
        f << "annot[comment]=" << annotation << ",";
1742
0
    }
1743
0
  }
1744
53.5k
  else if (dataSz)
1745
44.8k
    ascii().addDelimiter(pos, '|');
1746
53.5k
  input->seek(pos+dataSz, librevenge::RVNG_SEEK_SET);
1747
1748
53.5k
  pos = input->tell();
1749
53.5k
  ascii().addPos(beginPos);
1750
53.5k
  ascii().addNote(f.str().c_str());
1751
53.5k
  if (pos != endPos)
1752
15.5k
    ascii().addDelimiter(pos, '#');
1753
1754
53.5k
  return true;
1755
81.3k
}
1756
1757
////////////////////////////////////////////////////////////
1758
// check if a zone is a picture/read a picture
1759
////////////////////////////////////////////////////////////
1760
bool MsWrdParser::checkPicturePos(long pos, int type)
1761
160k
{
1762
160k
  MWAWInputStreamPtr input = getInput();
1763
160k
  if (pos < 0x100 || !input->checkPosition(pos))
1764
69.4k
    return false;
1765
1766
91.0k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1767
91.0k
  auto sz = long(input->readULong(4));
1768
91.0k
  long endPos = pos+sz;
1769
91.0k
  if (sz < 14 || !input->checkPosition(sz+pos)) return false;
1770
59.6k
  auto num = static_cast<int>(input->readLong(1));
1771
59.6k
  if (num < 0 || num > 4) return false;
1772
54.3k
  input->seek(pos+14, librevenge::RVNG_SEEK_SET);
1773
94.0k
  for (int n = 0; n < num; n++) {
1774
43.7k
    long actPos = input->tell();
1775
43.7k
    auto pSz = long(input->readULong(4));
1776
43.7k
    if (pSz+actPos > endPos) return false;
1777
39.6k
    input->seek(pSz+actPos, librevenge::RVNG_SEEK_SET);
1778
39.6k
  }
1779
50.2k
  if (input->tell() != endPos)
1780
7.27k
    return false;
1781
1782
42.9k
  static int id = 0;
1783
42.9k
  MsWrdEntry entry;
1784
42.9k
  entry.setBegin(pos);
1785
42.9k
  entry.setEnd(endPos);
1786
42.9k
  entry.setType("Picture");
1787
42.9k
  entry.setPictType(type);
1788
42.9k
  entry.setId(id++);
1789
42.9k
  m_entryMap.insert
1790
42.9k
  (std::multimap<std::string, MsWrdEntry>::value_type(entry.type(), entry));
1791
1792
42.9k
  return true;
1793
50.2k
}
1794
1795
bool MsWrdParser::readPicture(MsWrdEntry &entry)
1796
42.9k
{
1797
42.9k
  if (m_state->m_picturesMap.find(entry.begin())!=m_state->m_picturesMap.end())
1798
5.11k
    return true;
1799
37.8k
  if (entry.length() < 30 && entry.length() != 14) {
1800
0
    MWAW_DEBUG_MSG(("MsWrdParser::readPicture: the zone seems too short\n"));
1801
0
    return false;
1802
0
  }
1803
37.8k
  MWAWInputStreamPtr input = getInput();
1804
37.8k
  long pos = entry.begin();
1805
37.8k
  entry.setParsed(true);
1806
37.8k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1807
37.8k
  libmwaw::DebugStream f;
1808
37.8k
  f << "Entries(Picture)[" << entry.pictType() << "-" << entry.id() << "]:";
1809
37.8k
  auto sz = long(input->readULong(4));
1810
37.8k
  if (sz > entry.length()) {
1811
0
    MWAW_DEBUG_MSG(("MsWrdParser::readPicture: the zone size seems too big\n"));
1812
0
    return false;
1813
0
  }
1814
37.8k
  auto N = static_cast<int>(input->readULong(1));
1815
37.8k
  f << "N=" << N << ",";
1816
37.8k
  MsWrdParserInternal::Picture pict;
1817
37.8k
  pict.m_flag = static_cast<int>(input->readULong(1)); // find 0 or 0x80
1818
37.8k
  int dim[4];
1819
151k
  for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1820
37.8k
  pict.m_dim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1821
37.8k
  f << pict;
1822
37.8k
  ascii().addPos(pos);
1823
37.8k
  ascii().addNote(f.str().c_str());
1824
1825
72.8k
  for (int n=0; n < N; n++) {
1826
37.4k
    MsWrdParserInternal::Picture::Zone zone;
1827
37.4k
    pos = input->tell();
1828
37.4k
    f.str("");
1829
37.4k
    f << "Picture-" << n << "[" << entry.pictType() << "-" << entry.id() << "]:";
1830
37.4k
    sz = long(input->readULong(4));
1831
37.4k
    if (sz < 16 || sz+pos > entry.end()) {
1832
2.48k
      MWAW_DEBUG_MSG(("MsWrdParser::readPicture: pb with the picture size\n"));
1833
2.48k
      f << "#";
1834
2.48k
      ascii().addPos(pos);
1835
2.48k
      ascii().addNote(f.str().c_str());
1836
2.48k
      return false;
1837
2.48k
    }
1838
139k
    for (int i = 0; i < 3; ++i) zone.m_flags[i] = static_cast<int>(input->readULong((i==2) ? 2 : 1));
1839
139k
    for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1840
34.9k
    zone.m_dim=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
1841
34.9k
    zone.m_pos.setBegin(pos+16);
1842
34.9k
    zone.m_pos.setLength(sz-16);
1843
34.9k
    f << zone;
1844
34.9k
    ascii().addPos(pos);
1845
34.9k
    ascii().addNote(f.str().c_str());
1846
34.9k
    if (sz <= 16)
1847
0
      continue;
1848
34.9k
    pict.m_picturesList.push_back(zone);
1849
#ifdef DEBUG_WITH_FILES
1850
    ascii().skipZone(pos+16, pos+sz-1);
1851
    librevenge::RVNGBinaryData file;
1852
    input->seek(pos+16, librevenge::RVNG_SEEK_SET);
1853
    input->readDataBlock(sz-16, file);
1854
    static int volatile pictName = 0;
1855
    libmwaw::DebugStream f2;
1856
    f2 << "PICT-" << ++pictName << ".pct";
1857
    libmwaw::Debug::dumpFile(file, f2.str().c_str());
1858
#endif
1859
1860
34.9k
    input->seek(pos+sz, librevenge::RVNG_SEEK_SET);
1861
34.9k
  }
1862
35.3k
  m_state->m_picturesMap[entry.begin()]=pict;
1863
35.3k
  pos = input->tell();
1864
35.3k
  if (pos != entry.end())
1865
0
    ascii().addDelimiter(pos, '|');
1866
35.3k
  ascii().addPos(entry.end());
1867
35.3k
  ascii().addNote("_");
1868
35.3k
  return true;
1869
37.8k
}
1870
1871
void MsWrdParser::sendPicture(long fPos, int cPos, MWAWPosition::AnchorTo anchor)
1872
54.7k
{
1873
54.7k
  if (!getTextListener()) {
1874
0
    MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: listener is not set\n"));
1875
0
    return;
1876
0
  }
1877
54.7k
  if ((anchor == MWAWPosition::Char || anchor == MWAWPosition::CharBaseLine) &&
1878
42.3k
      m_state->m_posToCommentMap.find(long(cPos-1))!=m_state->m_posToCommentMap.end()) {
1879
0
    MWAWInputStreamPtr input = getInput();
1880
0
    std::shared_ptr<MWAWSubDocument> subdoc=std::make_shared<MsWrdParserInternal::SubDocument>(*this, input, m_state->m_posToCommentMap.find(long(cPos-1))->second, libmwaw::DOC_COMMENT_ANNOTATION);
1881
0
    getTextListener()->insertComment(subdoc);
1882
0
    return;
1883
0
  }
1884
54.7k
  if (m_state->m_picturesMap.find(fPos)==m_state->m_picturesMap.end()) {
1885
0
    MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: can not find picture for pos %lx\n", static_cast<long unsigned int>(fPos)));
1886
0
    return;
1887
0
  }
1888
54.7k
  auto const &pict= m_state->m_picturesMap.find(fPos)->second;
1889
54.7k
  MWAWInputStreamPtr input = getInput();
1890
54.7k
  if (pict.m_picturesList.size()!=1 &&
1891
24.6k
      (anchor == MWAWPosition::Char || anchor == MWAWPosition::CharBaseLine)) {
1892
12.3k
    std::shared_ptr<MsWrdParserInternal::SubDocument> subdoc
1893
12.3k
    (new MsWrdParserInternal::SubDocument(*this, input, fPos, cPos));
1894
12.3k
    MWAWPosition pictPos(MWAWVec2f(pict.m_dim.min()), MWAWVec2f(pict.m_dim.size()), librevenge::RVNG_POINT);
1895
12.3k
    pictPos.setRelativePosition(MWAWPosition::Char,
1896
12.3k
                                MWAWPosition::XLeft, MWAWPosition::YTop);
1897
12.3k
    pictPos.m_wrapping =  MWAWPosition::WBackground;
1898
12.3k
    getTextListener()->insertTextBox(pictPos, subdoc);
1899
12.3k
    return;
1900
12.3k
  }
1901
42.3k
  MWAWPosition basicPos(MWAWVec2f(0.,0.), MWAWVec2f(100.,100.), librevenge::RVNG_POINT);
1902
42.3k
  if (anchor != MWAWPosition::Page && anchor != MWAWPosition::Frame) {
1903
30.0k
    basicPos.setRelativePosition(anchor, MWAWPosition::XLeft, MWAWPosition::YCenter);
1904
30.0k
    basicPos.m_wrapping =  MWAWPosition::WBackground;
1905
30.0k
  }
1906
12.3k
  else
1907
12.3k
    basicPos.setRelativePosition(anchor);
1908
1909
42.3k
  long actPos = input->tell();
1910
42.3k
  MWAWBox2f naturalBox;
1911
42.3k
  int n=0;
1912
42.3k
  for (auto const &zone : pict.m_picturesList) {
1913
30.0k
    n++;
1914
30.0k
    if (!zone.m_pos.valid()) continue;
1915
30.0k
    MWAWPosition pos(basicPos);
1916
30.0k
    pos.setOrigin(pos.origin()+MWAWVec2f(zone.m_dim.min()));
1917
30.0k
    pos.setSize(MWAWVec2f(zone.m_dim.size()));
1918
1919
30.0k
    input->seek(zone.m_pos.begin(), librevenge::RVNG_SEEK_SET);
1920
30.0k
    MWAWPict::ReadResult res = MWAWPictData::check(input, static_cast<int>(zone.m_pos.length()), naturalBox);
1921
30.0k
    if (res == MWAWPict::MWAW_R_BAD) {
1922
7
      MWAW_DEBUG_MSG(("MsWrdParser::sendPicture: can not find the picture %d\n", int(n-1)));
1923
7
      continue;
1924
7
    }
1925
1926
30.0k
    input->seek(zone.m_pos.begin(), librevenge::RVNG_SEEK_SET);
1927
30.0k
    std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(input, static_cast<int>(zone.m_pos.length())));
1928
30.0k
    if (!thePict) continue;
1929
30.0k
    MWAWEmbeddedObject picture;
1930
30.0k
    if (thePict->getBinary(picture))
1931
30.0k
      getTextListener()->insertPicture(pos, picture);
1932
30.0k
  }
1933
42.3k
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
1934
42.3k
}
1935
1936
////////////////////////////////////////////////////////////
1937
// read the print info
1938
////////////////////////////////////////////////////////////
1939
bool MsWrdParser::readPrintInfo(MsWrdEntry &entry)
1940
6.91k
{
1941
6.91k
  if (entry.length() < 0x78) {
1942
3.21k
    MWAW_DEBUG_MSG(("MsWrdParser::readPrintInfo: the zone seems to short\n"));
1943
3.21k
    return false;
1944
3.21k
  }
1945
3.70k
  MWAWInputStreamPtr input = getInput();
1946
3.70k
  long pos = entry.begin();
1947
3.70k
  entry.setParsed(true);
1948
3.70k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1949
3.70k
  libmwaw::DebugStream f;
1950
  // print info
1951
3.70k
  libmwaw::PrinterInfo info;
1952
3.70k
  if (!info.read(input)) return false;
1953
1.83k
  f << "PrintInfo:"<< info;
1954
1955
1.83k
  MWAWVec2i paperSize = info.paper().size();
1956
1.83k
  MWAWVec2i pageSize = info.page().size();
1957
1.83k
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1958
1.70k
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
1959
1960
  // define margin from print info
1961
1.64k
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1962
1.64k
  MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
1963
1964
  // move margin left | top
1965
1.64k
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1966
1.64k
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1967
1.64k
  lTopMargin -= MWAWVec2i(decalX, decalY);
1968
1.64k
  rBotMargin += MWAWVec2i(decalX, decalY);
1969
1970
1.64k
  int leftMargin = lTopMargin.x();
1971
1.64k
  int topMargin = lTopMargin.y();
1972
1973
  // decrease right | bottom
1974
1.64k
  int rightMarg = rBotMargin.x() -50;
1975
1.64k
  if (rightMarg < 0) {
1976
1.48k
    leftMargin -= (-rightMarg);
1977
1.48k
    if (leftMargin < 0) leftMargin=0;
1978
1.48k
    rightMarg=0;
1979
1.48k
  }
1980
1.64k
  int botMarg = rBotMargin.y() -50;
1981
1.64k
  if (botMarg < 0) {
1982
298
    topMargin -= (-botMarg);
1983
298
    if (topMargin < 0) topMargin=0;
1984
298
    botMarg=0;
1985
298
  }
1986
1987
1.64k
  getPageSpan().setFormOrientation(MWAWPageSpan::PORTRAIT);
1988
1.64k
  getPageSpan().setMarginTop(topMargin/72.0);
1989
1.64k
  getPageSpan().setMarginBottom(botMarg/72.0);
1990
1.64k
  getPageSpan().setMarginLeft(leftMargin/72.0);
1991
1.64k
  getPageSpan().setMarginRight(rightMarg/72.0);
1992
1.64k
  getPageSpan().setFormLength(paperSize.y()/72.);
1993
1.64k
  getPageSpan().setFormWidth(paperSize.x()/72.);
1994
1995
1.64k
  ascii().addPos(pos);
1996
1.64k
  ascii().addNote(f.str().c_str());
1997
1998
1.64k
  if (long(input->tell()) != entry.end())
1999
285
    ascii().addDelimiter(input->tell(), '|');
2000
2001
1.64k
  ascii().addPos(entry.end());
2002
1.64k
  ascii().addNote("_");
2003
2004
1.64k
  return true;
2005
1.83k
}
2006
2007
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: