Coverage Report

Created: 2026-03-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MacWrtParser.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
/* Inspired of TN-012-Disk-Based-MW-Format.txt */
35
36
#include <iomanip>
37
#include <iostream>
38
#include <limits>
39
#include <sstream>
40
41
#include <librevenge/librevenge.h>
42
43
#include "MWAWTextListener.hxx"
44
#include "MWAWFont.hxx"
45
#include "MWAWFontConverter.hxx"
46
#include "MWAWHeader.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPictMac.hxx"
49
#include "MWAWPosition.hxx"
50
#include "MWAWPrinter.hxx"
51
#include "MWAWRSRCParser.hxx"
52
#include "MWAWSubDocument.hxx"
53
54
#include "MacWrtParser.hxx"
55
56
/** Internal: the structures of a MacWrtParser */
57
namespace MacWrtParserInternal
58
{
59
60
//! Document header
61
struct FileHeader {
62
  FileHeader()
63
153k
    : m_hideFirstPageHeaderFooter(false)
64
153k
    , m_startNumberPage(1)
65
153k
    , m_freeListPos(0)
66
153k
    , m_freeListLength(0)
67
153k
    , m_freeListAllocated(0)
68
153k
    , m_dataPos(0)
69
153k
  {
70
461k
    for (auto &num : m_numParagraphs) num = 0;
71
153k
  }
72
73
  friend std::ostream &operator<<(std::ostream &o, FileHeader const &header);
74
75
  //! the number of lines : text, header footer
76
  int m_numParagraphs[3];
77
  //! true if the first page header/footer must be draw
78
  bool m_hideFirstPageHeaderFooter;
79
  //! the first number page
80
  int m_startNumberPage;
81
  //! free list start position
82
  long m_freeListPos;
83
  //! free list length
84
  long m_freeListLength;
85
  //! free list allocated
86
  long m_freeListAllocated;
87
  //! the begin of data ( if version == 3)
88
  long m_dataPos;
89
};
90
91
std::ostream &operator<<(std::ostream &o, FileHeader const &header)
92
0
{
93
0
  for (int i=0; i < 3; i++) {
94
0
    if (!header.m_numParagraphs[i]) continue;
95
0
    o << "numParagraph";
96
0
    if (i==1) o << "[header]";
97
0
    else if (i==2) o << "[footer]";
98
0
    o << "=" << header.m_numParagraphs[i] << ",";
99
0
  }
100
0
  if (header.m_hideFirstPageHeaderFooter)
101
0
    o << "noHeaderFooter[FirstPage],";
102
0
  if (header.m_startNumberPage != 1)
103
0
    o << "firstPageNumber=" << header.m_startNumberPage << ",";
104
0
  if (header.m_freeListPos) {
105
0
    o << "FreeList=" << std::hex
106
0
      << header.m_freeListPos
107
0
      << "[" << header.m_freeListLength << "+" << header.m_freeListAllocated << "],"
108
0
      << std::dec << ",";
109
0
  }
110
0
  if (header.m_dataPos)
111
0
    o << "DataPos="  << std::hex << header.m_dataPos << std::dec << ",";
112
113
0
  return o;
114
0
}
115
116
////////////////////////////////////////
117
//! the paragraph... information
118
struct Information {
119
  /** the different type */
120
  enum Type { TEXT, RULER, GRAPHIC, PAGEBREAK, UNKNOWN };
121
122
  //! constructor
123
  Information()
124
30.2M
    : m_type(UNKNOWN)
125
30.2M
    , m_compressed(false)
126
30.2M
    , m_pos()
127
30.2M
    , m_height(0)
128
30.2M
    , m_justify(MWAWParagraph::JustificationLeft)
129
30.2M
    , m_justifySet(false)
130
30.2M
    , m_data()
131
30.2M
    , m_font()
132
30.2M
  {
133
30.2M
  }
134
135
  //! operator<<
136
  friend std::ostream &operator<<(std::ostream &o, Information const &info);
137
138
  //! the type
139
  Type m_type;
140
141
  //! a flag to know if the text data are compressed
142
  bool m_compressed;
143
144
  //! top left position
145
  MWAWPosition m_pos;
146
147
  //! the paragraph height
148
  int m_height;
149
150
  //! paragraph justification : MWAW_PARAGRAPH_JUSTIFICATION*
151
  MWAWParagraph::Justification m_justify;
152
153
  //! true if the justification must be used
154
  bool m_justifySet;
155
  //! the position in the file
156
  MWAWEntry m_data;
157
158
  //! the font
159
  MWAWFont m_font;
160
};
161
162
std::ostream &operator<<(std::ostream &o, Information const &info)
163
0
{
164
0
  switch (info.m_type) {
165
0
  case Information::TEXT:
166
0
    o << "text";
167
0
    if (info.m_compressed) o << "[compressed]";
168
0
    o << ",";
169
0
    break;
170
0
  case Information::RULER:
171
0
    o << "indent,";
172
0
    break;
173
0
  case Information::GRAPHIC:
174
0
    o << "graphics,";
175
0
    break;
176
0
  case Information::PAGEBREAK:
177
0
    o << "pageBreak,";
178
0
    break;
179
0
  case Information::UNKNOWN:
180
#if !defined(__clang__)
181
  default:
182
#endif
183
0
    o << "###unknownType,";
184
0
    break;
185
0
  }
186
0
  o << info.m_pos << ",";
187
0
  if (info.m_height) o << "height=" << info.m_height << ",";
188
189
0
  if (info.m_justifySet) {
190
0
    switch (info.m_justify) {
191
0
    case MWAWParagraph::JustificationLeft:
192
0
      o << "left[justify],";
193
0
      break;
194
0
    case MWAWParagraph::JustificationCenter:
195
0
      o << "center[justify],";
196
0
      break;
197
0
    case MWAWParagraph::JustificationRight:
198
0
      o << "right[justify],";
199
0
      break;
200
0
    case MWAWParagraph::JustificationFull:
201
0
      o << "full[justify],";
202
0
      break;
203
0
    case MWAWParagraph::JustificationFullAllLines:
204
0
      o << "fullAllLines[justify],";
205
0
      break;
206
#if !defined(__clang__)
207
    default:
208
      o << "###unknown[justify],";
209
      break;
210
#endif
211
0
    }
212
0
  }
213
0
  if (info.m_data.begin() > 0)
214
0
    o << std::hex << "data=[" << info.m_data.begin() << "-" << info.m_data.end() << "]," << std::dec;
215
0
  return o;
216
0
}
217
218
////////////////////////////////////////
219
//! the windows structure
220
struct WindowsInfo {
221
  WindowsInfo()
222
470k
    : m_startSel()
223
470k
    , m_endSel()
224
470k
    , m_posTopY(0)
225
470k
    , m_informations()
226
470k
    , m_firstParagLine()
227
470k
    , m_linesHeight()
228
470k
    , m_pageNumber()
229
470k
    , m_date()
230
470k
    , m_time()
231
470k
  {
232
470k
  }
233
234
  /** small function used to recognized empty header or footer */
235
  bool isEmpty() const
236
29.8k
  {
237
29.8k
    if (m_informations.size() == 0) return true;
238
13.6k
    if (m_pageNumber.x() >= 0 || m_date.x() >= 0 || m_time.x() >= 0)
239
11.1k
      return false;
240
2.50k
    if (m_informations.size() > 2) return false;
241
2.94k
    for (auto const &info : m_informations) {
242
2.94k
      switch (info.m_type) {
243
272
      case Information::GRAPHIC:
244
272
        return false;
245
1.27k
      case Information::TEXT:
246
1.27k
        if (info.m_data.length() != 10)
247
834
          return false;
248
        // empty line : ok
249
445
        break;
250
1.37k
      case Information::RULER:
251
1.39k
      case Information::PAGEBREAK:
252
1.39k
      case Information::UNKNOWN:
253
#if !defined(__clang__)
254
      default:
255
#endif
256
1.39k
        break;
257
2.94k
      }
258
2.94k
    }
259
890
    return true;
260
1.99k
  }
261
262
  friend std::ostream &operator<<(std::ostream &o, WindowsInfo const &w);
263
264
  MWAWVec2i m_startSel, m_endSel; // start end selection (parag, char)
265
  int m_posTopY;
266
  std::vector<Information> m_informations;
267
  std::vector<int> m_firstParagLine, m_linesHeight;
268
  MWAWVec2i m_pageNumber, m_date, m_time;
269
};
270
271
std::ostream &operator<<(std::ostream &o, WindowsInfo const &w)
272
0
{
273
0
  o << "sel=[" << w.m_startSel << "-" << w.m_endSel << "],";
274
0
  if (w.m_posTopY) o << "windowsY=" << w.m_posTopY << ",";
275
0
  o << "pageNumberPos=" << w.m_pageNumber << ",";
276
0
  o << "datePos=" << w.m_date << ",";
277
0
  o << "timePos=" << w.m_time << ",";
278
0
  return o;
279
0
}
280
281
////////////////////////////////////////
282
//! Internal: the state of a MacWrtParser
283
struct State {
284
  //! constructor
285
  State()
286
153k
    : m_compressCorr(" etnroaisdlhcfp")
287
153k
    , m_actPage(0)
288
153k
    , m_numPages(0)
289
153k
    , m_fileHeader()
290
153k
    , m_headerHeight(0)
291
153k
    , m_footerHeight(0)
292
153k
  {
293
153k
  }
294
295
  //! the correspondance between int compressed and char : must be 15 character
296
  std::string m_compressCorr;
297
298
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
299
300
  //! the header
301
  FileHeader m_fileHeader;
302
303
  //! the information of main document, header, footer
304
  WindowsInfo m_windows[3];
305
306
  int m_headerHeight /** the header height if known */,
307
      m_footerHeight /** the footer height if known */;
308
};
309
310
////////////////////////////////////////
311
//! Internal: the subdocument of a MacWrtParser
312
class SubDocument final : public MWAWSubDocument
313
{
314
public:
315
  SubDocument(MacWrtParser &pars, MWAWInputStreamPtr const &input, int zoneId)
316
7.56k
    : MWAWSubDocument(&pars, input, MWAWEntry())
317
7.56k
    , m_id(zoneId)
318
7.56k
  {
319
7.56k
  }
320
321
  //! destructor
322
0
  ~SubDocument() final {}
323
324
  //! operator!=
325
  bool operator!=(MWAWSubDocument const &doc) const final;
326
327
  //! the parser function
328
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
329
330
protected:
331
  //! the subdocument id
332
  int m_id;
333
};
334
335
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
336
7.55k
{
337
7.55k
  if (!listener.get()) {
338
0
    MWAW_DEBUG_MSG(("MacWrtParserInternal::SubDocument::parse: no listener\n"));
339
0
    return;
340
0
  }
341
7.55k
  if (m_id != 1 && m_id != 2) {
342
0
    MWAW_DEBUG_MSG(("MacWrtParserInternal::SubDocument::parse: unknown zone\n"));
343
0
    return;
344
0
  }
345
7.55k
  auto *parser=dynamic_cast<MacWrtParser *>(m_parser);
346
7.55k
  if (!parser) {
347
0
    MWAW_DEBUG_MSG(("MacWrtParserInternal::SubDocument::parse: no parser\n"));
348
0
    return;
349
0
  }
350
351
7.55k
  long pos = m_input->tell();
352
7.55k
  parser->sendWindow(m_id);
353
7.55k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
354
7.55k
}
355
356
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
357
0
{
358
0
  if (MWAWSubDocument::operator!=(doc)) return true;
359
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
360
0
  if (!sDoc) return true;
361
0
  if (m_id != sDoc->m_id) return true;
362
0
  return false;
363
0
}
364
}
365
366
////////////////////////////////////////////////////////////
367
// constructor/destructor, ...
368
////////////////////////////////////////////////////////////
369
MacWrtParser::MacWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
370
71.2k
  : MWAWTextParser(input, rsrcParser, header)
371
71.2k
  , m_state()
372
71.2k
{
373
71.2k
  init();
374
71.2k
}
375
376
MacWrtParser::~MacWrtParser()
377
71.2k
{
378
71.2k
}
379
380
void MacWrtParser::init()
381
71.2k
{
382
71.2k
  resetTextListener();
383
71.2k
  setAsciiName("main-1");
384
385
71.2k
  m_state.reset(new MacWrtParserInternal::State);
386
387
  // reduce the margin (in case, the page is not defined)
388
71.2k
  getPageSpan().setMargins(0.1);
389
71.2k
}
390
391
////////////////////////////////////////////////////////////
392
// new page
393
////////////////////////////////////////////////////////////
394
void MacWrtParser::newPage(int number)
395
1.21M
{
396
1.21M
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
397
1.18M
    return;
398
399
1.43M
  while (m_state->m_actPage < number) {
400
1.41M
    m_state->m_actPage++;
401
1.41M
    if (!getTextListener() || m_state->m_actPage == 1)
402
7.18k
      continue;
403
1.40M
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
404
1.40M
  }
405
24.3k
}
406
407
////////////////////////////////////////////////////////////
408
// the parser
409
////////////////////////////////////////////////////////////
410
void MacWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
411
11.3k
{
412
11.3k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
413
11.3k
  bool ok = true;
414
11.3k
  try {
415
    // create the asciiFile
416
11.3k
    ascii().setStream(getInput());
417
11.3k
    ascii().open(asciiName());
418
11.3k
    checkHeader(nullptr);
419
11.3k
    if (getRSRCParser()) {
420
203
      MWAWEntry corrEntry = getRSRCParser()->getEntry("STR ", 700);
421
203
      std::string corrString("");
422
203
      if (corrEntry.valid() && getRSRCParser()->parseSTR(corrEntry, corrString)) {
423
0
        if (corrString.length() != 15) {
424
0
          MWAW_DEBUG_MSG(("MacWrtParser::parse: resource correspondance string seems bad\n"));
425
0
        }
426
0
        else
427
0
          m_state->m_compressCorr = corrString;
428
0
      }
429
203
    }
430
11.3k
    ok = (version() <= 3) ? createZonesV3() : createZones();
431
11.3k
    if (ok) {
432
8.55k
      createDocument(docInterface);
433
8.55k
      sendWindow(0);
434
8.55k
    }
435
436
11.3k
    ascii().reset();
437
11.3k
  }
438
11.3k
  catch (...) {
439
0
    MWAW_DEBUG_MSG(("MacWrtParser::parse: exception catched when parsing\n"));
440
0
    ok = false;
441
0
  }
442
443
11.3k
  resetTextListener();
444
11.3k
  if (!ok) throw(libmwaw::ParseException());
445
11.3k
}
446
447
////////////////////////////////////////////////////////////
448
// create the document
449
////////////////////////////////////////////////////////////
450
void MacWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
451
8.55k
{
452
8.55k
  if (!documentInterface) return;
453
8.55k
  if (getTextListener()) {
454
0
    MWAW_DEBUG_MSG(("MacWrtParser::createDocument: listener already exist\n"));
455
0
    return;
456
0
  }
457
458
  // update the page
459
8.55k
  m_state->m_actPage = 0;
460
461
  // create the page list
462
8.55k
  MWAWPageSpan ps(getPageSpan());
463
25.6k
  for (int i = 1; i < 3; i++) {
464
17.1k
    if (m_state->m_windows[i].isEmpty()) {
465
#ifdef DEBUG
466
      sendWindow(i); // force the parsing
467
#endif
468
9.54k
      continue;
469
9.54k
    }
470
7.56k
    MWAWHeaderFooter hF((i==1) ? MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
471
7.56k
    hF.m_subDocument.reset(new MacWrtParserInternal::SubDocument(*this, getInput(), i));
472
7.56k
    ps.setHeaderFooter(hF);
473
7.56k
  }
474
475
8.55k
  std::vector<MWAWPageSpan> pageList;
476
8.55k
  if (m_state->m_fileHeader.m_hideFirstPageHeaderFooter) {
477
220
    pageList.push_back(getPageSpan());
478
220
    ps.setPageSpan(m_state->m_numPages);
479
220
  }
480
8.33k
  else
481
8.33k
    ps.setPageSpan(m_state->m_numPages+1);
482
8.55k
  if (ps.getPageSpan())
483
8.55k
    pageList.push_back(ps);
484
  //
485
8.55k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
486
8.55k
  setTextListener(listen);
487
8.55k
  listen->startDocument();
488
8.55k
}
489
490
491
////////////////////////////////////////////////////////////
492
//
493
// Intermediate level
494
//
495
////////////////////////////////////////////////////////////
496
bool MacWrtParser::createZones()
497
7.15k
{
498
7.15k
  MWAWInputStreamPtr input = getInput();
499
7.15k
  long pos = input->tell();
500
501
7.15k
  if (!readPrintInfo()) {
502
    // bad sign, but we can try to recover
503
5.12k
    ascii().addPos(pos);
504
5.12k
    ascii().addNote("###PrintInfo");
505
5.12k
    input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
506
5.12k
  }
507
508
7.15k
  pos = input->tell();
509
27.8k
  for (int i = 0; i < 3; i++) {
510
21.4k
    if (readWindowsInfo(i))
511
12.1k
      continue;
512
9.27k
    if (i == 2) return false; // problem on the main zone, better quit
513
514
    // reset state
515
8.48k
    m_state->m_windows[2-i] = MacWrtParserInternal::WindowsInfo();
516
8.48k
    int const windowsSize = 46;
517
518
    // and try to continue
519
8.48k
    input->seek(pos+(i+1)*windowsSize, librevenge::RVNG_SEEK_SET);
520
8.48k
  }
521
522
#ifdef DEBUG
523
  checkFreeList();
524
#endif
525
526
  // ok, we can find calculate the number of pages and the header and the footer height
527
19.0k
  for (int i = 1; i < 3; i++) {
528
12.7k
    auto const &info = m_state->m_windows[i];
529
12.7k
    if (info.isEmpty()) // avoid reserving space for empty header/footer
530
7.51k
      continue;
531
5.19k
    int height = 0;
532
5.19k
    for (auto const &inf : info.m_informations)
533
1.63M
      height+=inf.m_height;
534
5.19k
    if (i == 1) m_state->m_headerHeight = height;
535
2.11k
    else m_state->m_footerHeight = height;
536
5.19k
  }
537
6.35k
  int numPages = 0;
538
6.35k
  auto const &mainInfo = m_state->m_windows[0];
539
1.06M
  for (auto &info : mainInfo.m_informations) {
540
1.06M
    if (info.m_pos.page() > numPages)
541
18.7k
      numPages = info.m_pos.page();
542
1.06M
  }
543
6.35k
  m_state->m_numPages = numPages+1;
544
545
6.35k
  return true;
546
7.15k
}
547
548
bool MacWrtParser::createZonesV3()
549
4.24k
{
550
4.24k
  MWAWInputStreamPtr input = getInput();
551
4.24k
  long pos = input->tell();
552
553
4.24k
  if (!readPrintInfo()) {
554
    // bad sign, but we can try to recover
555
3.25k
    ascii().addPos(pos);
556
3.25k
    ascii().addNote("###PrintInfo");
557
3.25k
    input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
558
3.25k
  }
559
560
4.24k
  pos = input->tell();
561
16.4k
  for (int i = 0; i < 3; i++) {
562
12.7k
    if (readWindowsInfo(i))
563
11.4k
      continue;
564
1.30k
    if (i == 2) return false; // problem on the main zone, better quit
565
566
    // reset state
567
810
    m_state->m_windows[2-i] = MacWrtParserInternal::WindowsInfo();
568
810
    int const windowsSize = 34;
569
570
    // and try to continue
571
810
    input->seek(pos+(i+1)*windowsSize, librevenge::RVNG_SEEK_SET);
572
810
  }
573
574
3.75k
  auto const &header = m_state->m_fileHeader;
575
576
15.0k
  for (int i = 0; i < 3; i++) {
577
11.2k
    if (!readInformationsV3
578
11.2k
        (header.m_numParagraphs[i], m_state->m_windows[i].m_informations))
579
0
      return false;
580
11.2k
  }
581
3.75k
  if (int(input->tell()) != header.m_dataPos) {
582
3.67k
    MWAW_DEBUG_MSG(("MacWrtParser::createZonesV3: pb with dataPos\n"));
583
3.67k
    ascii().addPos(input->tell());
584
3.67k
    ascii().addNote("###FileHeader");
585
586
    // posibility to do very bad thing from here, so we stop
587
3.67k
    if (int(input->tell()) > header.m_dataPos)
588
1.40k
      return false;
589
590
    // and try to continue
591
2.27k
    input->seek(header.m_dataPos, librevenge::RVNG_SEEK_SET);
592
2.27k
    if (int(input->tell()) != header.m_dataPos)
593
0
      return false;
594
2.27k
  }
595
5.77k
  for (int z = 0; z < 3; z++) {
596
4.94k
    int numParag = header.m_numParagraphs[z];
597
4.94k
    auto &wInfo = m_state->m_windows[z];
598
69.7k
    for (int p = 0; p < numParag; p++) {
599
66.3k
      pos = input->tell();
600
66.3k
      auto type = static_cast<int>(input->readLong(2));
601
66.3k
      auto sz = static_cast<int>(input->readLong(2));
602
66.3k
      input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
603
66.3k
      if (sz < 0 || long(input->tell()) !=  pos+4+sz) {
604
1.52k
        MWAW_DEBUG_MSG(("MacWrtParser::createZonesV3: pb with dataZone\n"));
605
1.52k
        return (p != 0);
606
1.52k
      }
607
64.7k
      MWAWEntry entry;
608
64.7k
      entry.setBegin(pos+4);
609
64.7k
      entry.setLength(sz);
610
64.7k
      if (int(wInfo.m_informations.size()) <= p)
611
0
        continue;
612
64.7k
      wInfo.m_informations[size_t(p)].m_data = entry;
613
64.7k
      auto newType = MacWrtParserInternal::Information::UNKNOWN;
614
615
64.7k
      switch ((type & 0x7)) {
616
54.6k
      case 0:
617
54.6k
        newType=MacWrtParserInternal::Information::RULER;
618
54.6k
        break;
619
2.88k
      case 1:
620
2.88k
        newType=MacWrtParserInternal::Information::TEXT;
621
2.88k
        break;
622
2.40k
      case 2:
623
2.40k
        newType=MacWrtParserInternal::Information::PAGEBREAK;
624
2.40k
        break;
625
4.83k
      default:
626
4.83k
        break;
627
64.7k
      }
628
64.7k
      if (newType != wInfo.m_informations[size_t(p)].m_type) {
629
31.4k
        MWAW_DEBUG_MSG(("MacWrtParser::createZonesV3: types are inconstant\n"));
630
31.4k
        if (newType != MacWrtParserInternal::Information::UNKNOWN)
631
26.6k
          wInfo.m_informations[size_t(p)].m_type = newType;
632
31.4k
      }
633
64.7k
    }
634
4.94k
  }
635
824
  if (!input->isEnd()) {
636
760
    ascii().addPos(input->tell());
637
760
    ascii().addNote("Entries(END)");
638
760
  }
639
640
824
  int numPages = 0;
641
824
  auto const &mainInfo = m_state->m_windows[0];
642
18.2k
  for (auto const &info : mainInfo.m_informations) {
643
18.2k
    if (info.m_pos.page() > numPages)
644
769
      numPages = info.m_pos.page();
645
18.2k
  }
646
824
  m_state->m_numPages = numPages+1;
647
824
  return true;
648
2.35k
}
649
650
bool MacWrtParser::sendWindow(int zone)
651
16.1k
{
652
16.1k
  if (zone < 0 || zone >= 3) {
653
0
    MWAW_DEBUG_MSG(("MacWrtParser::sendWindow: invalid zone %d\n", zone));
654
0
    return false;
655
0
  }
656
657
16.1k
  auto const &info = m_state->m_windows[zone];
658
16.1k
  size_t numInfo = info.m_informations.size();
659
16.1k
  auto numPara = int(info.m_firstParagLine.size());
660
661
16.1k
  if (version() <= 3 && zone == 0)
662
2.19k
    newPage(1);
663
2.94M
  for (size_t i=0; i < numInfo; i++) {
664
2.93M
    if (zone == 0)
665
1.18M
      newPage(info.m_informations[i].m_pos.page()+1);
666
2.93M
    switch (info.m_informations[i].m_type) {
667
1.52M
    case MacWrtParserInternal::Information::TEXT:
668
1.52M
      if (!zone || info.m_informations[i].m_data.length() != 10) {
669
1.52M
        std::vector<int> lineHeight;
670
1.52M
        if (int(i) < numPara) {
671
8.04k
          int firstLine = info.m_firstParagLine[i];
672
8.04k
          int lastLine = (int(i+1) < numPara) ?  info.m_firstParagLine[i+1] : int(info.m_linesHeight.size());
673
89.7k
          for (int line = firstLine; line < lastLine; line++)
674
81.7k
            lineHeight.push_back(info.m_linesHeight[size_t(line)]);
675
8.04k
        }
676
1.52M
        readText(info.m_informations[i], lineHeight);
677
1.52M
      }
678
1.52M
      break;
679
971k
    case MacWrtParserInternal::Information::RULER:
680
971k
      readParagraph(info.m_informations[i]);
681
971k
      break;
682
395k
    case MacWrtParserInternal::Information::GRAPHIC:
683
395k
      readGraphic(info.m_informations[i]);
684
395k
      break;
685
34.9k
    case MacWrtParserInternal::Information::PAGEBREAK:
686
34.9k
      readPageBreak(info.m_informations[i]);
687
34.9k
      if (zone == 0 && version() <= 3)
688
20.6k
        newPage(info.m_informations[i].m_pos.page()+2);
689
34.9k
      break;
690
0
    case MacWrtParserInternal::Information::UNKNOWN:
691
#if !defined(__clang__)
692
    default:
693
#endif
694
0
      break;
695
2.93M
    }
696
2.93M
  }
697
16.1k
  if (getTextListener() && zone) {
698
    // FIXME: try to insert field in the good place
699
7.55k
    if (info.m_pageNumber.x() >= 0 && info.m_pageNumber.y() >= 0)
700
4.98k
      getTextListener()->insertField(MWAWField(MWAWField::PageNumber));
701
7.55k
    if (info.m_date.x() >= 0 && info.m_date.y() >= 0)
702
5.04k
      getTextListener()->insertField(MWAWField(MWAWField::Date));
703
7.55k
    if (info.m_time.x() >= 0 && info.m_time.y() >= 0)
704
5.52k
      getTextListener()->insertField(MWAWField(MWAWField::Time));
705
7.55k
  }
706
16.1k
  return true;
707
16.1k
}
708
709
////////////////////////////////////////////////////////////
710
//
711
// Low level
712
//
713
////////////////////////////////////////////////////////////
714
715
////////////////////////////////////////////////////////////
716
// read the header
717
////////////////////////////////////////////////////////////
718
bool MacWrtParser::checkHeader(MWAWHeader *header, bool /*strict*/)
719
82.6k
{
720
82.6k
  *m_state = MacWrtParserInternal::State();
721
82.6k
  MacWrtParserInternal::FileHeader fHeader = m_state->m_fileHeader;
722
723
82.6k
  MWAWInputStreamPtr input = getInput();
724
82.6k
  if (!input || !input->hasDataFork())
725
0
    return false;
726
727
82.6k
  libmwaw::DebugStream f;
728
82.6k
  int headerSize=40;
729
82.6k
  if (!input->checkPosition(headerSize)) {
730
4.14k
    MWAW_DEBUG_MSG(("MacWrtParser::checkHeader: file is too short\n"));
731
4.14k
    return false;
732
4.14k
  }
733
78.4k
  input->seek(0,librevenge::RVNG_SEEK_SET);
734
735
78.4k
  auto vers = static_cast<int>(input->readULong(2));
736
78.4k
  setVersion(vers);
737
738
78.4k
  std::string vName("");
739
740
78.4k
  switch (vers) {
741
41.1k
  case 3:
742
41.1k
    vName="v1.0-2.2";
743
41.1k
    break;
744
37.2k
  case 6: // version 4.5 ( also version 5.01 of Claris MacWrite )
745
37.2k
    vName="v4.5-5.01";
746
37.2k
    break;
747
54
  default:
748
54
    MWAW_DEBUG_MSG(("MacWrtParser::checkHeader: unknown version\n"));
749
54
    return false;
750
78.4k
  }
751
78.4k
  if (vName.empty()) {
752
0
    MWAW_DEBUG_MSG(("Maybe a MacWrite file unknown version(%d)\n", vers));
753
0
  }
754
78.4k
  else {
755
78.4k
    MWAW_DEBUG_MSG(("MacWrite file %s\n", vName.c_str()));
756
78.4k
  }
757
758
78.4k
  f << "FileHeader: vers=" << vers << ",";
759
760
78.4k
  if (vers <= 3) fHeader.m_dataPos = static_cast<int>(input->readULong(2));
761
762
231k
  for (int &numParagraph : fHeader.m_numParagraphs) {
763
231k
    auto numParag = static_cast<int>(input->readLong(2));
764
231k
    numParagraph = numParag;
765
231k
    if (numParag < 0) {
766
2.37k
      MWAW_DEBUG_MSG(("MacWrtParser::checkHeader: numParagraphs is negative : %d\n",
767
2.37k
                      numParag));
768
2.37k
      return false;
769
2.37k
    }
770
231k
  }
771
772
76.0k
  if (vers <= 3) {
773
39.5k
    input->seek(6, librevenge::RVNG_SEEK_CUR); // unknown
774
39.5k
    if (input->readLong(1)) f << "hasFooter(?);";
775
39.5k
    if (input->readLong(1)) f << "hasHeader(?),";
776
39.5k
    fHeader.m_startNumberPage = static_cast<int>(input->readLong(2));
777
39.5k
    headerSize=20;
778
39.5k
  }
779
36.5k
  else {
780
36.5k
    fHeader.m_hideFirstPageHeaderFooter = (input->readULong(1)==0xFF);
781
782
36.5k
    input->seek(7, librevenge::RVNG_SEEK_CUR); // unused + 4 display flags + active doc
783
36.5k
    fHeader.m_startNumberPage = static_cast<int>(input->readLong(2));
784
36.5k
    fHeader.m_freeListPos = long(input->readULong(4));
785
36.5k
    fHeader.m_freeListLength = static_cast<int>(input->readULong(2));
786
36.5k
    fHeader.m_freeListAllocated = static_cast<int>(input->readULong(2));
787
    // 14 unused
788
36.5k
  }
789
76.0k
  f << fHeader;
790
791
  //
792
76.0k
  input->seek(headerSize, librevenge::RVNG_SEEK_SET);
793
76.0k
  if (!readPrintInfo()) {
794
63.5k
    input->seek(headerSize, librevenge::RVNG_SEEK_SET);
795
63.5k
    if (input->readLong(2)) return false;  // allow iPrVersion to be zero
796
37.7k
    input->seek(headerSize+0x78, librevenge::RVNG_SEEK_SET);
797
140k
    for (int i=0; i<3; ++i)
798
113k
      if (!readWindowsInfo(i) && i==2) return false;
799
37.7k
  }
800
40.0k
  if (!input->checkPosition(vers <= 3 ? fHeader.m_dataPos : fHeader.m_freeListPos))
801
3.97k
    return false;
802
803
36.0k
  input->seek(headerSize, librevenge::RVNG_SEEK_SET);
804
36.0k
  m_state->m_fileHeader = fHeader;
805
806
  // ok, we can finish initialization
807
36.0k
  if (header)
808
13.2k
    header->reset(MWAWDocument::MWAW_T_MACWRITE, version());
809
810
36.0k
  ascii().addPos(0);
811
36.0k
  ascii().addNote(f.str().c_str());
812
36.0k
  ascii().addPos(headerSize);
813
814
36.0k
  return true;
815
40.0k
}
816
817
////////////////////////////////////////////////////////////
818
// read the print info
819
////////////////////////////////////////////////////////////
820
bool MacWrtParser::readPrintInfo()
821
87.4k
{
822
87.4k
  MWAWInputStreamPtr input = getInput();
823
87.4k
  long pos = input->tell();
824
87.4k
  libmwaw::DebugStream f;
825
  // print info
826
87.4k
  libmwaw::PrinterInfo info;
827
87.4k
  if (!info.read(input)) return false;
828
21.4k
  f << "Entries(PrintInfo):"<< info;
829
830
21.4k
  MWAWVec2i paperSize = info.paper().size();
831
21.4k
  MWAWVec2i pageSize = info.page().size();
832
21.4k
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
833
16.6k
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
834
835
  // define margin from print info
836
15.5k
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
837
15.5k
  MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
838
839
  // move margin left | top
840
15.5k
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
841
15.5k
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
842
15.5k
  lTopMargin -= MWAWVec2i(decalX, decalY);
843
15.5k
  rBotMargin += MWAWVec2i(decalX, decalY);
844
845
  // decrease right | bottom
846
15.5k
  int rightMarg = rBotMargin.x() -10;
847
15.5k
  if (rightMarg < 0) rightMarg=0;
848
15.5k
  int botMarg = rBotMargin.y() -50;
849
15.5k
  if (botMarg < 0) botMarg=0;
850
851
15.5k
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
852
15.5k
  getPageSpan().setMarginBottom(botMarg/72.0);
853
15.5k
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
854
15.5k
  getPageSpan().setMarginRight(rightMarg/72.0);
855
15.5k
  getPageSpan().setFormLength(paperSize.y()/72.);
856
15.5k
  getPageSpan().setFormWidth(paperSize.x()/72.);
857
858
15.5k
  ascii().addPos(pos);
859
15.5k
  ascii().addNote(f.str().c_str());
860
15.5k
  input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
861
15.5k
  if (long(input->tell()) != pos+0x78) {
862
0
    MWAW_DEBUG_MSG(("MacWrtParser::readPrintInfo: file is too short\n"));
863
0
    return false;
864
0
  }
865
15.5k
  ascii().addPos(input->tell());
866
867
15.5k
  return true;
868
15.5k
}
869
870
////////////////////////////////////////////////////////////
871
// read the windows info
872
////////////////////////////////////////////////////////////
873
bool MacWrtParser::readWindowsInfo(int wh)
874
147k
{
875
147k
  MWAWInputStreamPtr input = getInput();
876
147k
  long pos = input->tell();
877
147k
  int windowsSize = version() <= 3 ? 34 : 46;
878
879
147k
  input->seek(pos+windowsSize, librevenge::RVNG_SEEK_SET);
880
147k
  if (long(input->tell()) !=pos+windowsSize) {
881
19.7k
    MWAW_DEBUG_MSG(("MacWrtParser::readWindowsInfo: file is too short\n"));
882
19.7k
    return false;
883
19.7k
  }
884
885
127k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
886
127k
  libmwaw::DebugStream f;
887
127k
  f << "Entries(Windows)";
888
127k
  switch (wh) {
889
45.4k
  case 0:
890
45.4k
    f << "[Footer]";
891
45.4k
    break;
892
42.3k
  case 1:
893
42.3k
    f << "[Header]";
894
42.3k
    break;
895
39.7k
  case 2:
896
39.7k
    break;
897
0
  default:
898
0
    MWAW_DEBUG_MSG(("MacWrtParser::readWindowsInfo: called with bad which=%d\n",wh));
899
0
    return false;
900
127k
  }
901
902
127k
  int which = 2-wh;
903
127k
  auto &info = m_state->m_windows[which];
904
127k
  f << ": ";
905
906
127k
  MWAWEntry informations;
907
127k
  MWAWEntry lineHeightEntry;
908
909
382k
  for (int i = 0; i < 2; i++) {
910
255k
    auto x = static_cast<int>(input->readLong(2));
911
255k
    auto y = static_cast<int>(input->readLong(2));
912
255k
    if (i == 0) info.m_startSel = MWAWVec2i(x,y);
913
127k
    else info.m_endSel = MWAWVec2i(x,y);
914
255k
  }
915
916
127k
  if (version() <= 3) {
917
134k
    for (int i = 0; i < 2; i++) {
918
89.5k
      auto val = static_cast<int>(input->readLong(2));
919
89.5k
      if (val) f << "unkn" << i << "=" << val << ",";
920
89.5k
    }
921
44.7k
  }
922
82.8k
  else {
923
82.8k
    info.m_posTopY = static_cast<int>(input->readLong(2));
924
82.8k
    input->seek(2,librevenge::RVNG_SEEK_CUR); // need to redraw
925
82.8k
    informations.setBegin(long(input->readULong(4)));
926
82.8k
    informations.setLength(long(input->readULong(2)));
927
82.8k
    informations.setId(which);
928
929
82.8k
    lineHeightEntry.setBegin(long(input->readULong(4)));
930
82.8k
    lineHeightEntry.setLength(long(input->readULong(2)));
931
82.8k
    lineHeightEntry.setId(which);
932
933
82.8k
    f << std::hex
934
82.8k
      << "lineHeight=[" << lineHeightEntry.begin() << "-" << lineHeightEntry.end() << "],"
935
82.8k
      << "informations=[" << informations.begin() << "-" << informations.end() << "],"
936
82.8k
      << std::dec;
937
82.8k
  }
938
510k
  for (int i = 0; i < 3; i++) {
939
382k
    auto x = static_cast<int>(input->readLong(2));
940
382k
    auto y = static_cast<int>(input->readLong(2));
941
382k
    if (i == 0) info.m_pageNumber = MWAWVec2i(x,y);
942
255k
    else if (i == 1) info.m_date = MWAWVec2i(x,y);
943
127k
    else info.m_time = MWAWVec2i(x,y);
944
382k
  }
945
127k
  f << info;
946
127k
  bool ok=true;
947
127k
  if (version() <= 3) {
948
44.7k
    input->seek(6,librevenge::RVNG_SEEK_CUR); // unknown flags: ff ff ff ff ff 00
949
44.7k
    f << "actFont=" << input->readLong(1) << ",";
950
134k
    for (int i= 0; i < 2; i++) {
951
89.5k
      auto val = static_cast<int>(input->readULong(1));
952
89.5k
      if (val==255) f << "f" << i << "=true,";
953
89.5k
    }
954
44.7k
    f << "flg=" << input->readLong(1);
955
44.7k
  }
956
82.8k
  else {
957
82.8k
    input->seek(4,librevenge::RVNG_SEEK_CUR); // unused
958
82.8k
    if (input->readULong(1) == 0xFF) f << "redrawOval,";
959
82.8k
    if (input->readULong(1) == 0xFF) f << "lastOvalUpdate,";
960
82.8k
    f << "actStyle=" << input->readLong(2) << ",";
961
82.8k
    f << "actFont=" << input->readLong(2);
962
963
82.8k
    if (!readLinesHeight(lineHeightEntry, info.m_firstParagLine, info.m_linesHeight)) {
964
      // ok, try to continue without lineHeight
965
79.6k
      info.m_firstParagLine.resize(0);
966
79.6k
      info.m_linesHeight.resize(0);
967
79.6k
    }
968
82.8k
    ok = readInformations(informations, info.m_informations);
969
82.8k
    if (!ok) info.m_informations.resize(0);
970
82.8k
  }
971
972
127k
  input->seek(pos+windowsSize, librevenge::RVNG_SEEK_SET);
973
127k
  ascii().addPos(pos);
974
127k
  ascii().addNote(f.str().c_str());
975
127k
  ascii().addPos(input->tell());
976
977
127k
  return ok;
978
127k
}
979
980
////////////////////////////////////////////////////////////
981
// read the lines height
982
////////////////////////////////////////////////////////////
983
bool MacWrtParser::readLinesHeight(MWAWEntry const &entry, std::vector<int> &firstParagLine, std::vector<int> &linesHeight)
984
83.6k
{
985
83.6k
  firstParagLine.resize(0);
986
83.6k
  linesHeight.resize(0);
987
988
83.6k
  if (!entry.valid()) return false;
989
990
50.4k
  MWAWInputStreamPtr input = getInput();
991
992
50.4k
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
993
50.4k
  if (long(input->tell()) != entry.end()-1) {
994
34.7k
    MWAW_DEBUG_MSG(("MacWrtParser::readLinesHeight: file is too short\n"));
995
34.7k
    return false;
996
34.7k
  }
997
998
15.7k
  long pos = entry.begin(), endPos = entry.end();
999
15.7k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1000
1001
15.7k
  libmwaw::DebugStream f;
1002
15.7k
  int numParag=0;
1003
425k
  while (input->tell() != endPos) {
1004
421k
    pos = input->tell();
1005
421k
    auto sz = static_cast<int>(input->readULong(2));
1006
421k
    if (pos+sz+2 > endPos) {
1007
8.84k
      MWAW_DEBUG_MSG(("MacWrtParser::readLinesHeight: find odd line\n"));
1008
8.84k
      ascii().addPos(pos);
1009
8.84k
      ascii().addNote("Entries(LineHeight):###");
1010
8.84k
      return false;
1011
8.84k
    }
1012
1013
412k
    firstParagLine.push_back(int(linesHeight.size()));
1014
412k
    int actHeight = 0;
1015
412k
    bool heightOk = false;
1016
412k
    f.str("");
1017
412k
    f << "Entries(LineHeight)[" << entry.id() << "-" << ++numParag << "]:";
1018
2.72M
    for (int c = 0; c < sz; c++) {
1019
2.31M
      auto val = static_cast<int>(input->readULong(1));
1020
2.31M
      if (val & 0x80) {
1021
100k
        val &= 0x7f;
1022
100k
        if (!heightOk || val==0) {
1023
3.20k
          MWAW_DEBUG_MSG(("MacWrtParser::readLinesHeight: find factor without height \n"));
1024
3.20k
          return false;
1025
3.20k
        }
1026
1027
10.4M
        for (int i = 0; i < val-1; i++)
1028
10.3M
          linesHeight.push_back(actHeight);
1029
97.3k
        if (val != 0x7f) heightOk = false;
1030
97.3k
        f << "x" << val;
1031
97.3k
        continue;
1032
100k
      }
1033
2.21M
      actHeight = val;
1034
2.21M
      linesHeight.push_back(actHeight);
1035
2.21M
      heightOk = true;
1036
2.21M
      if (c) f << ",";
1037
2.21M
      f << actHeight;
1038
2.21M
    }
1039
1040
409k
    ascii().addPos(pos);
1041
409k
    ascii().addNote(f.str().c_str());
1042
1043
409k
    if ((sz%2)==1) sz++;
1044
409k
    input->seek(pos+sz+2, librevenge::RVNG_SEEK_SET);
1045
409k
  }
1046
3.68k
  firstParagLine.push_back(int(linesHeight.size()));
1047
1048
3.68k
  ascii().addPos(endPos);
1049
3.68k
  ascii().addNote("_");
1050
3.68k
  return true;
1051
15.7k
}
1052
1053
////////////////////////////////////////////////////////////
1054
// read the entries
1055
////////////////////////////////////////////////////////////
1056
bool MacWrtParser::readInformationsV3(int numEntries, std::vector<MacWrtParserInternal::Information> &informations)
1057
11.2k
{
1058
11.2k
  informations.resize(0);
1059
1060
11.2k
  if (numEntries < 0) return false;
1061
11.2k
  if (numEntries == 0) return true;
1062
1063
7.17k
  MWAWInputStreamPtr input = getInput();
1064
1065
7.17k
  libmwaw::DebugStream f;
1066
19.5M
  for (int i = 0; i < numEntries; i++) {
1067
19.5M
    long pos = input->tell();
1068
19.5M
    MacWrtParserInternal::Information info;
1069
19.5M
    f.str("");
1070
19.5M
    f << "Entries(Information)[" << i+1 << "]:";
1071
19.5M
    auto height = static_cast<int>(input->readLong(2));
1072
19.5M
    info.m_height = height;
1073
19.5M
    if (info.m_height < 0) {
1074
308k
      info.m_height = 0;
1075
308k
      info.m_type = MacWrtParserInternal::Information::PAGEBREAK;
1076
308k
    }
1077
19.2M
    else if (info.m_height > 0)
1078
406k
      info.m_type = MacWrtParserInternal::Information::TEXT;
1079
18.8M
    else
1080
18.8M
      info.m_type = MacWrtParserInternal::Information::RULER;
1081
1082
19.5M
    auto y = static_cast<int>(input->readLong(2));
1083
19.5M
    info.m_pos=MWAWPosition(MWAWVec2f(0,float(y)), MWAWVec2f(0, float(height)), librevenge::RVNG_POINT);
1084
19.5M
    info.m_pos.setPage(static_cast<int>(input->readLong(1)));
1085
19.5M
    f << info;
1086
19.5M
    informations.push_back(info);
1087
1088
19.5M
    f << "unkn1=" << std::hex << input->readULong(2) << std::dec << ",";
1089
19.5M
    f << "unkn2=" << std::hex << input->readULong(1) << std::dec << ",";
1090
19.5M
    ascii().addPos(pos);
1091
19.5M
    ascii().addNote(f.str().c_str());
1092
19.5M
  }
1093
7.17k
  ascii().addPos(input->tell());
1094
7.17k
  ascii().addNote("_");
1095
1096
7.17k
  return true;
1097
11.2k
}
1098
1099
////////////////////////////////////////////////////////////
1100
// read the entries
1101
////////////////////////////////////////////////////////////
1102
bool MacWrtParser::readInformations(MWAWEntry const &entry, std::vector<MacWrtParserInternal::Information> &informations)
1103
82.8k
{
1104
82.8k
  informations.resize(0);
1105
1106
82.8k
  if (!entry.valid()) return false;
1107
1108
70.5k
  MWAWInputStreamPtr input = getInput();
1109
1110
70.5k
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
1111
70.5k
  if (long(input->tell()) != entry.end()-1) {
1112
20.4k
    MWAW_DEBUG_MSG(("MacWrtParser::readInformations: file is too short\n"));
1113
20.4k
    return false;
1114
20.4k
  }
1115
1116
50.0k
  long pos = entry.begin(), endPos = entry.end();
1117
50.0k
  if ((endPos-pos)%16) {
1118
5.63k
    MWAW_DEBUG_MSG(("MacWrtParser::readInformations: entry size is odd\n"));
1119
5.63k
    return false;
1120
5.63k
  }
1121
44.4k
  auto numEntries = int((endPos-pos)/16);
1122
44.4k
  libmwaw::DebugStream f;
1123
1124
44.4k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1125
10.6M
  for (int i = 0; i < numEntries; i++) {
1126
10.6M
    pos = input->tell();
1127
1128
10.6M
    f.str("");
1129
10.6M
    f << "Entries(Information)[" << entry.id() << "-" << i+1 << "]:";
1130
10.6M
    MacWrtParserInternal::Information info;
1131
10.6M
    auto height = static_cast<int>(input->readLong(2));
1132
10.6M
    if (height < 0) {
1133
1.55M
      info.m_type = MacWrtParserInternal::Information::GRAPHIC;
1134
1.55M
      height *= -1;
1135
1.55M
    }
1136
9.06M
    else if (height == 0)
1137
3.38M
      info.m_type = MacWrtParserInternal::Information::RULER;
1138
5.68M
    else
1139
5.68M
      info.m_type = MacWrtParserInternal::Information::TEXT;
1140
10.6M
    info.m_height = height;
1141
1142
10.6M
    auto y = static_cast<int>(input->readLong(2));
1143
10.6M
    auto page = static_cast<int>(input->readULong(1));
1144
10.6M
    input->seek(3, librevenge::RVNG_SEEK_CUR); // unused
1145
10.6M
    info.m_pos = MWAWPosition(MWAWVec2f(0,float(y)), MWAWVec2f(0, float(height)), librevenge::RVNG_POINT);
1146
10.6M
    info.m_pos.setPage(page);
1147
1148
10.6M
    auto paragStatus = static_cast<int>(input->readULong(1));
1149
10.6M
    switch (paragStatus & 0x3) {
1150
6.44M
    case 0:
1151
6.44M
      info.m_justify = MWAWParagraph::JustificationLeft;
1152
6.44M
      break;
1153
1.58M
    case 1:
1154
1.58M
      info.m_justify = MWAWParagraph::JustificationCenter;
1155
1.58M
      break;
1156
1.18M
    case 2:
1157
1.18M
      info.m_justify = MWAWParagraph::JustificationRight;
1158
1.18M
      break;
1159
1.41M
    case 3:
1160
1.41M
      info.m_justify = MWAWParagraph::JustificationFull;
1161
1.41M
      break;
1162
0
    default:
1163
0
      break;
1164
10.6M
    }
1165
10.6M
    info.m_compressed = (paragStatus & 0x8);
1166
10.6M
    info.m_justifySet = (paragStatus & 0x20);
1167
1168
    // other bits used internally
1169
10.6M
    auto highPos = static_cast<unsigned int>(input->readULong(1));
1170
10.6M
    info.m_data.setBegin(long(highPos<<16)+long(input->readULong(2)));
1171
10.6M
    info.m_data.setLength(long(input->readULong(2)));
1172
1173
10.6M
    auto paragFormat = static_cast<int>(input->readULong(2));
1174
10.6M
    uint32_t flags = 0;
1175
    // bit 1 = plain
1176
10.6M
    if (paragFormat&0x2) flags |= MWAWFont::boldBit;
1177
10.6M
    if (paragFormat&0x4) flags |= MWAWFont::italicBit;
1178
10.6M
    if (paragFormat&0x8) info.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
1179
10.6M
    if (paragFormat&0x10) flags |= MWAWFont::embossBit;
1180
10.6M
    if (paragFormat&0x20) flags |= MWAWFont::shadowBit;
1181
10.6M
    if (paragFormat&0x40)
1182
2.16M
      info.m_font.set(MWAWFont::Script::super100());
1183
10.6M
    if (paragFormat&0x80)
1184
1.57M
      info.m_font.set(MWAWFont::Script::sub100());
1185
10.6M
    info.m_font.setFlags(flags);
1186
1187
10.6M
    int fontSize = 0;
1188
10.6M
    switch ((paragFormat >> 8) & 7) {
1189
5.72M
    case 0:
1190
5.72M
      break;
1191
1.10M
    case 1:
1192
1.10M
      fontSize=9;
1193
1.10M
      break;
1194
735k
    case 2:
1195
735k
      fontSize=10;
1196
735k
      break;
1197
599k
    case 3:
1198
599k
      fontSize=12;
1199
599k
      break;
1200
580k
    case 4:
1201
580k
      fontSize=14;
1202
580k
      break;
1203
528k
    case 5:
1204
528k
      fontSize=18;
1205
528k
      break;
1206
480k
    case 6:
1207
480k
      fontSize=14;
1208
480k
      break;
1209
869k
    default: // rare, but can appears on some empty lines
1210
869k
      MWAW_DEBUG_MSG(("MacWrtParser::readInformations: unknown font size=7\n"));
1211
869k
      f << "##fSize=7,";
1212
10.6M
    }
1213
10.6M
    if (fontSize) info.m_font.setSize(float(fontSize));
1214
10.6M
    if ((paragFormat >> 11)&0x1F) info.m_font.setId((paragFormat >> 11)&0x1F);
1215
1216
10.6M
    informations.push_back(info);
1217
10.6M
    f << info;
1218
#ifdef DEBUG
1219
    f << "font=[" << info.m_font.getDebugString(getFontConverter()) << "]";
1220
#endif
1221
1222
10.6M
    input->seek(pos+16, librevenge::RVNG_SEEK_SET);
1223
10.6M
    ascii().addPos(pos);
1224
10.6M
    ascii().addNote(f.str().c_str());
1225
10.6M
  }
1226
1227
44.4k
  ascii().addPos(endPos);
1228
44.4k
  ascii().addNote("_");
1229
44.4k
  return true;
1230
44.4k
}
1231
1232
////////////////////////////////////////////////////////////
1233
// read a text
1234
////////////////////////////////////////////////////////////
1235
bool MacWrtParser::readText(MacWrtParserInternal::Information const &info,
1236
                            std::vector<int> const &lineHeight)
1237
1.52M
{
1238
1.52M
  if (!getTextListener()) {
1239
0
    MWAW_DEBUG_MSG(("MacWrtParser::readText: can not find the listener\n"));
1240
0
    return false;
1241
0
  }
1242
1.52M
  MWAWEntry const &entry = info.m_data;
1243
1.52M
  if (!entry.valid()) return false;
1244
1245
1.15M
  MWAWInputStreamPtr input = getInput();
1246
1.15M
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
1247
1.15M
  if (long(input->tell()) != entry.end()-1) {
1248
819k
    MWAW_DEBUG_MSG(("MacWrtParser::readText: file is too short\n"));
1249
819k
    return false;
1250
819k
  }
1251
1252
331k
  long pos = entry.begin();
1253
331k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1254
1255
331k
  libmwaw::DebugStream f;
1256
331k
  f << "Entries(Text):";
1257
1258
331k
  auto numChar = static_cast<int>(input->readULong(2));
1259
331k
  std::string text("");
1260
331k
  if (!info.m_compressed) {
1261
267k
    if (numChar+2 >= entry.length()) {
1262
98.1k
      MWAW_DEBUG_MSG(("MacWrtParser::readText: text is too long\n"));
1263
98.1k
      return false;
1264
98.1k
    }
1265
98.3M
    for (int i = 0; i < numChar; i++)
1266
98.1M
      text += char(input->readULong(1));
1267
168k
  }
1268
64.1k
  else {
1269
64.1k
    std::string const &compressCorr = m_state->m_compressCorr;
1270
1271
64.1k
    int actualChar = 0;
1272
64.1k
    bool actualCharSet = false;
1273
1274
148M
    for (int i = 0; i < numChar; i++) {
1275
148M
      int highByte = 0;
1276
162M
      for (int st = 0; st < 3; st++) {
1277
157M
        int actVal;
1278
157M
        if (!actualCharSet) {
1279
78.9M
          if (long(input->tell()) >= entry.end()) {
1280
18.6k
            MWAW_DEBUG_MSG(("MacWrtParser::readText: text is too long\n"));
1281
18.6k
            return false;
1282
18.6k
          }
1283
78.8M
          actualChar = static_cast<int>(input->readULong(1));
1284
78.8M
          actVal = (actualChar >> 4);
1285
78.8M
        }
1286
78.8M
        else
1287
78.8M
          actVal = (actualChar & 0xf);
1288
157M
        actualCharSet = !actualCharSet;
1289
157M
        if (st == 0) {
1290
148M
          if (actVal == 0xf) continue;
1291
143M
          text += compressCorr[size_t(actVal)];
1292
143M
          break;
1293
148M
        }
1294
9.32M
        if (st == 1) { // high bytes
1295
4.66M
          highByte = (actVal<<4);
1296
4.66M
          continue;
1297
4.66M
        }
1298
4.66M
        text += char(highByte | actVal);
1299
4.66M
      }
1300
148M
    }
1301
64.1k
  }
1302
214k
  f << "'" << text << "'";
1303
1304
214k
  long actPos = input->tell();
1305
214k
  if ((actPos-pos)%2==1) {
1306
44.6k
    input->seek(1,librevenge::RVNG_SEEK_CUR);
1307
44.6k
    actPos++;
1308
44.6k
  }
1309
1310
214k
  auto formatSize = static_cast<int>(input->readULong(2));
1311
214k
  if ((formatSize%6)!=0 || actPos+2+formatSize > entry.end()) {
1312
70.7k
    MWAW_DEBUG_MSG(("MacWrtParser::readText: format is too long\n"));
1313
70.7k
    return false;
1314
70.7k
  }
1315
143k
  int numFormat = formatSize/6;
1316
1317
143k
  std::vector<int> listPos;
1318
143k
  std::vector<MWAWFont> listFonts;
1319
1320
4.08M
  for (int i = 0; i < numFormat; i++) {
1321
3.93M
    auto tPos = static_cast<int>(input->readULong(2));
1322
1323
3.93M
    MWAWFont font;
1324
3.93M
    font.setSize(float(input->readULong(1)));
1325
3.93M
    auto flag = static_cast<int>(input->readULong(1));
1326
3.93M
    uint32_t flags = 0;
1327
    // bit 1 = plain
1328
3.93M
    if (flag&0x1) flags |= MWAWFont::boldBit;
1329
3.93M
    if (flag&0x2) flags |= MWAWFont::italicBit;
1330
3.93M
    if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
1331
3.93M
    if (flag&0x8) flags |= MWAWFont::embossBit;
1332
3.93M
    if (flag&0x10) flags |= MWAWFont::shadowBit;
1333
3.93M
    if (flag&0x20) font.set(MWAWFont::Script::super100());
1334
3.93M
    if (flag&0x40) font.set(MWAWFont::Script::sub100());
1335
3.93M
    font.setFlags(flags);
1336
3.93M
    font.setId(static_cast<int>(input->readULong(2)));
1337
3.93M
    listPos.push_back(tPos);
1338
3.93M
    listFonts.push_back(font);
1339
3.93M
    f << ",f" << i << "=[pos=" << tPos;
1340
#ifdef DEBUG
1341
    f << ",font=[" << font.getDebugString(getFontConverter()) << "]";
1342
#endif
1343
3.93M
    f << "]";
1344
3.93M
  }
1345
1346
143k
  std::vector<int> const *lHeight = &lineHeight;
1347
143k
  int totalHeight = info.m_height;
1348
143k
  std::vector<int> textLineHeight;
1349
143k
  if (version() <= 3) {
1350
852
    std::vector<int> fParagLines;
1351
852
    pos = input->tell();
1352
852
    MWAWEntry hEntry;
1353
852
    hEntry.setBegin(pos);
1354
852
    hEntry.setEnd(entry.end());
1355
1356
852
    if (readLinesHeight(hEntry, fParagLines, textLineHeight)) {
1357
460
      lHeight = &textLineHeight;
1358
460
      totalHeight = 0;
1359
460
      for (auto height : textLineHeight)
1360
40.2k
        totalHeight+=height;
1361
460
    }
1362
392
    else
1363
392
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1364
852
  }
1365
143k
  if (long(input->tell()) != entry.end()) {
1366
138k
    f << "#badend";
1367
138k
    ascii().addDelimiter(input->tell(), '|');
1368
138k
  }
1369
1370
143k
  if (getTextListener()) {
1371
143k
    MWAWParagraph para=getTextListener()->getParagraph();
1372
143k
    if (totalHeight && lHeight->size()) // fixme find a way to associate the good size to each line
1373
1.61k
      para.setInterline(totalHeight/double(lHeight->size()), librevenge::RVNG_POINT);
1374
141k
    else
1375
141k
      para.setInterline(1.2, librevenge::RVNG_PERCENT);
1376
143k
    if (info.m_justifySet)
1377
19.7k
      para.m_justify=info.m_justify;
1378
143k
    getTextListener()->setParagraph(para);
1379
1380
143k
    if (!numFormat || listPos[0] != 0)
1381
122k
      getTextListener()->setFont(info.m_font);
1382
1383
143k
    int actFormat = 0;
1384
143k
    numChar = int(text.length());
1385
66.9M
    for (int i = 0; i < numChar; i++) {
1386
66.8M
      if (actFormat < numFormat && i == listPos[size_t(actFormat)]) {
1387
28.9k
        getTextListener()->setFont(listFonts[size_t(actFormat)]);
1388
28.9k
        actFormat++;
1389
28.9k
      }
1390
66.8M
      auto c = static_cast<unsigned char>(text[size_t(i)]);
1391
66.8M
      if (c == 0x9)
1392
175k
        getTextListener()->insertTab();
1393
66.6M
      else if (c == 0xd)
1394
226k
        getTextListener()->insertEOL();
1395
66.4M
      else if (c==0x11) // command key (found in some files)
1396
76.4k
        getTextListener()->insertUnicode(0x2318);
1397
66.3M
      else if (c==0x14) // apple logo: check me
1398
138k
        getTextListener()->insertUnicode(0xf8ff);
1399
66.2M
      else if (c<0x1f) {
1400
        // MacWrite allows to add "invalid" characters in the text
1401
        // (and do not display them), this does not imply that the
1402
        // file is invalid...
1403
28.8M
        MWAW_DEBUG_MSG(("MacWrtParser::readText: find bad character %d at pos=0x%lx\n", int(c), version()<=3 ? entry.begin()-4 : entry.begin()));
1404
28.8M
        f << "###[" << int(c) << "]";
1405
28.8M
      }
1406
37.3M
      else
1407
37.3M
        getTextListener()->insertCharacter(c);
1408
66.8M
    }
1409
143k
  }
1410
1411
143k
  ascii().addPos(version()<=3 ? entry.begin()-4 : entry.begin());
1412
143k
  ascii().addNote(f.str().c_str());
1413
1414
143k
  return true;
1415
214k
}
1416
1417
////////////////////////////////////////////////////////////
1418
// read a paragraph
1419
////////////////////////////////////////////////////////////
1420
bool MacWrtParser::readParagraph(MacWrtParserInternal::Information const &info)
1421
971k
{
1422
971k
  MWAWEntry const &entry = info.m_data;
1423
971k
  if (!entry.valid()) return false;
1424
365k
  if (entry.length() != 34) {
1425
357k
    MWAW_DEBUG_MSG(("MacWrtParser::readParagraph: size is odd\n"));
1426
357k
    return false;
1427
357k
  }
1428
1429
8.66k
  MWAWParagraph parag;
1430
8.66k
  MWAWInputStreamPtr input = getInput();
1431
1432
8.66k
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
1433
8.66k
  if (long(input->tell()) != entry.end()-1) {
1434
1.35k
    MWAW_DEBUG_MSG(("MacWrtParser::readParagraph: file is too short\n"));
1435
1.35k
    return false;
1436
1.35k
  }
1437
1438
7.31k
  long pos = entry.begin();
1439
7.31k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1440
1441
7.31k
  libmwaw::DebugStream f;
1442
7.31k
  f << "Entries(Paragraph):";
1443
1444
7.31k
  parag.m_margins[1] = double(input->readLong(2))/80.;
1445
7.31k
  parag.m_margins[2] = double(input->readLong(2))/80.;
1446
7.31k
  auto justify = static_cast<int>(input->readLong(1));
1447
7.31k
  switch (justify) {
1448
3.11k
  case 0:
1449
3.11k
    parag.m_justify = MWAWParagraph::JustificationLeft;
1450
3.11k
    break;
1451
330
  case 1:
1452
330
    parag.m_justify = MWAWParagraph::JustificationCenter;
1453
330
    break;
1454
461
  case 2:
1455
461
    parag.m_justify = MWAWParagraph::JustificationRight;
1456
461
    break;
1457
451
  case 3:
1458
451
    parag.m_justify = MWAWParagraph::JustificationFull;
1459
451
    break;
1460
2.95k
  default:
1461
2.95k
    f << "##justify=" << justify << ",";
1462
2.95k
    break;
1463
7.31k
  }
1464
7.31k
  auto numTabs = static_cast<int>(input->readLong(1));
1465
7.31k
  if (numTabs < 0 || numTabs > 10) {
1466
2.89k
    f << "##numTabs=" << numTabs << ",";
1467
2.89k
    numTabs = 0;
1468
2.89k
  }
1469
7.31k
  auto highspacing = static_cast<int>(input->readULong(1));
1470
7.31k
  if (highspacing==0x80) // 6 by line
1471
593
    parag.setInterline(12, librevenge::RVNG_POINT);
1472
6.71k
  else if (highspacing) {
1473
3.64k
    f << "##highSpacing=" << std::hex << highspacing << std::dec << ",";
1474
3.64k
    MWAW_DEBUG_MSG(("MacWrtParser::readParagraph: high spacing bit set=%d\n", highspacing));
1475
3.64k
  }
1476
7.31k
  auto spacing = static_cast<int>(input->readLong(1));
1477
7.31k
  if (spacing < 0)
1478
1.99k
    f << "#interline=" << 1.+spacing/2.0 << ",";
1479
5.31k
  else if (spacing)
1480
2.49k
    parag.setInterline(1.+spacing/2.0, librevenge::RVNG_PERCENT);
1481
7.31k
  parag.m_margins[0] = double(input->readLong(2))/80.;
1482
1483
7.31k
  parag.m_tabs->resize(size_t(numTabs));
1484
17.2k
  for (size_t i = 0; i < size_t(numTabs); i++) {
1485
9.89k
    auto numPixel = static_cast<int>(input->readLong(2));
1486
9.89k
    auto align = MWAWTabStop::LEFT;
1487
9.89k
    if (numPixel < 0) {
1488
2.02k
      align = MWAWTabStop::DECIMAL;
1489
2.02k
      numPixel *= -1;
1490
2.02k
    }
1491
9.89k
    (*parag.m_tabs)[i].m_alignment = align;
1492
9.89k
    (*parag.m_tabs)[i].m_position = numPixel/72.0;
1493
9.89k
  }
1494
7.31k
  *(parag.m_margins[0]) -= parag.m_margins[1].get();
1495
7.31k
  if (parag.m_margins[2].get() > 0.0)
1496
4.41k
    parag.m_margins[2]=getPageWidth()-parag.m_margins[2].get()-1.0;
1497
7.31k
  if (parag.m_margins[2].get() < 0) parag.m_margins[2] = 0;
1498
7.31k
  f << parag;
1499
1500
7.31k
  if (getTextListener())
1501
7.31k
    getTextListener()->setParagraph(parag);
1502
7.31k
  ascii().addPos(version()<=3 ? pos-4 : pos);
1503
7.31k
  ascii().addNote(f.str().c_str());
1504
1505
7.31k
  return true;
1506
7.31k
}
1507
1508
////////////////////////////////////////////////////////////
1509
// read the page break
1510
////////////////////////////////////////////////////////////
1511
bool MacWrtParser::readPageBreak(MacWrtParserInternal::Information const &info)
1512
34.9k
{
1513
34.9k
  MWAWEntry const &entry = info.m_data;
1514
34.9k
  if (!entry.valid()) return false;
1515
2.28k
  if (entry.length() != 21) {
1516
2.27k
    MWAW_DEBUG_MSG(("MacWrtParser::readPageBreak: size is odd\n"));
1517
2.27k
    return false;
1518
2.27k
  }
1519
1520
12
  MWAWParagraph parag;
1521
12
  MWAWInputStreamPtr input = getInput();
1522
1523
12
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
1524
12
  if (long(input->tell()) != entry.end()-1) {
1525
0
    MWAW_DEBUG_MSG(("MacWrtParser::readPageBreak: file is too short\n"));
1526
0
    return false;
1527
0
  }
1528
1529
12
  long pos = entry.begin();
1530
12
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1531
1532
12
  libmwaw::DebugStream f;
1533
1534
12
  f << "Entries(PageBreak):";
1535
36
  for (int i = 0; i < 2; i++) {
1536
24
    auto val = static_cast<int>(input->readLong(2));
1537
24
    if (val) f << "f" << i << "=" << val << ",";
1538
24
  }
1539
12
  int dim[2]= {0,0};
1540
24
  for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1541
12
  f << "pageSize(?)=" << dim[0] << "x" << dim[1] << ",";
1542
12
  f << "unk=" << input->readLong(2) << ","; // find 0xd
1543
1544
  // find MAGICPIC
1545
12
  std::string name("");
1546
108
  for (int i = 0; i < 8; i++)
1547
96
    name += char(input->readULong(1));
1548
12
  f << name << ",";
1549
  // then I find 1101ff: end of quickdraw pict1 ?
1550
12
  ascii().addPos(version()<=3 ? pos-4 : pos);
1551
12
  ascii().addNote(f.str().c_str());
1552
1553
12
  return true;
1554
12
}
1555
1556
////////////////////////////////////////////////////////////
1557
// read a graphic
1558
////////////////////////////////////////////////////////////
1559
bool MacWrtParser::readGraphic(MacWrtParserInternal::Information const &info)
1560
395k
{
1561
395k
  MWAWEntry const &entry = info.m_data;
1562
395k
  if (!entry.valid()) return false;
1563
1564
330k
  if (entry.length() < 12) {
1565
27.7k
    MWAW_DEBUG_MSG(("MacWrtParser::readGraphic: file is too short\n"));
1566
27.7k
    return false;
1567
27.7k
  }
1568
1569
303k
  MWAWInputStreamPtr input = getInput();
1570
1571
303k
  input->seek(entry.end()-1, librevenge::RVNG_SEEK_SET);
1572
303k
  if (long(input->tell()) != entry.end()-1) {
1573
241k
    MWAW_DEBUG_MSG(("MacWrtParser::readGraphic: file is too short\n"));
1574
241k
    return false;
1575
241k
  }
1576
61.7k
  long pos = entry.begin();
1577
61.7k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1578
1579
61.7k
  int dim[4];
1580
246k
  for (auto &d : dim) d = static_cast<int>(input->readLong(2));
1581
61.7k
  if (dim[2] < dim[0] || dim[3] < dim[1]) {
1582
30.3k
    MWAW_DEBUG_MSG(("MacWrtParser::readGraphic: bdbox is bad\n"));
1583
30.3k
    return false;
1584
30.3k
  }
1585
31.3k
  libmwaw::DebugStream f;
1586
31.3k
  f << "Entries(Graphic):";
1587
1588
31.3k
  MWAWBox2f box;
1589
31.3k
  auto res = MWAWPictData::check(input, int(entry.length()-8), box);
1590
31.3k
  if (res == MWAWPict::MWAW_R_BAD) {
1591
12.3k
    MWAW_DEBUG_MSG(("MacWrtParser::readGraphic: can not find the picture\n"));
1592
12.3k
    return false;
1593
12.3k
  }
1594
1595
1596
18.9k
  MWAWVec2f actualSize(float(dim[3]-dim[1]), float(dim[2]-dim[0])), naturalSize(actualSize);
1597
18.9k
  if (box.size().x() > 0 && box.size().y()  > 0) naturalSize = box.size();
1598
18.9k
  MWAWPosition pictPos=MWAWPosition(MWAWVec2f(0,0),actualSize, librevenge::RVNG_POINT);
1599
18.9k
  pictPos.setRelativePosition(MWAWPosition::Char);
1600
18.9k
  pictPos.setNaturalSize(naturalSize);
1601
18.9k
  f << pictPos;
1602
1603
  // get the picture
1604
18.9k
  input->seek(pos+8, librevenge::RVNG_SEEK_SET);
1605
1606
18.9k
  std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, int(entry.length()-8)));
1607
18.9k
  if (pict) {
1608
18.9k
    if (getTextListener()) {
1609
18.9k
      MWAWParagraph para=getTextListener()->getParagraph();
1610
18.9k
      para.setInterline(1.0, librevenge::RVNG_PERCENT);
1611
18.9k
      getTextListener()->setParagraph(para);
1612
1613
18.9k
      MWAWEmbeddedObject picture;
1614
18.9k
      if (pict->getBinary(picture) && !picture.m_dataList.empty() && !isMagicPic(picture.m_dataList[0]))
1615
18.9k
        getTextListener()->insertPicture(pictPos, picture);
1616
18.9k
      getTextListener()->insertEOL();
1617
#ifdef DEBUG_WITH_FILES
1618
      if (!picture.m_dataList.empty()) {
1619
        static int volatile pictName = 0;
1620
        libmwaw::DebugStream f2;
1621
        f2 << "PICT-" << ++pictName;
1622
        libmwaw::Debug::dumpFile(picture.m_dataList[0], f2.str().c_str());
1623
        ascii().skipZone(pos+8, entry.end()-1);
1624
      }
1625
#endif
1626
18.9k
    }
1627
18.9k
  }
1628
1629
18.9k
  ascii().addPos(pos);
1630
18.9k
  ascii().addNote(f.str().c_str());
1631
1632
18.9k
  return true;
1633
31.3k
}
1634
1635
bool MacWrtParser::isMagicPic(librevenge::RVNGBinaryData const &dt)
1636
18.9k
{
1637
18.9k
  if (dt.size() != 526)
1638
18.5k
    return false;
1639
377
  static char const *header="MAGICPIC";
1640
377
  unsigned char const *dtBuf = dt.getDataBuffer()+514;
1641
416
  for (int i=0; i < 8; i++)
1642
416
    if (*(dtBuf++)!=header[i])
1643
377
      return false;
1644
0
  return true;
1645
377
}
1646
1647
////////////////////////////////////////////////////////////
1648
// read the free list
1649
////////////////////////////////////////////////////////////
1650
bool MacWrtParser::checkFreeList()
1651
0
{
1652
0
  if (version() <= 3)
1653
0
    return true;
1654
0
  MWAWInputStreamPtr input = getInput();
1655
0
  long pos = m_state->m_fileHeader.m_freeListPos;
1656
0
  if (!input->checkPosition(pos+m_state->m_fileHeader.m_freeListLength)) {
1657
0
    MWAW_DEBUG_MSG(("MacWrtParser::checkFreeList: zone is too short\n"));
1658
0
    return false;
1659
0
  }
1660
0
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1661
1662
0
  libmwaw::DebugStream f;
1663
0
  int N=int(m_state->m_fileHeader.m_freeListLength/8);
1664
0
  for (int n=0; n<N; ++n) {
1665
0
    pos=input->tell();
1666
0
    auto freePos = long(input->readULong(4));
1667
0
    auto sz = long(input->readULong(4));
1668
1669
0
    f.str("");
1670
0
    f << "Entries(FreeList)[" << n << "]:" << std::hex << freePos << "-" << sz << std::dec;
1671
0
    ascii().addPos(pos);
1672
0
    ascii().addNote(f.str().c_str());
1673
1674
    // if the file end by a free zone, pos+sz can be greater than the file size
1675
0
    if (!input->checkPosition(freePos+1)) {
1676
0
      if (!input->checkPosition(freePos)) {
1677
0
        MWAW_DEBUG_MSG(("MacWrtParser::checkFreeList: bad free block: \n"));
1678
0
        return false;
1679
0
      }
1680
0
      continue;
1681
0
    }
1682
0
    f.str("");
1683
0
    f << "Entries(FreeBlock)[" << n << "]:";
1684
0
    ascii().addPos(freePos);
1685
0
    ascii().addNote(f.str().c_str());
1686
0
  }
1687
0
  if (m_state->m_fileHeader.m_freeListLength!=m_state->m_fileHeader.m_freeListAllocated) {
1688
0
    ascii().addPos(input->tell());
1689
0
    ascii().addNote("Entries(FreeList)[end]:");
1690
0
  }
1691
0
  return true;
1692
0
}
1693
1694
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: