Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MouseWrtParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <iomanip>
35
#include <iostream>
36
#include <limits>
37
#include <map>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWTextListener.hxx"
43
#include "MWAWFont.hxx"
44
#include "MWAWFontConverter.hxx"
45
#include "MWAWHeader.hxx"
46
#include "MWAWParagraph.hxx"
47
#include "MWAWPictMac.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWPrinter.hxx"
50
#include "MWAWRSRCParser.hxx"
51
#include "MWAWSubDocument.hxx"
52
53
#include "MouseWrtParser.hxx"
54
55
/** Internal: the structures of a MouseWrtParser */
56
namespace MouseWrtParserInternal
57
{
58
////////////////////////////////////////
59
//! Internal: class to store zone information of a MouseWrtParser
60
struct Zone {
61
  //! constructor
62
  Zone()
63
84.3k
    : m_font()
64
84.3k
    , m_writingHebrew(false)
65
84.3k
    , m_text()
66
84.3k
  {
67
84.3k
  }
68
  //! the font
69
  MWAWFont m_font;
70
  //! flag to know if the writing is reverted
71
  bool m_writingHebrew;
72
  //! the text entry
73
  MWAWEntry m_text;
74
};
75
76
////////////////////////////////////////
77
//! Internal: class to store paragraph information of a MouseWrtParser
78
struct Paragraph {
79
  //! constructor
80
  explicit Paragraph(int id=0)
81
3.14M
    : m_id(id)
82
3.14M
    , m_paragraph()
83
3.14M
    , m_picture(false)
84
3.14M
  {
85
3.14M
  }
86
  //! the paragraph id
87
  int m_id;
88
  //! the paragraph
89
  MWAWParagraph m_paragraph;
90
  //! flag to know if this is a picture
91
  bool m_picture;
92
};
93
////////////////////////////////////////
94
//! Internal: the state of a MouseWrtParser
95
struct State {
96
  //! constructor
97
  State()
98
42.1k
    : m_actPage(0)
99
42.1k
    , m_numPages(0)
100
42.1k
    , m_charPLCMap()
101
42.1k
    , m_paraPLCMap()
102
42.1k
    , m_text()
103
42.1k
  {
104
210k
    for (auto &size : m_blockSizes) size=0;
105
42.1k
  }
106
107
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
108
  /** the first zone's size */
109
  long m_blockSizes[5];
110
  /** the map position to charPLC */
111
  std::map<int, MWAWFont> m_charPLCMap;
112
  /** the map position to paraPLC */
113
  std::map<int, Paragraph> m_paraPLCMap;
114
  /** the main text entry */
115
  MWAWEntry m_text;
116
  /** the header and the footer zone */
117
  Zone m_zones[2];
118
};
119
120
////////////////////////////////////////
121
//! Internal: the subdocument of a MouseWrtParser
122
class SubDocument final : public MWAWSubDocument
123
{
124
public:
125
  SubDocument(MouseWrtParser &pars, MWAWInputStreamPtr const &input, int zoneId)
126
5.01k
    : MWAWSubDocument(&pars, input, MWAWEntry())
127
5.01k
    , m_id(zoneId)
128
5.01k
  {
129
5.01k
  }
130
131
  //! destructor
132
0
  ~SubDocument() final {}
133
134
  //! operator!=
135
  bool operator!=(MWAWSubDocument const &doc) const final;
136
137
  //! the parser function
138
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
139
140
protected:
141
  //! the subdocument id
142
  int m_id;
143
};
144
145
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
146
5.01k
{
147
5.01k
  if (!listener.get()) {
148
0
    MWAW_DEBUG_MSG(("MouseWrtParserInternal::SubDocument::parse: no listener\n"));
149
0
    return;
150
0
  }
151
5.01k
  auto *parser=dynamic_cast<MouseWrtParser *>(m_parser);
152
5.01k
  if (!parser) {
153
0
    MWAW_DEBUG_MSG(("MouseWrtParserInternal::SubDocument::parse: no parser\n"));
154
0
    return;
155
0
  }
156
157
5.01k
  long pos = m_input->tell();
158
5.01k
  parser->sendZone(m_id);
159
5.01k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
160
5.01k
}
161
162
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
163
0
{
164
0
  if (MWAWSubDocument::operator!=(doc)) return true;
165
0
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
166
0
  if (!sDoc) return true;
167
0
  if (m_id != sDoc->m_id) return true;
168
0
  return false;
169
0
}
170
}
171
172
////////////////////////////////////////////////////////////
173
// constructor/destructor, ...
174
////////////////////////////////////////////////////////////
175
MouseWrtParser::MouseWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
176
17.9k
  : MWAWTextParser(input, rsrcParser, header)
177
17.9k
  , m_state(new MouseWrtParserInternal::State)
178
17.9k
{
179
17.9k
  setAsciiName("main-1");
180
17.9k
}
181
182
MouseWrtParser::~MouseWrtParser()
183
17.9k
{
184
17.9k
}
185
186
////////////////////////////////////////////////////////////
187
// new page
188
////////////////////////////////////////////////////////////
189
void MouseWrtParser::newPage(int number)
190
22.1k
{
191
22.1k
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
192
9.35k
    return;
193
194
25.6k
  while (m_state->m_actPage < number) {
195
12.8k
    m_state->m_actPage++;
196
12.8k
    if (!getTextListener() || m_state->m_actPage == 1)
197
5.60k
      continue;
198
7.20k
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
199
7.20k
  }
200
12.8k
}
201
202
////////////////////////////////////////////////////////////
203
// the parser
204
////////////////////////////////////////////////////////////
205
void MouseWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
206
6.20k
{
207
6.20k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
208
6.20k
  bool ok = true;
209
6.20k
  try {
210
    // create the asciiFile
211
6.20k
    ascii().setStream(getInput());
212
6.20k
    ascii().open(asciiName());
213
6.20k
    checkHeader(nullptr);
214
6.20k
    ok=createZones();
215
6.20k
    if (ok) {
216
6.20k
      createDocument(docInterface);
217
6.20k
      sendMainZone();
218
6.20k
    }
219
220
6.20k
    ascii().reset();
221
6.20k
  }
222
6.20k
  catch (...) {
223
0
    MWAW_DEBUG_MSG(("MouseWrtParser::parse: exception catched when parsing\n"));
224
0
    ok = false;
225
0
  }
226
227
6.20k
  resetTextListener();
228
6.20k
  if (!ok) throw(libmwaw::ParseException());
229
6.20k
}
230
231
////////////////////////////////////////////////////////////
232
// create the document
233
////////////////////////////////////////////////////////////
234
void MouseWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
235
6.20k
{
236
6.20k
  if (!documentInterface) return;
237
6.20k
  if (getTextListener()) {
238
0
    MWAW_DEBUG_MSG(("MouseWrtParser::createDocument: listener already exist\n"));
239
0
    return;
240
0
  }
241
242
  // update the page
243
6.20k
  m_state->m_actPage = 0;
244
245
  // create the page list
246
6.20k
  MWAWPageSpan ps(getPageSpan());
247
6.20k
  m_state->m_numPages=computeNumPages();
248
6.20k
  ps.setPageSpan(m_state->m_numPages);
249
18.6k
  for (int i=0; i<2; ++i) {
250
12.4k
    if (!m_state->m_zones[i].m_text.valid()) continue;
251
5.01k
    MWAWHeaderFooter hF(i==0 ? MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
252
5.01k
    hF.m_subDocument.reset(new MouseWrtParserInternal::SubDocument(*this, getInput(), i));
253
5.01k
    ps.setHeaderFooter(hF);
254
5.01k
  }
255
6.20k
  std::vector<MWAWPageSpan> pageList;
256
6.20k
  pageList.push_back(ps);
257
  //
258
6.20k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
259
6.20k
  setTextListener(listen);
260
6.20k
  listen->startDocument();
261
6.20k
}
262
263
264
////////////////////////////////////////////////////////////
265
//
266
// Intermediate level
267
//
268
////////////////////////////////////////////////////////////
269
bool MouseWrtParser::createZones()
270
6.20k
{
271
6.20k
  MWAWInputStreamPtr input = getInput();
272
6.20k
  libmwaw::DebugStream f;
273
37.2k
  for (int i=0; i<5; ++i) {
274
31.0k
    if (!m_state->m_blockSizes[i]) continue;
275
18.9k
    long pos = input->tell();
276
18.9k
    if (m_state->m_blockSizes[i]<0 || !input->checkPosition(pos+m_state->m_blockSizes[i])) {
277
0
      MWAW_DEBUG_MSG(("MouseWrtParser::createZones: the block sizes are wrong\n"));
278
0
      return false;
279
0
    }
280
18.9k
    if (i==1) continue;
281
13.3k
    bool done=false;
282
13.3k
    switch (i) {
283
4.84k
    case 0:
284
4.84k
      done=readCharPLCs(m_state->m_blockSizes[i]);
285
4.84k
      break;
286
4.35k
    case 2:
287
4.35k
      done=readParagraphPLCs(m_state->m_blockSizes[i]);
288
4.35k
      break;
289
1.10k
    case 3:
290
1.10k
      done=m_state->m_blockSizes[i]>=120 && readPrintInfo();
291
1.10k
      break;
292
3.01k
    case 4:
293
3.01k
      done=readDocumentInfo(m_state->m_blockSizes[i]);
294
3.01k
      break;
295
0
    default:
296
0
      break;
297
13.3k
    }
298
13.3k
    if (done) {
299
11.5k
      if (input->tell()!=pos+m_state->m_blockSizes[i])
300
2.68k
        ascii().addDelimiter(input->tell(),'|');
301
11.5k
    }
302
1.79k
    else {
303
1.79k
      f.str("");
304
1.79k
      f << "Entries(Zone" << i << "):";
305
1.79k
      ascii().addPos(pos);
306
1.79k
      ascii().addNote(f.str().c_str());
307
1.79k
    }
308
13.3k
    input->seek(pos+m_state->m_blockSizes[i], librevenge::RVNG_SEEK_SET);
309
13.3k
  }
310
6.20k
  m_state->m_text.setBegin(input->tell());
311
6.20k
  m_state->m_text.setLength(m_state->m_blockSizes[1]);
312
6.20k
  if (m_state->m_blockSizes[1]<0 || !input->checkPosition(m_state->m_text.end())) {
313
0
    MWAW_DEBUG_MSG(("MouseWrtParser::createZones: can not find the text zone\n"));
314
0
    return false;
315
0
  }
316
6.20k
  if (!input->isEnd()) {
317
6.11k
    ascii().addPos(input->tell());
318
6.11k
    ascii().addNote("Entries(Unknown):");
319
6.11k
  }
320
6.20k
  return true;
321
6.20k
}
322
323
////////////////////////////////////////////////////////////
324
//
325
// Low level
326
//
327
////////////////////////////////////////////////////////////
328
329
////////////////////////////////////////////////////////////
330
// read the header
331
////////////////////////////////////////////////////////////
332
bool MouseWrtParser::checkHeader(MWAWHeader *header, bool strict)
333
24.2k
{
334
24.2k
  *m_state = MouseWrtParserInternal::State();
335
336
24.2k
  MWAWInputStreamPtr input = getInput();
337
24.2k
  if (!input || !input->hasDataFork())
338
8
    return false;
339
340
24.1k
  libmwaw::DebugStream f;
341
24.1k
  f << "FileHeader:";
342
24.1k
  int headerSize=30;
343
24.1k
  if (!input->checkPosition(headerSize)) {
344
172
    MWAW_DEBUG_MSG(("MouseWrtParser::checkHeader: file is too short\n"));
345
172
    return false;
346
172
  }
347
24.0k
  input->seek(0,librevenge::RVNG_SEEK_SET);
348
24.0k
  if (input->readULong(4)!=0x4474d30 || input->readULong(2)!=0x3400)
349
222
    return false;
350
23.7k
  long totalSize=m_state->m_blockSizes[0];
351
138k
  for (int i=0; i<5; ++i) {
352
115k
    m_state->m_blockSizes[i]=long(input->readLong(4));
353
115k
    if (m_state->m_blockSizes[i]<0) return false;
354
114k
    char const *wh[]= {"charPlc","text","paraPLC","printer","zone4"};
355
114k
    f << wh[i] << "[sz]=" << m_state->m_blockSizes[i] << ",";
356
114k
    totalSize+=m_state->m_blockSizes[i];
357
114k
  }
358
22.0k
  if (totalSize<0 || !input->checkPosition(30+totalSize)) return false;
359
20.8k
  if (strict && ((m_state->m_blockSizes[0]%8)!=0 || (m_state->m_blockSizes[2]%38)!=0 ||
360
6.47k
                 (m_state->m_blockSizes[3] && m_state->m_blockSizes[3]<120) ||
361
5.94k
                 (m_state->m_blockSizes[4] && m_state->m_blockSizes[4]<76)))
362
1.30k
    return false;
363
  // probably a size, maybe pict size
364
19.5k
  auto dSz=long(input->readLong(4));
365
19.5k
  if (dSz) {
366
13.2k
    MWAW_DEBUG_MSG(("MouseWrtParser::checkHeader: find some extra size?\n"));
367
13.2k
    f << "##f0=" << dSz << ",";
368
13.2k
  }
369
  // ok, we can finish initialization
370
19.5k
  if (header)
371
7.13k
    header->reset(MWAWDocument::MWAW_T_MOUSEWRITE, 1);
372
19.5k
  input->seek(headerSize,librevenge::RVNG_SEEK_SET);
373
374
19.5k
  ascii().addPos(0);
375
19.5k
  ascii().addNote(f.str().c_str());
376
19.5k
  ascii().addPos(headerSize);
377
19.5k
  return true;
378
20.8k
}
379
380
////////////////////////////////////////////////////////////
381
// read the basic structure
382
////////////////////////////////////////////////////////////
383
bool MouseWrtParser::readCharPLCs(long sz)
384
4.84k
{
385
4.84k
  MWAWInputStreamPtr input = getInput();
386
4.84k
  long pos = input->tell();
387
4.84k
  if (sz<0 || (sz%8)!=0 || !input->checkPosition(pos+sz)) {
388
300
    MWAW_DEBUG_MSG(("MouseWrtParser::readCharPLCs: find unexpected size length\n"));
389
300
    return false;
390
300
  }
391
4.54k
  long N=sz/8;
392
4.54k
  libmwaw::DebugStream f;
393
4.54k
  f << "Entries(CharPLC):";
394
4.54k
  ascii().addPos(pos);
395
4.54k
  ascii().addNote(f.str().c_str());
396
2.92M
  for (long i=0; i<N; ++i) {
397
2.92M
    pos=input->tell();
398
2.92M
    f.str("");
399
2.92M
    f << "CharPLC-C" << i << ":";
400
2.92M
    int cPos;
401
2.92M
    MWAWFont font;
402
2.92M
    if (i+1!=N && readFont(font, cPos)) {
403
2.92M
      f << "cPos=" << cPos << "," << font.getDebugString(getParserState()->m_fontConverter);
404
2.92M
      m_state->m_charPLCMap[cPos]=font;
405
2.92M
    }
406
2.92M
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
407
2.92M
    ascii().addPos(pos);
408
2.92M
    ascii().addNote(f.str().c_str());
409
2.92M
  }
410
4.54k
  return true;
411
4.84k
}
412
413
bool MouseWrtParser::readFont(MWAWFont &font, int &cPos)
414
2.92M
{
415
2.92M
  MWAWInputStreamPtr input = getInput();
416
2.92M
  long pos = input->tell();
417
2.92M
  if (!input->checkPosition(pos+8)) return false;
418
2.92M
  cPos=static_cast<int>(input->readULong(2));
419
2.92M
  libmwaw::DebugStream f;
420
2.92M
  font=MWAWFont();
421
2.92M
  auto val=int(input->readULong(1));
422
2.92M
  if (val) f << "f0=" << val << ",";
423
2.92M
  font.setSize(float(input->readULong(1)));
424
2.92M
  auto flag=static_cast<int>(input->readULong(1));
425
2.92M
  uint32_t flags=0;
426
2.92M
  if (flag&0x1) flags |= MWAWFont::boldBit;
427
2.92M
  if (flag&0x2) flags |= MWAWFont::italicBit;
428
2.92M
  if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
429
2.92M
  if (flag&0x8) flags |= MWAWFont::embossBit;
430
2.92M
  if (flag&0x10) flags |= MWAWFont::shadowBit;
431
2.92M
  if (flag&0x60) f << "#flag[hi]=" << std::hex << (flag&0x60) << std::dec << ",";
432
2.92M
  font.setFlags(flags);
433
2.92M
  val=static_cast<int>(input->readULong(1)); // 0|7d
434
2.92M
  if (val) f << "f1=" << val << ",";
435
2.92M
  font.setId(static_cast<int>(input->readULong(2)));
436
2.92M
  font.m_extra=f.str().c_str();
437
2.92M
  return true;
438
2.92M
}
439
440
bool MouseWrtParser::readParagraphPLCs(long sz)
441
4.35k
{
442
4.35k
  MWAWInputStreamPtr input = getInput();
443
4.35k
  long pos = input->tell();
444
4.35k
  if (sz<0 || (sz%38)!=0 || !input->checkPosition(pos+sz)) {
445
376
    MWAW_DEBUG_MSG(("MouseWrtParser::readParagraphPLCs: find unexpected size length\n"));
446
376
    return false;
447
376
  }
448
3.97k
  auto N=int(sz/38);
449
3.97k
  libmwaw::DebugStream f;
450
3.97k
  f << "Entries(ParaPLC):";
451
3.97k
  ascii().addPos(pos);
452
3.97k
  ascii().addNote(f.str().c_str());
453
2.36M
  for (int i=0; i<N; ++i) {
454
2.36M
    pos=input->tell();
455
2.36M
    f.str("");
456
2.36M
    f << "ParaPLC-P" << i << ":";
457
2.36M
    if (i+1==N) { // last is sometimes random
458
3.97k
      input->seek(pos+36, librevenge::RVNG_SEEK_SET);
459
3.97k
      auto cPos=static_cast<int>(input->readULong(2));
460
3.97k
      f << "cPos=" << cPos << ",";
461
3.97k
      input->seek(pos+38, librevenge::RVNG_SEEK_SET);
462
3.97k
      ascii().addPos(pos);
463
3.97k
      ascii().addNote(f.str().c_str());
464
3.97k
      break;
465
3.97k
    }
466
2.36M
    MouseWrtParserInternal::Paragraph para(i);
467
2.36M
    para.m_paragraph.m_marginsUnit=librevenge::RVNG_POINT;
468
    // note: right margins is defined from left, so must be corrected when we know the page length
469
2.36M
    para.m_paragraph.m_margins[1] = double(input->readLong(2));
470
2.36M
    para.m_paragraph.m_margins[2] = double(input->readLong(2));
471
2.36M
    auto val=static_cast<int>(input->readULong(1));
472
2.36M
    switch (val) {
473
8.51k
    case 0xf: // left
474
8.51k
      break;
475
29.8k
    case 0x10:
476
29.8k
      para.m_paragraph.m_justify = MWAWParagraph::JustificationFull;
477
29.8k
      break;
478
31.1k
    case 0x11:
479
31.1k
      para.m_paragraph.m_justify = MWAWParagraph::JustificationRight;
480
31.1k
      break;
481
52.9k
    case 0x12:
482
52.9k
      para.m_paragraph.m_justify = MWAWParagraph::JustificationCenter;
483
52.9k
      break;
484
5.66k
    case 0x13:
485
5.66k
      f << "justify=rowCol,";
486
5.66k
      break;
487
7.84k
    case 0x14:
488
7.84k
      f << "justify=col,";
489
7.84k
      break;
490
2.22M
    default:
491
2.22M
      if (!val) break;
492
1.17M
      MWAW_DEBUG_MSG(("MouseWrtParser::readParagraphPLCs: unknown justify\n"));
493
1.17M
      f << "#justify=" << std::hex << val << std::dec << ",";
494
2.36M
    }
495
7.08M
    for (int j=0; j<2; ++j) { // fl0=1|7, maybe related to tabs definition
496
4.72M
      val=static_cast<int>(input->readULong(1)); // 1|7
497
4.72M
      if (val) f << "fl" << j << "=" << std::hex << val << std::dec << ",";
498
4.72M
    }
499
2.36M
    val=static_cast<int>(input->readULong(1));
500
2.36M
    switch (val) {
501
9.57k
    case 0xb:
502
9.57k
      break;
503
18.7k
    case 0xc:
504
18.7k
      para.m_paragraph.setInterline(1.1, librevenge::RVNG_PERCENT);
505
18.7k
      break;
506
24.0k
    case 0xd:
507
24.0k
      para.m_paragraph.setInterline(1.5, librevenge::RVNG_PERCENT);
508
24.0k
      break;
509
15.8k
    case 0xe:
510
15.8k
      para.m_paragraph.setInterline(2, librevenge::RVNG_PERCENT);
511
15.8k
      break;
512
2.29M
    default:
513
2.29M
      MWAW_DEBUG_MSG(("MouseWrtParser::readParagraphPLCs: unknown interline\n"));
514
2.29M
      f << "#interline=" << val << ",";
515
2.29M
      break;
516
2.36M
    }
517
2.36M
    val=static_cast<int>(input->readULong(1)); // always 0
518
2.36M
    if (val) f << "fl2=" << val << ",";
519
2.36M
    val=static_cast<int>(input->readULong(1));
520
2.36M
    switch (val) {
521
1.04M
    case 0:
522
1.04M
      break;
523
100k
    case 1:
524
100k
      para.m_picture=true;
525
100k
      f << "picture,";
526
100k
      break;
527
1.22M
    default:
528
1.22M
      MWAW_DEBUG_MSG(("MouseWrtParser::readParagraphPLCs: unknown picture def\n"));
529
1.22M
      f << "#picture=" << val << ",";
530
1.22M
      break;
531
2.36M
    }
532
2.36M
    int lastTabPos=0; // check that the tabulation are in increasing order
533
4.11M
    for (int j=0; j<10; ++j) {
534
4.11M
      val=static_cast<int>(input->readLong(2));
535
4.11M
      if (!val || val<=lastTabPos) break;
536
1.75M
      MWAWTabStop tab;
537
1.75M
      tab.m_alignment=MWAWTabStop::CENTER;
538
1.75M
      tab.m_position=double(val)/72.;
539
1.75M
      para.m_paragraph.m_tabs->push_back(tab);
540
1.75M
      lastTabPos=val;
541
1.75M
    }
542
2.36M
    input->seek(pos+30, librevenge::RVNG_SEEK_SET);
543
2.36M
    val=static_cast<int>(input->readLong(2));
544
2.36M
    if (val) f << "act[tab]=" << val << ",";
545
2.36M
    val=static_cast<int>(input->readULong(1));
546
2.36M
    switch (val) {
547
1.04M
    case 0:
548
1.04M
      para.m_paragraph.m_writingMode=libmwaw::WritingRightTop;
549
1.04M
      break;
550
96.6k
    case 1: // normal writing
551
96.6k
      break;
552
1.21M
    default:
553
1.21M
      MWAW_DEBUG_MSG(("MouseWrtParser::readParagraphPLCs: unknown writing mode\n"));
554
1.21M
      f << "#writing[mode]=" << val << ",";
555
1.21M
      break;
556
2.36M
    }
557
9.45M
    for (int j=0; j<3; ++j) { // always 0?
558
7.08M
      val=static_cast<int>(input->readULong(1));
559
7.08M
      if (val) f << "flA" << j << "=" << val << ",";
560
7.08M
    }
561
2.36M
    f << para.m_paragraph;
562
2.36M
    auto cPos=static_cast<int>(input->readULong(2));
563
2.36M
    f << "cPos=" << cPos << ",";
564
2.36M
    m_state->m_paraPLCMap[cPos]=para;
565
2.36M
    input->seek(pos+38, librevenge::RVNG_SEEK_SET);
566
2.36M
    ascii().addPos(pos);
567
2.36M
    ascii().addNote(f.str().c_str());
568
2.36M
  }
569
3.97k
  return true;
570
3.97k
}
571
572
bool MouseWrtParser::readDocumentInfo(long sz)
573
3.01k
{
574
3.01k
  MWAWInputStreamPtr input = getInput();
575
3.01k
  long pos = input->tell();
576
3.01k
  if (sz<76 || !input->checkPosition(pos+sz)) {
577
151
    MWAW_DEBUG_MSG(("MouseWrtParser::readDocumentInfo: find unexpected size length\n"));
578
151
    return false;
579
151
  }
580
2.86k
  libmwaw::DebugStream f;
581
2.86k
  f << "Entries(DocumentInfo):";
582
2.86k
  int val;
583
2.86k
  f << "unkns=[";
584
8.58k
  for (int i=0; i<2; ++i) { // footer,header
585
    // find 0|18|25, does not seems related to heigth...
586
5.72k
    val=static_cast<int>(input->readULong(2));
587
5.72k
    if (val)
588
4.08k
      f << val << ",";
589
1.64k
    else
590
1.64k
      f << "_,";
591
5.72k
  }
592
2.86k
  f << "],";
593
5.72k
  for (auto &zone : m_state->m_zones) { // header,footer
594
5.72k
    val=static_cast<int>(input->readULong(1));
595
5.72k
    switch (val) {
596
2.27k
    case 0:
597
2.27k
      zone.m_writingHebrew=true;
598
2.27k
      f << "writing[mode]=rt-lb,";
599
2.27k
      break;
600
322
    case 1: // normal writing
601
322
      break;
602
3.12k
    default:
603
3.12k
      MWAW_DEBUG_MSG(("MouseWrtParser::readDocumentInfo: unknown writing mode\n"));
604
3.12k
      f << "#writing[mode]=" << val << ",";
605
3.12k
      break;
606
5.72k
    }
607
5.72k
  }
608
2.86k
  f << "ids=[";
609
8.58k
  for (int i=0; i<2; ++i) { // header,footer
610
5.72k
    val=static_cast<int>(input->readULong(4));
611
5.72k
    if (val)
612
4.93k
      f << std::hex << val << std::dec << ",";
613
794
    else
614
794
      f << "_,";
615
5.72k
  }
616
2.86k
  f << "],";
617
2.86k
  long zoneSize[2];
618
8.58k
  for (int i=0; i<2; ++i) { // header,footer
619
5.72k
    zoneSize[i]=long(input->readULong(4));
620
5.72k
    if (zoneSize[i]) f << "block" << i << "[sz]=" << zoneSize[i] << ",";
621
5.72k
  }
622
8.58k
  for (int i=0; i<2; ++i) { // header,footer, always 0|-1?
623
5.72k
    val=static_cast<int>(input->readLong(4));
624
5.72k
    if (val) f << "f" << i+2 << "=" << val << ",";
625
5.72k
  }
626
8.58k
  for (int i=0; i<2; ++i) { // header,footer
627
5.72k
    long actPos=input->tell();
628
5.72k
    int cPos;
629
5.72k
    if (zoneSize[i]==0 || !readFont(m_state->m_zones[i].m_font, cPos))
630
698
      input->seek(actPos+8, librevenge::RVNG_SEEK_SET);
631
5.02k
    else
632
5.02k
      f << "font" << i << "=[" << m_state->m_zones[i].m_font.getDebugString(getParserState()->m_fontConverter) << "],";
633
5.72k
  }
634
2.86k
  ascii().addDelimiter(input->tell(),'|');
635
2.86k
  if (sz > 76+zoneSize[0]+zoneSize[1] || zoneSize[0]<0 || zoneSize[1]<0) {
636
193
    MWAW_DEBUG_MSG(("MouseWrtParser::readDocumentInfo: problem with the zoneSize\n"));
637
193
    f << "##zoneSize,";
638
193
    input->seek(pos+sz, librevenge::RVNG_SEEK_SET);
639
193
  }
640
2.67k
  else {
641
2.67k
    input->seek(pos+76, librevenge::RVNG_SEEK_SET);
642
8.01k
    for (int i=0; i<2; ++i) {
643
5.34k
      if (zoneSize[i]<=0) continue;
644
5.01k
      m_state->m_zones[i].m_text.setBegin(input->tell());
645
5.01k
      m_state->m_zones[i].m_text.setLength(zoneSize[i]);
646
5.01k
      input->seek(zoneSize[i], librevenge::RVNG_SEEK_CUR);
647
5.01k
    }
648
2.67k
  }
649
650
2.86k
  ascii().addPos(pos);
651
2.86k
  ascii().addNote(f.str().c_str());
652
2.86k
  return true;
653
2.86k
}
654
655
int MouseWrtParser::computeNumPages()
656
6.20k
{
657
6.20k
  if (!m_state->m_text.valid()) return 1;
658
5.60k
  MWAWInputStreamPtr input = getInput();
659
5.60k
  int numPages=1;
660
5.60k
  auto pIt=m_state->m_paraPLCMap.begin();
661
5.60k
  long const beginPos=m_state->m_text.begin();
662
194k
  while (pIt!=m_state->m_paraPLCMap.end()) {
663
192k
    if (pIt->second.m_picture) {
664
15.9k
      ++pIt;
665
15.9k
      continue;
666
15.9k
    }
667
176k
    long actPos=beginPos+(pIt++)->first;
668
176k
    long lastPos=(pIt!=m_state->m_paraPLCMap.end()) ? beginPos+pIt->first : m_state->m_text.end();
669
176k
    if (lastPos>m_state->m_text.end()) {
670
3.41k
      MWAW_DEBUG_MSG(("MouseWrtParser::computeNumPages: oops, problem with some plc pos\n"));
671
3.41k
      break;
672
3.41k
    }
673
173k
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
674
4.63M
    for (long cPos=actPos; cPos<lastPos; ++cPos) {
675
4.46M
      if (input->readULong(1)==0xd7)
676
7.41k
        ++numPages;
677
4.46M
    }
678
173k
  }
679
5.60k
  return numPages;
680
6.20k
}
681
682
////////////////////////////////////////////////////////////
683
// read the print info
684
////////////////////////////////////////////////////////////
685
bool MouseWrtParser::readPrintInfo()
686
491
{
687
491
  MWAWInputStreamPtr input = getInput();
688
491
  long pos = input->tell();
689
491
  libmwaw::DebugStream f;
690
  // print info
691
491
  libmwaw::PrinterInfo info;
692
491
  if (!info.read(input)) return false;
693
274
  f << "Entries(PrintInfo):"<< info;
694
695
274
  MWAWVec2i paperSize = info.paper().size();
696
274
  MWAWVec2i pageSize = info.page().size();
697
274
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
698
165
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
699
700
  // define margin from print info
701
136
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
702
136
  MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
703
704
  // move margin left | top
705
136
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
706
136
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
707
136
  lTopMargin -= MWAWVec2i(decalX, decalY);
708
136
  rBotMargin += MWAWVec2i(decalX, decalY);
709
710
  // decrease right | bottom
711
136
  int rightMarg = rBotMargin.x() -10;
712
136
  if (rightMarg < 0) rightMarg=0;
713
136
  int botMarg = rBotMargin.y() -50;
714
136
  if (botMarg < 0) botMarg=0;
715
716
136
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
717
136
  getPageSpan().setMarginBottom(botMarg/72.0);
718
136
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
719
136
  getPageSpan().setMarginRight(rightMarg/72.0);
720
136
  getPageSpan().setFormLength(paperSize.y()/72.);
721
136
  getPageSpan().setFormWidth(paperSize.x()/72.);
722
723
136
  ascii().addPos(pos);
724
136
  ascii().addNote(f.str().c_str());
725
136
  input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
726
136
  if (long(input->tell()) != pos+0x78) {
727
0
    MWAW_DEBUG_MSG(("MouseWrtParser::readPrintInfo: file is too short\n"));
728
0
    return false;
729
0
  }
730
136
  ascii().addPos(input->tell());
731
732
136
  return true;
733
136
}
734
735
////////////////////////////////////////////////////////////
736
// send the data
737
////////////////////////////////////////////////////////////
738
bool MouseWrtParser::sendMainZone()
739
6.20k
{
740
6.20k
  MWAWListenerPtr listener=getMainListener();
741
6.20k
  if (!listener) {
742
0
    MWAW_DEBUG_MSG(("MouseWrtParser::sendMainZone: can not find the listener\n"));
743
0
    return false;
744
0
  }
745
6.20k
  MWAWInputStreamPtr input = getInput();
746
6.20k
  if (!m_state->m_text.valid() || !input->checkPosition(m_state->m_text.end())) {
747
608
    listener->insertChar(' ');
748
608
    return true;
749
608
  }
750
5.60k
  long begPos = m_state->m_text.begin(), pos=begPos;
751
5.60k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
752
5.60k
  auto N=static_cast<int>(m_state->m_text.length());
753
5.60k
  libmwaw::DebugStream f;
754
5.60k
  f << "Entries(Text):";
755
5.60k
  double const pageWidth=72. * getPageSpan().getPageWidth();
756
5.60k
  int actPage=1;
757
5.60k
  newPage(actPage);
758
4.58M
  for (int i=0; i<N; ++i) {
759
4.58M
    auto pIt=m_state->m_paraPLCMap.find(i);
760
4.58M
    if (pIt!=m_state->m_paraPLCMap.end()) {
761
178k
      if (i!=0) {
762
174k
        ascii().addPos(pos);
763
174k
        ascii().addNote(f.str().c_str());
764
174k
        pos=input->tell();
765
174k
        f.str("");
766
174k
        f << "Text:";
767
174k
      }
768
178k
      auto const &para=pIt->second;
769
178k
      f << "[P" << para.m_id << "]";
770
      // time to send the paragraph, so first update the right margins
771
178k
      MWAWParagraph paragraph=para.m_paragraph;
772
178k
      if (*(paragraph.m_margins[2])>pageWidth) {
773
80.4k
        f << "#";
774
80.4k
        paragraph.m_margins[2]=0;
775
80.4k
      }
776
97.8k
      else
777
97.8k
        paragraph.m_margins[2]=pageWidth-*paragraph.m_margins[2];
778
178k
      if (para.m_picture) paragraph.m_justify = MWAWParagraph::JustificationRight;
779
178k
      listener->setParagraph(paragraph);
780
178k
      if (para.m_picture) {
781
15.0k
        f << "[picture],";
782
15.0k
        ++pIt;
783
15.0k
        long endPos=pIt==m_state->m_paraPLCMap.end() ? m_state->m_text.end() : begPos+pIt->first;
784
15.0k
        if (endPos<=input->tell()) { // check that we do not go backward
785
180
          f << "###";
786
180
          MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: can not compute the end of picture pos, stop!!!\n"));
787
180
          break;
788
180
        }
789
14.9k
        long actPos=input->tell();
790
14.9k
        bool ok=endPos-actPos>9;
791
14.9k
        if (ok) {
792
          // look for pict
793
5.17k
          auto dSz=static_cast<int>(input->readULong(2));
794
5.17k
          if (dSz+9>endPos-actPos || dSz+12<endPos-actPos) {
795
4.72k
            f << "#pict?";
796
4.72k
            MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: no sure that this is a picture\n"));
797
4.72k
            input->seek(endPos-9, librevenge::RVNG_SEEK_SET);
798
4.72k
          }
799
446
          else
800
446
            input->seek(actPos+dSz, librevenge::RVNG_SEEK_SET);
801
5.17k
          long pictSz=input->tell()-actPos;
802
5.17k
          int dim[4];
803
20.6k
          for (auto &d : dim) d=static_cast<int>(input->readLong(2));
804
5.17k
          MWAWBox2i box(MWAWVec2i(dim[1],dim[0]),MWAWVec2i(dim[3],dim[2]));
805
5.17k
          f << "box=" << box << ",";
806
5.17k
          if (box.size()[0]<0 || box.size()[1]<0 || box.size()[0]>2000 || box.size()[1]>2000) {
807
2.71k
            MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: the bdbox is bad\n"));
808
2.71k
            f << "###";
809
2.71k
            ok=false;
810
2.71k
          }
811
2.46k
          else {
812
2.46k
            librevenge::RVNGBinaryData data;
813
2.46k
            input->seek(actPos, librevenge::RVNG_SEEK_SET);
814
2.46k
            input->readDataBlock(pictSz, data);
815
2.46k
            MWAWEmbeddedObject object(data);
816
2.46k
            MWAWPosition position(MWAWVec2f(0,0), MWAWVec2f(box.size()), librevenge::RVNG_POINT);
817
2.46k
            position.m_anchorTo=MWAWPosition::Char;
818
2.46k
            listener->insertPicture(position, object);
819
#ifdef DEBUG_WITH_FILES
820
            static int volatile pictName = 0;
821
            libmwaw::DebugStream f2;
822
            f2 << "Pict-" << ++pictName << ".pct";
823
            libmwaw::Debug::dumpFile(data, f2.str().c_str());
824
#endif
825
2.46k
            ascii().skipZone(actPos, actPos+pictSz-1);
826
2.46k
          }
827
5.17k
        }
828
829
14.9k
        if (ok || endPos-actPos>20) {
830
4.55k
          listener->insertEOL();
831
4.55k
          ascii().addPos(pos);
832
4.55k
          ascii().addNote(f.str().c_str());
833
4.55k
          pos=input->tell();
834
4.55k
          f.str("");
835
4.55k
          f << "Text:";
836
4.55k
          input->seek(endPos, librevenge::RVNG_SEEK_SET);
837
4.55k
          i=int(endPos-begPos-1); // will be endPos-begPos after
838
4.55k
          continue;
839
4.55k
        }
840
14.9k
      }
841
178k
    }
842
4.57M
    auto fIt=m_state->m_charPLCMap.find(i);
843
4.57M
    if (fIt!=m_state->m_charPLCMap.end()) {
844
112k
      listener->setFont(fIt->second);
845
112k
      f << "[" << fIt->second.getDebugString(getParserState()->m_fontConverter) << "]";
846
112k
    }
847
4.57M
    auto c=static_cast<unsigned char>(input->readULong(1));
848
4.57M
    f << c;
849
4.57M
    switch (c) {
850
46.7k
    case 0x9:
851
46.7k
      listener->insertTab();
852
46.7k
      break;
853
53.3k
    case 0xd:
854
53.3k
      listener->insertEOL();
855
53.3k
      ascii().addPos(pos);
856
53.3k
      ascii().addNote(f.str().c_str());
857
53.3k
      pos=input->tell();
858
53.3k
      f.str("");
859
53.3k
      f << "Text:";
860
53.3k
      break;
861
16.5k
    case 0xd7: {
862
16.5k
      newPage(++actPage);
863
16.5k
      long actPos=input->tell();
864
16.5k
      if (i+1!=N && input->readULong(1)==0xd) {
865
145
        ascii().addPos(pos);
866
145
        ascii().addNote(f.str().c_str());
867
145
        pos=input->tell();
868
145
        f.str("");
869
145
        f << "Text:";
870
145
        ++i;
871
145
      }
872
16.4k
      else
873
16.4k
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
874
16.5k
      break;
875
0
    }
876
4.45M
    default:
877
4.45M
      listener->insertCharacter(c);
878
4.45M
      break;
879
4.57M
    }
880
4.57M
  }
881
5.60k
  if (input->tell()!=pos) {
882
4.74k
    ascii().addPos(pos);
883
4.74k
    ascii().addNote(f.str().c_str());
884
4.74k
  }
885
5.60k
  return true;
886
5.60k
}
887
888
bool MouseWrtParser::sendZone(int zoneId)
889
5.01k
{
890
5.01k
  if (zoneId < 0 || zoneId >= 2) {
891
0
    MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: invalid zone %d\n", zoneId));
892
0
    return false;
893
0
  }
894
5.01k
  MWAWListenerPtr listener=getMainListener();
895
5.01k
  if (!listener) {
896
0
    MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: can not find the listener\n"));
897
0
    return false;
898
0
  }
899
5.01k
  auto const &zone=m_state->m_zones[zoneId];
900
5.01k
  if (!zone.m_text.valid()) return true;
901
5.01k
  if (zone.m_writingHebrew) {
902
1.76k
    MWAWParagraph para;
903
1.76k
    para.m_writingMode=libmwaw::WritingRightTop;
904
1.76k
    listener->setParagraph(para);
905
1.76k
  }
906
5.01k
  listener->setFont(zone.m_font);
907
5.01k
  MWAWInputStreamPtr input = getInput();
908
5.01k
  libmwaw::DebugStream f;
909
5.01k
  f << "Entries(Text):" << (zoneId==0 ? "header" : "footer") << ",";
910
5.01k
  input->seek(zone.m_text.begin(), librevenge::RVNG_SEEK_SET);
911
5.01k
  auto N=static_cast<int>(zone.m_text.length());
912
21.0M
  for (long i=0; i<N ; ++i) {
913
21.0M
    if (input->isEnd()) {
914
3.19k
      MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: oops the text length seems too big\n"));
915
3.19k
      f << "###";
916
3.19k
      break;
917
3.19k
    }
918
21.0M
    auto c=static_cast<unsigned char>(input->readULong(1));
919
21.0M
    f << c;
920
21.0M
    switch (c) {
921
122k
    case 0x9:
922
122k
      MWAW_DEBUG_MSG(("MouseWrtParser::sendZone: oops unexpected tab\n"));
923
122k
      listener->insertChar(' ');
924
122k
      break;
925
149k
    case 0xd:
926
149k
      if (i+1==N)
927
59
        break;
928
149k
      listener->insertEOL();
929
149k
      break;
930
20.7M
    default:
931
20.7M
      listener->insertCharacter(c);
932
20.7M
      break;
933
21.0M
    }
934
21.0M
  }
935
5.01k
  ascii().addPos(zone.m_text.begin());
936
5.01k
  ascii().addNote(f.str().c_str());
937
5.01k
  return true;
938
5.01k
}
939
940
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: