Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/WriterPlsParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cstring>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWCell.hxx"
43
#include "MWAWTextListener.hxx"
44
#include "MWAWFont.hxx"
45
#include "MWAWFontConverter.hxx"
46
#include "MWAWHeader.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWPictMac.hxx"
50
#include "MWAWPrinter.hxx"
51
#include "MWAWSection.hxx"
52
#include "MWAWSubDocument.hxx"
53
#include "MWAWTable.hxx"
54
55
#include "WriterPlsParser.hxx"
56
57
/** Internal: the structures of a WriterPlsParser */
58
namespace WriterPlsParserInternal
59
{
60
//! Page informations
61
struct PageInfo {
62
  PageInfo()
63
4.06k
    : m_firstLine(0)
64
4.06k
    , m_height(0)
65
4.06k
    , m_heightFromBegin(0)
66
4.06k
  {
67
4.06k
    std::memset(m_unknown, 0, sizeof(m_unknown));
68
4.06k
  }
69
  friend std::ostream &operator<<(std::ostream &o, PageInfo const &p)
70
0
  {
71
0
    o << "firstLine=" << p.m_firstLine
72
0
      << ", height=" << p.m_height
73
0
      << ", height[fromStart]=" << p.m_heightFromBegin;
74
0
    if (p.m_unknown[0] != 1) o << ", unkn0=" << p.m_unknown[0];
75
0
    if (p.m_unknown[1]) o << ", unkn1=" << p.m_unknown[1];
76
0
    return o;
77
0
  }
78
79
  int m_firstLine;
80
  int m_unknown[2]; // 1 0
81
  int m_height, m_heightFromBegin;
82
};
83
84
//! Column informations
85
struct ColumnInfo {
86
  ColumnInfo()
87
3.44k
    : m_firstLine(0)
88
3.44k
    , m_height(0)
89
3.44k
    , m_col(0)
90
3.44k
    , m_numCol(1)
91
3.44k
  {
92
3.44k
    std::memset(m_unknown, 0, sizeof(m_unknown));
93
3.44k
  }
94
  friend std::ostream &operator<<(std::ostream &o, ColumnInfo const &c)
95
0
  {
96
0
    o << "firstLine=" << c.m_firstLine
97
0
      << ", col=" << c.m_col << "/" << c.m_numCol
98
0
      << ", height=" << c.m_height
99
0
      << ", dim?=" << c.m_unknown[3];
100
0
    if (c.m_unknown[0]) o << ", unkn0=" << c.m_unknown[0];
101
0
    if (c.m_unknown[1] != 1) o << ", unkn1=" << c.m_unknown[1];
102
0
    if (c.m_unknown[2]) o << ", unkn2=" << c.m_unknown[2];
103
0
    return o;
104
0
  }
105
106
  int m_firstLine;
107
  int m_unknown[4]; // 0 1 0
108
  int m_height, m_col, m_numCol;
109
};
110
111
//! Column informations in a table
112
struct ColumnTableInfo {
113
  ColumnTableInfo()
114
89.7M
    : m_height(0)
115
89.7M
    , m_numData(0)
116
89.7M
    , m_flags(0)
117
89.7M
  {
118
179M
    for (auto &col : m_colX) col=0;
119
269M
    for (auto &text : m_textX) text=0;
120
89.7M
  }
121
  friend std::ostream &operator<<(std::ostream &o, ColumnTableInfo const &c)
122
0
  {
123
0
    o << "height=" << c.m_height
124
0
      << ", numData=" << c.m_numData
125
0
      << ", colX=" <<  c.m_colX[0] << "<->" << c.m_colX[1]
126
0
      << ", textX=" <<  c.m_textX[0] << "<->" << c.m_textX[1];
127
0
    if (c.m_textX[0] !=  c.m_textX[2])
128
0
      o << ", textX[begin?]=" << c.m_textX[2];
129
0
    if (c.m_flags) o << ", flags=" << c.m_flags;
130
0
    return o;
131
0
  }
132
133
  int m_height;
134
  int m_numData;
135
  int m_colX[2]; // x : begin and end pos
136
  int m_textX[3]; // x : begin|end|begin pos
137
  int m_flags; // 0
138
};
139
140
//! Paragraph informations
141
struct ParagraphInfo {
142
  ParagraphInfo()
143
142k
    : m_pos(0)
144
142k
    , m_type(-2)
145
142k
    , m_height(0)
146
142k
    , m_height2(0)
147
142k
    , m_width(0)
148
142k
    , m_numLines(0)
149
142k
    , m_linesHeight()
150
142k
    , m_unknowns()
151
142k
  {
152
855k
    for (auto &fl : m_flags) fl=0;
153
142k
  }
154
  int getType() const
155
427k
  {
156
427k
    if (m_type >= 8) return (m_type & 0x7);
157
269k
    return m_type;
158
427k
  }
159
  friend std::ostream &operator<<(std::ostream &o, ParagraphInfo const &p)
160
0
  {
161
0
    int type = p.m_type;
162
0
    bool typeFlag = false;
163
0
    if (type >= 8) {
164
0
      typeFlag = true;
165
0
      type &= 7;
166
0
    }
167
0
    switch (type) {
168
0
    case 0:
169
0
      o << "text";
170
0
      break;
171
0
    case 1:
172
0
      o << "section";
173
0
      break;
174
0
    case 2:
175
0
      o << "text2";
176
0
      break;
177
0
    case 3:
178
0
      o << "colBreak";
179
0
      break;
180
0
    case 4:
181
0
      o << "graphics";
182
0
      break;
183
0
    case 5:
184
0
      o << "table";
185
0
      break;
186
0
187
0
    case -1:
188
0
      o << "empty";
189
0
      break;
190
0
    case -2:
191
0
      break;
192
0
    default:
193
0
      o << "type=" << type;
194
0
      break;
195
0
    }
196
0
    if (typeFlag) o << "[in table],";
197
0
    else o << ",";
198
0
199
0
    if (p.m_pos) o << "pos=" << std::hex << p.m_pos << std::dec << ",";
200
0
    o << "h=" << p.m_height << ",";
201
0
    if (p.m_height2 != p.m_height) o << "h[next]=" << p.m_height2 << ",";
202
0
    if (p.m_width) o << "w=" << p.m_width << ",";
203
0
    if (type == 5) {
204
0
      o << "numCols=" << p.m_numLines << ",";
205
0
      if (!p.m_linesHeight.empty()) {
206
0
        o << "numDataByCols=[";
207
0
        for (auto i : p.m_linesHeight)
208
0
          o << i << ",";
209
0
        o << "],";
210
0
      }
211
0
    }
212
0
    else {
213
0
      if (p.m_numLines) o << "numLines=" << p.m_numLines << ",";
214
0
      if (!p.m_linesHeight.empty()) {
215
0
        o << "lineH=[";
216
0
        for (auto i : p.m_linesHeight)
217
0
          o << i << ",";
218
0
        o << "],";
219
0
      }
220
0
    }
221
0
    for (int i= 0; i < 6; i++) {
222
0
      if (!p.m_flags[i]) continue;
223
0
      o << "f" << i << "=" << std::hex << p.m_flags[i] << std::dec << ",";
224
0
    }
225
0
    if (p.m_unknowns.size()) {
226
0
      o << "unkn=[";
227
0
      for (auto unk : p.m_unknowns) {
228
0
        if (unk)
229
0
          o << unk << ",";
230
0
        else
231
0
          o << "_,";
232
0
      }
233
0
      o << "],";
234
0
    }
235
0
    return o;
236
0
  }
237
238
  long m_pos;
239
  int m_type;
240
241
  int m_height, m_height2, m_width, m_numLines;
242
  std::vector<int> m_linesHeight;
243
  int m_flags[6];
244
  std::vector<int> m_unknowns;
245
};
246
247
//! Windows informations
248
struct WindowsInfo {
249
  struct Zone {
250
    Zone()
251
1.50M
      : m_number(0)
252
1.50M
      , m_size(0)
253
1.50M
      , m_width(0)
254
1.50M
    {
255
4.52M
      for (auto &unk : m_unknown) unk = 0;
256
1.50M
    }
257
    bool empty() const
258
0
    {
259
0
      return m_number==0 && m_size==0;
260
0
    }
261
    friend std::ostream &operator<<(std::ostream &o, Zone const &z)
262
0
    {
263
0
      o << "N=" << z.m_number << ", sz=" << std::hex << z.m_size << std::dec;
264
0
      o << ", w=" << z.m_width;
265
0
      for (int i = 0; i < 3; i++) {
266
0
        if (!z.m_unknown[i]) continue;
267
0
        o << ", f" << i << "=" << z.m_unknown[i];
268
0
      }
269
0
      return o;
270
0
    }
271
    int m_number;
272
    int m_size;
273
    int m_width;
274
    int m_unknown[3];
275
  };
276
277
  friend std::ostream &operator<<(std::ostream &o, WindowsInfo const &w);
278
279
  WindowsInfo()
280
180k
    : m_pageDim()
281
180k
    , m_headerY(0)
282
180k
    , m_footerY(0)
283
180k
    , m_pages()
284
180k
    , m_columns()
285
180k
    , m_paragraphs()
286
180k
  {
287
180k
  }
288
289
  bool dimensionInvalid() const
290
35.1k
  {
291
35.1k
    return (m_pageDim.x() < 0 || m_pageDim.y() < 0 ||
292
33.8k
            m_headerY < 0 || m_footerY < 0 ||
293
33.1k
            m_headerY+m_footerY > m_pageDim.y());
294
35.1k
  }
295
296
  bool getColumnLimitsFor(int line, std::vector<int> &listPos);
297
298
  MWAWVec2i m_pageDim;
299
  int m_headerY, m_footerY;
300
  std::vector<PageInfo> m_pages;
301
  std::vector<ColumnInfo> m_columns;
302
  std::vector<ParagraphInfo> m_paragraphs;
303
304
  // ????, pages, columns, parag, ???, ???, ???
305
  Zone m_zone[7];
306
};
307
308
bool WindowsInfo::getColumnLimitsFor(int line, std::vector<int> &listPos)
309
29.0k
{
310
29.0k
  listPos.resize(0);
311
312
29.0k
  size_t numColumns = m_columns.size();
313
29.0k
  size_t firstColumn = 0; // initialized to make clang analyzer happier
314
29.0k
  int numCols = 0;
315
30.9k
  for (size_t i = 0; i < numColumns; i++) {
316
2.54k
    if (m_columns[i].m_firstLine == line+2) {
317
141
      numCols=m_columns[i].m_numCol;
318
141
      firstColumn = i;
319
141
      if (numCols > int(unsigned(numColumns - firstColumn)))
320
88
        numCols = int(unsigned(numColumns - firstColumn));
321
141
      if (numCols <= 1 || m_columns[i].m_col != 1) return false;
322
60
      break;
323
141
    }
324
2.39k
    if (m_columns[i].m_firstLine > line+2)
325
585
      return true;
326
2.39k
  }
327
28.4k
  if (numCols <= 1)
328
28.3k
    return true;
329
330
60
  size_t numPara = m_paragraphs.size();
331
60
  listPos.resize(size_t(numCols));
332
150
  for (size_t i = 0; i < size_t(numCols); i++) {
333
150
    ColumnInfo const &colInfo =  m_columns[firstColumn++];
334
150
    int l = colInfo.m_firstLine-1;
335
150
    if (l < 0 || l >= static_cast<int>(numPara)) {
336
44
      MWAW_DEBUG_MSG(("WindowsInfo::getColumnLimitsFor: pb with line position\n"));
337
44
      return false;
338
44
    }
339
106
    if (i && m_paragraphs[size_t(l)].getType() != 3) {
340
16
      MWAW_DEBUG_MSG(("WindowsInfo::getColumnLimitsFor: can not find cols break\n"));
341
16
      return false;
342
16
    }
343
344
90
    listPos[i] = (i == 0) ? l-1 : l;
345
90
  }
346
0
  return true;
347
60
}
348
349
std::ostream &operator<<(std::ostream &o, WindowsInfo const &w)
350
0
{
351
0
  if (w.m_pageDim.x() || w.m_pageDim.y())
352
0
    o << "pagesDim=" << w.m_pageDim << ",";
353
0
  if (w.m_headerY) o << "header[Height]=" << w.m_headerY << ",";
354
0
  if (w.m_footerY) o << "footer[Height]=" << w.m_footerY << ",";
355
0
  for (int i = 0; i < 7; i++) {
356
0
    if (w.m_zone[i].empty()) continue;
357
0
    switch (i) {
358
0
    case 1:
359
0
      o << "zonePages";
360
0
      break;
361
0
    case 2:
362
0
      o << "zoneCols?";
363
0
      break;
364
0
    case 3:
365
0
      o << "zoneParag";
366
0
      break;
367
0
    default:
368
0
      o << "unkZone" << i;
369
0
      break;
370
0
    }
371
0
    o << "=[" << w.m_zone[i] << "], ";
372
0
  }
373
0
  return o;
374
0
}
375
376
////////////////////////////////////////
377
/** Internal: class to store the font properties */
378
struct Font {
379
  Font()
380
4.58M
    : m_font()
381
4.58M
    , m_firstChar(0)
382
4.58M
  {
383
4.58M
  }
384
385
  //! operator<<
386
  friend std::ostream &operator<<(std::ostream &o, Font const &f)
387
0
  {
388
0
    if (f.m_firstChar) o << "firstChar=" << f.m_firstChar << ",";
389
0
    return o;
390
0
  }
391
  //! the font
392
  MWAWFont m_font;
393
  //! the first character
394
  int m_firstChar;
395
};
396
397
////////////////////////////////////////
398
/** Internal: class to store the line  properties */
399
struct Line {
400
  Line()
401
175M
    : m_firstChar(0)
402
175M
    , m_height(0)
403
175M
    , m_width(0)
404
175M
    , m_maxFontSize(0)
405
175M
  {
406
701M
    for (auto &fl : m_flags) fl=0;
407
175M
  }
408
409
  //! operator<<
410
  friend std::ostream &operator<<(std::ostream &o, Line const &l)
411
0
  {
412
0
    if (l.m_firstChar) o << "firstChar=" << l.m_firstChar << ",";
413
0
    o << "height=" << l.m_height << ", width=" << l.m_width;
414
0
    for (int i = 0; i < 4; i++) {
415
0
      if (!l.m_flags[i]) continue;
416
0
      o << ", lF" << i << "=" << std::hex << l.m_flags[i] << std::dec;
417
0
    }
418
0
    return o;
419
0
  }
420
  //! the first character
421
  int m_firstChar;
422
  int m_height/** the height */, m_width /** the width */;
423
  int m_maxFontSize; /** the maximum font size */
424
  //! some flag
425
  int m_flags[4]; // flags[0]  a small number : a,b,c
426
};
427
428
////////////////////////////////////////
429
/** Internal: class to store the Graphic properties */
430
struct GraphicInfo {
431
  GraphicInfo()
432
12.5M
    : m_width(0)
433
12.5M
    , m_graphicWidth(0)
434
12.5M
  {
435
88.1M
    for (auto &fl : m_flags) fl=0;
436
12.5M
  }
437
438
  //! operator<<
439
  friend std::ostream &operator<<(std::ostream &o, GraphicInfo const &g)
440
0
  {
441
0
    o << "width=" << g.m_graphicWidth << ", width[line]=" << g.m_width;
442
0
    for (int i = 0; i < 6; i++) { // m_flags[6] seems to be junk
443
0
      if (!g.m_flags[i]) continue;
444
0
      o << ", gF" << i << "=" << std::hex << g.m_flags[i] << std::dec;
445
0
    }
446
0
    return o;
447
0
  }
448
  //! the first character
449
  int m_width/** the line width */, m_graphicWidth /** the graphic width */;
450
  //! some flag
451
  int m_flags[7];
452
};
453
454
////////////////////////////////////////
455
/** Internal: class to store the Section properties */
456
struct SectionInfo {
457
  SectionInfo()
458
19.6M
    : m_numCol(0)
459
19.6M
  {
460
58.9M
    for (auto &dim : m_dim) dim = 0;
461
78.6M
    for (auto &fl : m_flags) fl = 0;
462
19.6M
  }
463
464
  bool empty() const
465
19.6M
  {
466
19.6M
    if (m_numCol) return false;
467
19.4M
    for (auto dim : m_dim)
468
58.4M
      if (dim) return false;
469
19.4M
    for (auto fl : m_flags)
470
77.8M
      if (fl) return false;
471
19.4M
    return true;
472
19.4M
  }
473
  //! operator<<
474
  friend std::ostream &operator<<(std::ostream &o, SectionInfo const &s)
475
0
  {
476
0
    if (s.m_numCol) o << "numCols?=" << s.m_numCol << ",";
477
0
    o << "dim?=[";
478
0
    for (auto dim : s.m_dim)
479
0
      o << dim << ",";
480
0
    o << "],";
481
0
    for (int i = 0; i < 4; i++) {
482
0
      if (!s.m_flags[i]) continue;
483
0
      o << ", sF" << i << "=" << std::hex << s.m_flags[i] << std::dec;
484
0
    }
485
0
    return o;
486
0
  }
487
  //! the number of columns(?)
488
  int m_numCol;
489
  //! unknown dimension
490
  int m_dim[3];
491
  //! some flag
492
  int m_flags[4];
493
};
494
495
////////////////////////////////////////
496
/** Internal: class to store the beginning of all paragraph data */
497
struct ParagraphData {
498
  //! Constructor
499
  ParagraphData()
500
716k
    : m_type(-1)
501
716k
    , m_typeFlag(0)
502
716k
    , m_height(0)
503
716k
    , m_width(0)
504
716k
    , m_unknown(0)
505
716k
    , m_text("")
506
716k
    , m_fonts()
507
716k
    , m_endPos(0)
508
716k
  {
509
1.43M
    for (auto &indent : m_indent) indent=0;
510
1.43M
    for (auto &numData : m_numData) numData=0;
511
716k
  }
512
  //! operator<<
513
  friend std::ostream &operator<<(std::ostream &o, ParagraphData const &p)
514
0
  {
515
0
    switch (p.m_type) {
516
0
    case 0:
517
0
      o << "text";
518
0
      break;
519
0
    case 1:
520
0
      o << "section";
521
0
      break; // checkme find only one time before a colbreak
522
0
    case 2:
523
0
      o << "text2";
524
0
      break;  // what is the difference with 1
525
0
    case 3:
526
0
      o << "colBreak";
527
0
      break;  // find only one time to change column
528
0
    case 4:
529
0
      o << "graphic";
530
0
      break;
531
0
    case 5:
532
0
      o << "table";
533
0
      break;
534
0
    default:
535
0
      o << "type=" << p.m_type;
536
0
      break;
537
0
    }
538
0
    switch (p.m_typeFlag) {
539
0
    case 0:
540
0
      break;
541
0
    case 0x80:
542
0
      o << "[in table]";
543
0
      break;
544
0
    default:
545
0
      o << "[" << std::hex << p.m_typeFlag << std::dec << "],";
546
0
    }
547
0
    o << ",";
548
0
549
0
    o << "height=" << p.m_height << ",";
550
0
    o << "witdh=" << p.m_width << ",";
551
0
    if (p.m_indent[0]) o << "indent[left]=" << p.m_indent[0] << ",";
552
0
    if (p.m_indent[1] != p.m_indent[0])
553
0
      o << "indent[firstPos]=" << p.m_indent[1] << ",";
554
0
    if (p.m_text.length()) o << "text='" << p.m_text << "',";
555
0
    if (p.m_type==5) o << "numData[total]=" << p.m_unknown << ",";
556
0
    else o << "unkn=" << p.m_unknown << ","; /* in text2: often 1, but can be 5|13|25|29 */
557
0
    return o;
558
0
  }
559
560
  int m_type, m_typeFlag;
561
  int m_height, m_width;
562
  int m_indent[2]; // left indent and ?
563
  int m_unknown;
564
565
  std::string m_text;
566
  std::vector<Font> m_fonts;
567
568
  long m_endPos; // end of the data ( except if there is auxilliary data )
569
  int m_numData[2]; // number of data[1] ( always font?), data[2]
570
};
571
572
////////////////////////////////////////
573
//! Internal: the state of a WriterPlsParser
574
struct State {
575
  //! constructor
576
  State()
577
48.4k
    : m_actPage(0)
578
48.4k
    , m_numPages(0)
579
48.4k
    , m_headerHeight(0)
580
48.4k
    , m_footerHeight(0)
581
48.4k
  {
582
48.4k
  }
583
584
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
585
586
  //! the information ( 0: main, 1: header, 2: footer)
587
  WindowsInfo m_windows[3];
588
589
  int m_headerHeight /** the header height if known */,
590
      m_footerHeight /** the footer height if known */;
591
};
592
593
////////////////////////////////////////
594
//! Internal: the subdocument of a WriterPlsParser
595
class SubDocument final : public MWAWSubDocument
596
{
597
public:
598
  SubDocument(WriterPlsParser &pars, MWAWInputStreamPtr const &input, int zoneId)
599
78
    : MWAWSubDocument(&pars, input, MWAWEntry()), m_id(zoneId)
600
78
  {
601
78
  }
602
603
  //! destructor
604
0
  ~SubDocument() final {}
605
606
  //! operator!=
607
  bool operator!=(MWAWSubDocument const &doc) const final
608
0
  {
609
0
    if (MWAWSubDocument::operator!=(doc)) return true;
610
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
611
0
    if (!sDoc) return true;
612
0
    if (m_id != sDoc->m_id) return true;
613
0
    return false;
614
0
  }
615
616
  //! the parser function
617
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
618
619
protected:
620
  //! the subdocument id
621
  int m_id;
622
};
623
624
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
625
78
{
626
78
  if (!listener.get()) {
627
0
    MWAW_DEBUG_MSG(("WriterPlsParserInternal::SubDocument::parse: no listener\n"));
628
0
    return;
629
0
  }
630
78
  if (m_id != 1 && m_id != 2) {
631
0
    MWAW_DEBUG_MSG(("WriterPlsParserInternal::SubDocument::parse: unknown zone\n"));
632
0
    return;
633
0
  }
634
78
  auto *parser=dynamic_cast<WriterPlsParser *>(m_parser);
635
78
  if (!parser) {
636
0
    MWAW_DEBUG_MSG(("WriterPlsParserInternal::SubDocument::parse: no parser\n"));
637
0
    return;
638
0
  }
639
640
78
  long pos = m_input->tell();
641
78
  parser->sendWindow(m_id);
642
78
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
643
78
}
644
}
645
646
////////////////////////////////////////////////////////////
647
// constructor/destructor, ...
648
////////////////////////////////////////////////////////////
649
WriterPlsParser::WriterPlsParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
650
20.5k
  : MWAWTextParser(input, rsrcParser, header)
651
20.5k
  , m_state()
652
20.5k
{
653
20.5k
  init();
654
20.5k
}
655
656
WriterPlsParser::~WriterPlsParser()
657
20.5k
{
658
20.5k
}
659
660
void WriterPlsParser::init()
661
20.5k
{
662
20.5k
  resetTextListener();
663
20.5k
  setAsciiName("main-1");
664
665
20.5k
  m_state.reset(new WriterPlsParserInternal::State);
666
667
  // reduce the margin (in case, the page is not defined)
668
20.5k
  getPageSpan().setMargins(0.1);
669
20.5k
}
670
671
////////////////////////////////////////////////////////////
672
// position and height
673
////////////////////////////////////////////////////////////
674
double WriterPlsParser::getTextHeight() const
675
3.96k
{
676
3.96k
  return getPageSpan().getPageLength()-m_state->m_headerHeight/72.0-m_state->m_footerHeight/72.0;
677
3.96k
}
678
679
////////////////////////////////////////////////////////////
680
// new page
681
////////////////////////////////////////////////////////////
682
void WriterPlsParser::newPage(int number)
683
6.87k
{
684
6.87k
  if (number <= m_state->m_actPage || number > m_state->m_numPages)
685
4.45k
    return;
686
687
4.83k
  while (m_state->m_actPage < number) {
688
2.41k
    m_state->m_actPage++;
689
2.41k
    if (!getTextListener() || m_state->m_actPage == 1)
690
2.41k
      continue;
691
1
    getTextListener()->insertBreak(MWAWTextListener::PageBreak);
692
1
  }
693
2.41k
}
694
695
696
697
////////////////////////////////////////////////////////////
698
// the parser
699
////////////////////////////////////////////////////////////
700
void WriterPlsParser::parse(librevenge::RVNGTextInterface *docInterface)
701
7.33k
{
702
7.33k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
703
7.33k
  bool ok = true;
704
7.33k
  try {
705
    // create the asciiFile
706
7.33k
    ascii().setStream(getInput());
707
7.33k
    ascii().open(asciiName());
708
709
7.33k
    checkHeader(nullptr);
710
7.33k
    ok = createZones();
711
7.33k
    ascii().addPos(getInput()->tell());
712
7.33k
    ascii().addNote("_");
713
7.33k
    if (ok) {
714
6.87k
      createDocument(docInterface);
715
6.87k
      sendWindow(0);
716
6.87k
    }
717
718
7.33k
    ascii().reset();
719
7.33k
  }
720
7.33k
  catch (...) {
721
246
    MWAW_DEBUG_MSG(("WriterPlsParser::parse: exception catched when parsing\n"));
722
246
    ok = false;
723
246
  }
724
725
7.33k
  resetTextListener();
726
7.33k
  if (!ok) throw(libmwaw::ParseException());
727
7.33k
}
728
729
////////////////////////////////////////////////////////////
730
// create the document
731
////////////////////////////////////////////////////////////
732
void WriterPlsParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
733
6.87k
{
734
6.87k
  if (!documentInterface) return;
735
6.87k
  if (getTextListener()) {
736
0
    MWAW_DEBUG_MSG(("WriterPlsParser::createDocument: listener already exist\n"));
737
0
    return;
738
0
  }
739
740
  // update the page
741
6.87k
  m_state->m_actPage = 0;
742
743
  // create the page list
744
6.87k
  MWAWPageSpan ps(getPageSpan());
745
20.6k
  for (int i = 1; i < 3; i++) {
746
13.7k
    if (m_state->m_windows[i].m_paragraphs.size() == 0)
747
13.6k
      continue;
748
78
    MWAWHeaderFooter hF((i==1) ? MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
749
78
    hF.m_subDocument.reset(new WriterPlsParserInternal::SubDocument(*this, getInput(), i));
750
78
    ps.setHeaderFooter(hF);
751
78
  }
752
753
6.87k
  m_state->m_numPages = int(m_state->m_windows[0].m_pages.size());
754
6.87k
  ps.setPageSpan(m_state->m_numPages+1);
755
6.87k
  std::vector<MWAWPageSpan> pageList(1,ps);
756
  //
757
6.87k
  MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
758
6.87k
  setTextListener(listen);
759
6.87k
  listen->startDocument();
760
6.87k
}
761
762
763
////////////////////////////////////////////////////////////
764
//
765
// Intermediate level
766
//
767
////////////////////////////////////////////////////////////
768
bool WriterPlsParser::createZones()
769
7.33k
{
770
7.33k
  if (!readWindowsInfo(0) || !readPrintInfo())
771
0
    return false;
772
21.4k
  for (int st = 1; st < 4; st++) {
773
21.2k
    bool ok = true;
774
21.2k
    switch (st) {
775
7.33k
    case 1:
776
7.33k
      ok = m_state->m_headerHeight > 0;
777
7.33k
      break;
778
7.04k
    case 2:
779
7.04k
      ok = m_state->m_footerHeight > 0;
780
7.04k
      break;
781
6.87k
    default:
782
6.87k
      break;
783
21.2k
    }
784
21.2k
    if (!ok) continue;
785
7.74k
    if (st !=3 && !readWindowsInfo(st))
786
312
      return false;
787
7.43k
    if (!readWindowsZone(st==3 ? 0 : st))
788
6.85k
      return (st==3);
789
7.43k
  }
790
791
171
  return true;
792
7.33k
}
793
794
////////////////////////////////////////////////////////////
795
//
796
// Low level
797
//
798
////////////////////////////////////////////////////////////
799
800
////////////////////////////////////////////////////////////
801
// read the header
802
////////////////////////////////////////////////////////////
803
bool WriterPlsParser::checkHeader(MWAWHeader *header, bool /*strict*/)
804
27.8k
{
805
27.8k
  *m_state = WriterPlsParserInternal::State();
806
807
27.8k
  MWAWInputStreamPtr input = getInput();
808
27.8k
  if (!input || !input->hasDataFork())
809
0
    return false;
810
811
27.8k
  int const headerSize=2;
812
27.8k
  if (!input->checkPosition(headerSize)) {
813
0
    MWAW_DEBUG_MSG(("WriterPlsParser::checkHeader: file is too short\n"));
814
0
    return false;
815
0
  }
816
27.8k
  input->seek(0,librevenge::RVNG_SEEK_SET);
817
27.8k
  if (input->readULong(2) != 0x110)
818
142
    return false;
819
27.7k
  ascii().addPos(0);
820
27.7k
  ascii().addNote("FileHeader");
821
822
27.7k
  if (!readWindowsInfo(0) || !readPrintInfo())
823
4.29k
    return false;
824
23.4k
  input->seek(2,librevenge::RVNG_SEEK_SET);
825
23.4k
  if (header)
826
8.77k
    header->reset(MWAWDocument::MWAW_T_WRITERPLUS, 1);
827
828
23.4k
  return true;
829
27.7k
}
830
831
bool WriterPlsParser::readWindowsInfo(int zone)
832
35.9k
{
833
35.9k
  if (zone<0 || zone>=3) {
834
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsInfo:the zone seems bad\n"));
835
0
    return false;
836
0
  }
837
35.9k
  MWAWInputStreamPtr input = getInput();
838
839
35.9k
  long debPos = input->tell();
840
35.9k
  if (!input->checkPosition(debPos+0xf4)) {
841
777
    MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsInfo: file is too short\n"));
842
777
    return false;
843
777
  }
844
845
35.1k
  WriterPlsParserInternal::WindowsInfo info;
846
35.1k
  libmwaw::DebugStream f;
847
35.1k
  f << "Entries(WindowsZone)";
848
35.1k
  switch (zone) {
849
34.5k
  case 0:
850
34.5k
    break;
851
367
  case 1:
852
367
    f << "[Header]";
853
367
    break;
854
249
  case 2:
855
249
    f << "[Footer]";
856
249
    break;
857
0
  default:
858
0
    f << "[Unknown]";
859
0
    break;
860
35.1k
  }
861
35.1k
  f << ":";
862
105k
  for (int i = 0; i < 2; i++) {
863
70.3k
    auto val = static_cast<int>(input->readLong(1));
864
70.3k
    f << "f" << i << "=" << val << ",";
865
70.3k
  }
866
35.1k
  f << "unkn=" << input->readLong(2);
867
868
35.1k
  long pos;
869
246k
  for (auto &i : info.m_zone) {
870
246k
    WriterPlsParserInternal::WindowsInfo::Zone infoZone;
871
246k
    infoZone.m_unknown[0] = static_cast<int>(input->readULong(1));
872
246k
    infoZone.m_width = static_cast<int>(input->readULong(2));
873
246k
    infoZone.m_unknown[1] = static_cast<int>(input->readULong(1));
874
246k
    infoZone.m_unknown[2] = static_cast<int>(input->readULong(2));
875
246k
    infoZone.m_size = static_cast<int>(input->readULong(2));
876
246k
    infoZone.m_number = static_cast<int>(input->readULong(2));
877
246k
    i = infoZone;
878
246k
  }
879
35.1k
  f << "," << info;
880
881
35.1k
  ascii().addPos(debPos);
882
35.1k
  ascii().addNote(f.str().c_str());
883
884
35.1k
  pos = input->tell();
885
35.1k
  ascii().addPos(pos);
886
35.1k
  ascii().addNote("WindowsZone(A-1)");
887
35.1k
  ascii().addPos(pos+12);
888
35.1k
  ascii().addNote("WindowsZone(A-2)");
889
35.1k
  ascii().addPos(pos+30);
890
35.1k
  ascii().addNote("WindowsZone(A-3)");
891
35.1k
  ascii().addPos(pos+60);
892
35.1k
  ascii().addNote("WindowsZone(A-4)");
893
35.1k
  ascii().addPos(pos+60+14);
894
35.1k
  ascii().addNote("WindowsZone(A-5)");
895
35.1k
  ascii().addPos(pos+60+14*2);
896
35.1k
  ascii().addNote("WindowsZone(A-6)");
897
898
35.1k
  pos = debPos+0xc2;
899
35.1k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
900
35.1k
  f.str("");
901
35.1k
  f << "WindowsZone(A-7):";
902
35.1k
  auto val = static_cast<int>(input->readLong(2));
903
35.1k
  if (val) f << "unkn=" << val << ",";
904
35.1k
  auto width = static_cast<int>(input->readLong(2));
905
35.1k
  info.m_footerY = static_cast<int>(input->readLong(2));
906
35.1k
  info.m_headerY = static_cast<int>(input->readLong(2));
907
35.1k
  auto height = static_cast<int>(input->readLong(2));
908
35.1k
  info.m_pageDim = MWAWVec2i(width, height);
909
35.1k
  f << "page=" << info.m_pageDim << ",";
910
35.1k
  if (info.m_headerY)
911
5.20k
    f << "header[height]=" << info.m_headerY << ",";
912
35.1k
  if (info.m_footerY)
913
5.22k
    f << "footer[height]=" << info.m_footerY << ",";
914
140k
  for (int i = 0; i < 3; i++) // always 17 12 0 left|right ?
915
105k
    f << "f" << i << "=" << static_cast<int>(input->readLong(2)) << ",";
916
35.1k
  ascii().addPos(pos);
917
35.1k
  ascii().addNote(f.str().c_str());
918
35.1k
  if (info.dimensionInvalid())
919
2.98k
    return false;
920
32.1k
  if (zone == 0) {
921
31.6k
    m_state->m_headerHeight = info.m_headerY;
922
31.6k
    m_state->m_footerHeight = info.m_footerY;
923
31.6k
  }
924
32.1k
  pos = input->tell();
925
32.1k
  f.str("");
926
32.1k
  f << "WindowsZone(B):";
927
32.1k
  int dim[4];
928
128k
  for (auto &d : dim) d = static_cast<int>(input->readLong(2));
929
32.1k
  f << "dim(?)=" << dim[1] << "x" << dim[0] << "-" << dim[3] << "x" << dim[2] << ",";
930
96.5k
  for (int i = 0; i < 2; i++) {
931
64.3k
    auto fl = static_cast<int>(input->readLong(1)); // almost always 0 except some time 1
932
64.3k
    if (fl) f << "fl" << i << "=" << fl << ",";
933
64.3k
  }
934
225k
  for (int i = 0; i < 6; i++) {
935
193k
    int values[3];
936
193k
    values[0] = static_cast<int>(input->readULong(1));
937
193k
    values[1] = static_cast<int>(input->readLong(2));
938
193k
    values[2] = static_cast<int>(input->readULong(1));
939
193k
    if (values[0] == 0 && values[1] == 0 && values[2] == 0) continue;
940
130k
    f << "f" << i << "=[" << values[0] << ", w=" << values[1]
941
130k
      << ", " << std::hex << values[2] << std::dec << "],";
942
130k
  }
943
944
32.1k
  m_state->m_windows[zone]=info;
945
946
32.1k
  ascii().addPos(pos);
947
32.1k
  ascii().addNote(f.str().c_str());
948
949
32.1k
  return true;
950
35.1k
}
951
952
////////////////////////////////////////////////////////////
953
// read all the windows zone info
954
////////////////////////////////////////////////////////////
955
bool WriterPlsParser::readWindowsZone(int zone)
956
7.43k
{
957
7.43k
  if (zone<0 || zone>=3) {
958
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsZone:the zone seems bad\n"));
959
0
    return false;
960
0
  }
961
962
7.43k
  MWAWInputStreamPtr input = getInput();
963
7.43k
  auto &wInfo = m_state->m_windows[zone];
964
965
7.43k
  libmwaw::DebugStream f;
966
25.8k
  for (int wh=1; wh < 7; wh++) {
967
24.9k
    auto const &z = wInfo.m_zone[wh];
968
24.9k
    int length = z.m_size;
969
24.9k
    if (!length) continue;
970
971
13.4k
    long pos = input->tell();
972
13.4k
    input->seek(length, librevenge::RVNG_SEEK_CUR);
973
13.4k
    if (long(input->tell()) != pos+length) {
974
919
      MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsZone: zone is too short\n"));
975
919
      return false;
976
919
    }
977
12.5k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
978
979
12.5k
    bool ok = false;
980
12.5k
    switch (wh) {
981
4.67k
    case 1:
982
4.67k
      ok=readPageInfo(zone);
983
4.67k
      break;
984
948
    case 2:
985
948
      ok=readColInfo(zone);
986
948
      break;
987
6.28k
    case 3:
988
      // need to get next block
989
6.28k
      ok = readParagraphInfo(zone);
990
6.28k
      if (!ok) return false;
991
680
      break;
992
680
    default:
993
659
      break;
994
12.5k
    }
995
6.96k
    if (ok) continue;
996
997
3.42k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
998
3.42k
    if (z.m_number && (length % z.m_number) == 0) {
999
2.09k
      int dataSz = length / z.m_number;
1000
1.26M
      for (int i = 0; i < z.m_number; i++) {
1001
1.26M
        f.str("");
1002
1.26M
        f << "Entries(Zone" << wh << ")-" << i << ":";
1003
1.26M
        ascii().addPos(input->tell());
1004
1.26M
        ascii().addNote(f.str().c_str());
1005
1.26M
        input->seek(dataSz, librevenge::RVNG_SEEK_CUR);
1006
1.26M
      }
1007
2.09k
    }
1008
1.32k
    else {
1009
1.32k
      f.str("");
1010
1.32k
      f << "Entries(Zone" << wh << "):";
1011
1.32k
      ascii().addPos(input->tell());
1012
1.32k
      ascii().addNote(f.str().c_str());
1013
1.32k
      input->seek(length, librevenge::RVNG_SEEK_CUR);
1014
1.32k
    }
1015
3.42k
  }
1016
1017
1.08k
  for (int i = int(wInfo.m_paragraphs.size())-1; i >= 0; i--) {
1018
621
    auto const &pInfo = wInfo.m_paragraphs[size_t(i)];
1019
621
    if (!pInfo.m_pos)  continue;
1020
1021
447
    input->seek(pInfo.m_pos, librevenge::RVNG_SEEK_SET);
1022
447
    auto length = long(input->readULong(2));
1023
447
    auto length2 = long(input->readULong(2));
1024
447
    long endPos = pInfo.m_pos+4+length+length2;
1025
447
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1026
447
    if (long(input->tell()) != endPos) {
1027
315
      MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsZone: data zone is too short\n"));
1028
315
      return false;
1029
315
    }
1030
132
    switch (pInfo.getType()) {
1031
32
    case 4:
1032
32
      length = long(input->readULong(4));
1033
32
      input->seek(length, librevenge::RVNG_SEEK_CUR);
1034
32
      if (long(input->tell()) != endPos+length+4) {
1035
18
        MWAW_DEBUG_MSG(("WriterPlsParser::readWindowsZone: graphics zone is too short\n"));
1036
18
        return false;
1037
18
      }
1038
14
      break;
1039
100
    default: // 0,1,2,3, 5 : ok, other ?
1040
100
      break;
1041
132
    }
1042
114
    return true;
1043
132
  }
1044
467
  return true;
1045
914
}
1046
1047
////////////////////////////////////////////////////////////
1048
// send the windows zone info
1049
////////////////////////////////////////////////////////////
1050
bool WriterPlsParser::sendWindow(int zone, MWAWVec2i limits)
1051
185k
{
1052
185k
  MWAWTextListenerPtr listener=getTextListener();
1053
185k
  if (!listener) {
1054
0
    MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: can not find a listener\n"));
1055
0
    return false;
1056
0
  }
1057
185k
  if (zone<0 || zone>=3) {
1058
0
    MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow:the zone seems bad\n"));
1059
0
    return false;
1060
0
  }
1061
185k
  auto &wInfo = m_state->m_windows[zone];
1062
1063
185k
  bool sendAll = limits[0] < 0;
1064
1065
185k
  auto maxPages = int(wInfo.m_pages.size());
1066
185k
  if (maxPages == 0 || zone || !sendAll) maxPages = 1;
1067
1068
185k
  int actParag = 0;
1069
185k
  int actCol = 0, numCols = 0;
1070
344k
  for (int pg = 0; pg < maxPages; pg++) {
1071
185k
    int endParag = 0;
1072
185k
    if (!sendAll) {
1073
178k
      actParag = limits[0];
1074
178k
      endParag = limits[1];
1075
178k
      if (endParag <= actParag) {
1076
25.4k
        MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: pb2 with limits\n"));
1077
25.4k
        return true;
1078
25.4k
      }
1079
178k
    }
1080
6.94k
    else {
1081
6.94k
      if (zone == 0) {
1082
6.87k
        newPage(pg+1);
1083
6.87k
        actCol = numCols ? 1 : 0;
1084
6.87k
      }
1085
6.94k
      if (pg == maxPages-1 || wInfo.m_pages.size() == 0)
1086
6.94k
        endParag = int(wInfo.m_paragraphs.size());
1087
1
      else {
1088
1
        endParag = wInfo.m_pages[size_t(pg)+1].m_firstLine-1;
1089
1
        if (endParag == -1 || endParag < actParag) {
1090
0
          MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: pb with page zone\n"));
1091
0
          continue;
1092
0
        }
1093
1
      }
1094
6.94k
    }
1095
159k
    if (endParag > int(wInfo.m_paragraphs.size())) {
1096
72.5k
      MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: pb with limits\n"));
1097
72.5k
      endParag = int(wInfo.m_paragraphs.size());
1098
72.5k
    }
1099
1100
527k
    for (int i = actParag; i < endParag; i++) {
1101
368k
      auto const &pInfo = wInfo.m_paragraphs[size_t(i)];
1102
368k
      if (!pInfo.m_pos) {
1103
6.11k
        readText(pInfo);
1104
6.11k
        continue;
1105
6.11k
      }
1106
362k
      bool ok = true;
1107
362k
      switch (pInfo.getType()) {
1108
3.20k
      case 3: // col break: seems similar to an entry data (with a text zone which does not contain any character)
1109
3.20k
        if (numCols) {
1110
0
          if (actCol >numCols) {
1111
0
            MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: pb with col break\n"));
1112
0
          }
1113
0
          else {
1114
0
            actCol++;
1115
0
            listener->insertBreak(MWAWTextListener::ColumnBreak);
1116
0
          }
1117
0
        }
1118
3.20k
        MWAW_FALLTHROUGH;
1119
96.3k
      case 0:
1120
135k
      case 2:
1121
135k
        ok = readText(pInfo);
1122
135k
        break;
1123
29.0k
      case 1: {
1124
29.0k
        MWAWSection section;
1125
29.0k
        bool canCreateSection = sendAll && zone == 0 && actCol == numCols;
1126
29.0k
        if (findSection(zone, MWAWVec2i(i, endParag), section)) {
1127
28.9k
          if (!canCreateSection) {
1128
19.6k
            if (section.numColumns()>1) {
1129
0
              MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: find a section in auxilliary zone\n"));
1130
0
            }
1131
19.6k
          }
1132
9.27k
          else {
1133
9.27k
            if (listener->isSectionOpened())
1134
5.18k
              listener->closeSection();
1135
9.27k
            listener->openSection(section);
1136
9.27k
            numCols = listener->getSection().numColumns();
1137
9.27k
            if (numCols<=1) numCols=0;
1138
9.27k
            actCol = numCols ? 1 : 0;
1139
9.27k
            canCreateSection = false;
1140
9.27k
          }
1141
28.9k
        }
1142
1143
29.0k
        ok = readSection(pInfo, canCreateSection);
1144
29.0k
        break;
1145
96.3k
      }
1146
11.3k
      case 4:
1147
11.3k
        ok = readGraphic(pInfo);
1148
11.3k
        break;
1149
154k
      case 5:
1150
154k
        if (pInfo.m_numLines + i <= endParag) {
1151
147k
          if ((ok = readTable(pInfo))) {
1152
116k
            listener->openTableRow(float(pInfo.m_height), librevenge::RVNG_POINT);
1153
1154
295k
            for (size_t j = 0; j < pInfo.m_linesHeight.size(); j++) {
1155
178k
              int numData = pInfo.m_linesHeight[j];
1156
178k
              MWAWCell cell;
1157
178k
              cell.setPosition(MWAWVec2i(int(j), 0));
1158
178k
              listener->openTableCell(cell);
1159
178k
              sendWindow(zone, MWAWVec2i(i+1, i+1+numData));
1160
178k
              i += numData;
1161
178k
              listener->closeTableCell();
1162
178k
            }
1163
1164
116k
            listener->closeTableRow();
1165
116k
            listener->closeTable();
1166
116k
          }
1167
147k
        }
1168
7.35k
        else {
1169
7.35k
          MWAW_DEBUG_MSG(("WriterPlsParser::sendWindow: table across a page\n"));
1170
7.35k
        }
1171
154k
        break;
1172
31.2k
      default:
1173
31.2k
        ok = readUnknown(pInfo);
1174
31.2k
        break;
1175
362k
      }
1176
361k
      if (!ok) {
1177
142k
        libmwaw::DebugStream f;
1178
142k
        f << "Entries(Unknown):" << pInfo;
1179
142k
        ascii().addPos(pInfo.m_pos);
1180
142k
        ascii().addNote(f.str().c_str());
1181
142k
      }
1182
361k
    }
1183
159k
    actParag = endParag;
1184
159k
  }
1185
159k
  return true;
1186
185k
}
1187
1188
1189
/*
1190
 * find the column size which correspond to a limit
1191
 *
1192
 * Note: complex because we need to read the file in order to find the limit
1193
 */
1194
bool WriterPlsParser::findSection(int zone, MWAWVec2i limits, MWAWSection &sec)
1195
29.0k
{
1196
29.0k
  if (zone<0 || zone>=3) {
1197
0
    MWAW_DEBUG_MSG(("WriterPlsParser::findSection:the zone seems bad\n"));
1198
0
    return false;
1199
0
  }
1200
29.0k
  auto &wInfo = m_state->m_windows[zone];
1201
1202
29.0k
  sec=MWAWSection();
1203
29.0k
  std::vector<int> listPos;
1204
29.0k
  if (!wInfo.getColumnLimitsFor(limits[0], listPos))
1205
141
    return false;
1206
1207
28.9k
  size_t numPos = listPos.size();
1208
28.9k
  if (!numPos)
1209
28.9k
    return true;
1210
0
  if (listPos[numPos-1] >= limits[1]) {
1211
0
    MWAW_DEBUG_MSG(("WriterPlsParser::findSection: columns across a page\n"));
1212
0
    return false;
1213
0
  }
1214
1215
0
  MWAWInputStreamPtr input = getInput();
1216
0
  int totalSize = 0;
1217
0
  for (auto &line : listPos) {
1218
0
    long pos = wInfo.m_paragraphs[size_t(line)].m_pos;
1219
0
    if (!pos) {
1220
0
      MWAW_DEBUG_MSG(("WriterPlsParser::findSection: bad data pos\n"));
1221
0
      return false;
1222
0
    }
1223
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1224
0
    if (input->readLong(2)) {
1225
0
      MWAW_DEBUG_MSG(("WriterPlsParser::findSection: find a text size\n"));
1226
0
      return false;
1227
0
    }
1228
0
    input->seek(8, librevenge::RVNG_SEEK_CUR); // sz2 and type, h, indent
1229
0
    auto val = static_cast<int>(input->readLong(2));
1230
0
    if (val <= 0 || long(input->tell()) != pos + 12) {
1231
0
      MWAW_DEBUG_MSG(("WriterPlsParser::findSection: file is too short\n"));
1232
0
      return false;
1233
0
    }
1234
0
    totalSize += val;
1235
0
    MWAWSection::Column col;
1236
0
    col.m_width=val;
1237
0
    col.m_widthUnit=librevenge::RVNG_POINT;
1238
0
    sec.m_columns.push_back(col);
1239
0
  }
1240
0
  if (sec.m_columns.size()==1)
1241
0
    sec.m_columns.resize(0);
1242
0
  if (totalSize >= int(72.*getPageWidth())) {
1243
0
    MWAW_DEBUG_MSG(("WriterPlsParser::findSection: total size is too big\n"));
1244
0
    return false;
1245
0
  }
1246
0
  return true;
1247
0
}
1248
1249
////////////////////////////////////////////////////////////
1250
// read all the windows zone info
1251
////////////////////////////////////////////////////////////
1252
bool WriterPlsParser::readPageInfo(int zone)
1253
4.67k
{
1254
4.67k
  if (zone<0 || zone>=3) {
1255
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readPageInfo:the zone seems bad\n"));
1256
0
    return false;
1257
0
  }
1258
1259
4.67k
  MWAWInputStreamPtr input = getInput();
1260
4.67k
  libmwaw::DebugStream f;
1261
1262
4.67k
  auto &wInfo = m_state->m_windows[zone];
1263
4.67k
  int numPages = wInfo.m_zone[1].m_number;
1264
4.67k
  if (wInfo.m_zone[1].m_size != numPages * 10) {
1265
712
    MWAW_DEBUG_MSG(("WriterPlsParser::readPageInfo: odd page size\n"));
1266
712
    return false;
1267
712
  }
1268
1269
3.96k
  int actNumLine = 0;
1270
3.96k
  auto maxHeight = int(72.*getTextHeight()+20.);
1271
3.96k
  if (maxHeight < 1000) maxHeight = 1000;
1272
3.96k
  int prevTotalHeight = 0;
1273
1274
6.47k
  for (int page = 0; page < numPages; page++) {
1275
4.06k
    long pos = input->tell();
1276
4.06k
    WriterPlsParserInternal::PageInfo pInfo;
1277
4.06k
    pInfo.m_firstLine = static_cast<int>(input->readLong(2));
1278
4.06k
    if ((page == 0 && pInfo.m_firstLine != 1) || pInfo.m_firstLine < actNumLine)
1279
1.06k
      return false;
1280
2.99k
    actNumLine=pInfo.m_firstLine;
1281
5.99k
    for (auto &unkn : pInfo.m_unknown) unkn = static_cast<int>(input->readLong(2));
1282
2.99k
    pInfo.m_heightFromBegin = static_cast<int>(input->readULong(2));
1283
2.99k
    if (pInfo.m_heightFromBegin < prevTotalHeight) return false;
1284
2.98k
    prevTotalHeight = pInfo.m_heightFromBegin;
1285
2.98k
    pInfo.m_height = static_cast<int>(input->readULong(2));
1286
2.98k
    if (pInfo.m_height > maxHeight) return false;
1287
1288
2.51k
    wInfo.m_pages.push_back(pInfo);
1289
2.51k
    f.str("");
1290
2.51k
    f << "Entries(PageInfo)-"<< page+1 << ":" << pInfo;
1291
1292
2.51k
    ascii().addPos(pos);
1293
2.51k
    ascii().addNote(f.str().c_str());
1294
2.51k
  }
1295
1296
2.41k
  return true;
1297
3.96k
}
1298
1299
////////////////////////////////////////////////////////////
1300
// read a windows paragraph info
1301
////////////////////////////////////////////////////////////
1302
MWAWParagraph WriterPlsParser::getParagraph(WriterPlsParserInternal::ParagraphData const &data)
1303
64.5k
{
1304
64.5k
  MWAWParagraph para;
1305
1306
64.5k
  para.m_marginsUnit=librevenge::RVNG_POINT;
1307
  // decrease a little left indent to avoid some page width pb
1308
64.5k
  double left=double(data.m_indent[0])-20.-72.*getPageSpan().getMarginLeft();
1309
64.5k
  if (left > 0)
1310
15.6k
    para.m_margins[1]=left;
1311
64.5k
  para.m_margins[0]=double(data.m_indent[1]-data.m_indent[0]);
1312
64.5k
  if (getTextListener() && getTextListener()->getSection().numColumns() > 1)
1313
0
    return para; // too dangerous to set the paragraph width in this case...
1314
64.5k
  double right=getPageWidth()*72.-double(data.m_width);
1315
64.5k
  if (right > 0)
1316
51.4k
    para.m_margins[2]=right;
1317
64.5k
  return para;
1318
64.5k
}
1319
1320
bool WriterPlsParser::readParagraphInfo(int zone)
1321
6.28k
{
1322
6.28k
  if (zone<0 || zone>=3) {
1323
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readParagraphInfo:the zone seems bad\n"));
1324
0
    return false;
1325
0
  }
1326
1327
6.28k
  libmwaw::DebugStream f;
1328
1329
6.28k
  MWAWInputStreamPtr input = getInput();
1330
6.28k
  WriterPlsParserInternal::WindowsInfo &wInfo = m_state->m_windows[zone];
1331
6.28k
  int numPara = wInfo.m_zone[3].m_number;
1332
6.28k
  long endPos = long(input->tell()) + wInfo.m_zone[3].m_size;
1333
1334
6.28k
  int para = 0;
1335
145k
  while (para <= numPara) {
1336
145k
    long pos = input->tell();
1337
145k
    if (pos == endPos) break;
1338
145k
    if (pos > endPos) return false;
1339
142k
    WriterPlsParserInternal::ParagraphInfo pInfo;
1340
1341
142k
    f.str("");
1342
142k
    f << "Entries(ParaInfo)-"<< para+1 << ":";
1343
142k
    auto wh = static_cast<int>(input->readLong(1));
1344
142k
    if ((wh%2) == 0) {
1345
39.9k
      if (wh < 4) return false;
1346
165k
      for (int i = 0; i < (wh-4)/2; i++)
1347
128k
        pInfo.m_unknowns.push_back(static_cast<int>(input->readULong(2)));
1348
36.9k
      pInfo.m_type = -1;
1349
36.9k
      pInfo.m_numLines = static_cast<int>(input->readULong(1)); // probably numLine
1350
36.9k
      pInfo.m_height = static_cast<int>(input->readULong(2));
1351
36.9k
      f << pInfo;
1352
36.9k
      ascii().addPos(pos);
1353
36.9k
      ascii().addNote(f.str().c_str());
1354
36.9k
      continue;
1355
39.9k
    }
1356
102k
    para++;
1357
102k
    pInfo.m_flags[0] = (wh>>1);
1358
102k
    pInfo.m_flags[1] = static_cast<int>(input->readULong(1)); // almost always 0
1359
102k
    pInfo.m_type = static_cast<int>(input->readULong(1));
1360
102k
    pInfo.m_numLines = static_cast<int>(input->readULong(1)); // or numColumns if type==5
1361
102k
    pInfo.m_height = static_cast<int>(input->readULong(2));
1362
102k
    pInfo.m_pos = long(input->readULong(4));
1363
102k
    pInfo.m_flags[2] = static_cast<int>(input->readULong(1)); // almost always 0
1364
102k
    pInfo.m_width = static_cast<int>(input->readULong(2));
1365
307k
    for (int i = 3; i < 5; i++)
1366
205k
      pInfo.m_flags[i] = static_cast<int>(input->readULong(1));
1367
102k
    if (pInfo.m_numLines!=1) {
1368
862k
      for (int i = 0; i < pInfo.m_numLines; i++)
1369
813k
        pInfo.m_linesHeight.push_back(static_cast<int>(input->readULong(1)));
1370
48.9k
    }
1371
102k
    pInfo.m_height2 = static_cast<int>(input->readULong(1));
1372
102k
    wInfo.m_paragraphs.push_back(pInfo);
1373
102k
    f << pInfo;
1374
1375
102k
    ascii().addPos(pos);
1376
102k
    ascii().addNote(f.str().c_str());
1377
1378
102k
  }
1379
1380
680
  return true;
1381
6.28k
}
1382
1383
////////////////////////////////////////////////////////////
1384
// read all the windows col info ?
1385
////////////////////////////////////////////////////////////
1386
bool WriterPlsParser::readColInfo(int zone)
1387
948
{
1388
948
  if (zone<0 || zone>=3) {
1389
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readColInfo:the zone seems bad\n"));
1390
0
    return false;
1391
0
  }
1392
1393
948
  libmwaw::DebugStream f;
1394
1395
948
  WriterPlsParserInternal::WindowsInfo &wInfo = m_state->m_windows[zone];
1396
948
  int numCols = wInfo.m_zone[2].m_number;
1397
948
  if (wInfo.m_zone[2].m_size != numCols * 16) {
1398
503
    MWAW_DEBUG_MSG(("WriterPlsParser::readColInfo: odd col size\n"));
1399
503
    return false;
1400
503
  }
1401
1402
445
  MWAWInputStreamPtr input = getInput();
1403
3.88k
  for (int col = 0; col < numCols; col++) {
1404
3.44k
    long pos = input->tell();
1405
3.44k
    WriterPlsParserInternal::ColumnInfo cInfo;
1406
3.44k
    cInfo.m_col = static_cast<int>(input->readLong(2));
1407
3.44k
    cInfo.m_unknown[0] = static_cast<int>(input->readLong(2));
1408
3.44k
    cInfo.m_numCol = static_cast<int>(input->readLong(2));
1409
3.44k
    cInfo.m_firstLine = static_cast<int>(input->readLong(2));
1410
13.7k
    for (int i = 1; i < 4; i++)
1411
10.3k
      cInfo.m_unknown[i] = static_cast<int>(input->readLong(2));
1412
3.44k
    cInfo.m_height = static_cast<int>(input->readLong(2));
1413
3.44k
    wInfo.m_columns.push_back(cInfo);
1414
1415
3.44k
    f.str("");
1416
3.44k
    f << "Entries(ColInfo):" << cInfo;
1417
3.44k
    ascii().addPos(pos);
1418
3.44k
    ascii().addNote(f.str().c_str());
1419
3.44k
  }
1420
1421
445
  return true;
1422
948
}
1423
1424
bool WriterPlsParser::readText(WriterPlsParserInternal::ParagraphInfo const &info)
1425
141k
{
1426
141k
  WriterPlsParserInternal::ParagraphData data;
1427
141k
  std::vector<WriterPlsParserInternal::Line> lines;
1428
141k
  if (!info.m_pos) {
1429
6.11k
    MWAW_DEBUG_MSG(("WriterPlsParser::readText: pb with pos\n"));
1430
6.11k
    return false;
1431
6.11k
  }
1432
1433
135k
  if (!readParagraphData(info, true, data))
1434
71.1k
    return false;
1435
1436
64.5k
  libmwaw::DebugStream f;
1437
1438
64.5k
  MWAWInputStreamPtr input = getInput();
1439
64.5k
  long pos = input->tell();
1440
64.5k
  f.str("");
1441
64.5k
  f << "Paragraph" << data.m_type << "(II):";
1442
1443
64.5k
  int numLines = data.m_numData[1];
1444
64.5k
  if (!readLines(info, numLines, lines)) {
1445
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readText: pb with the lines\n"));
1446
0
    lines.resize(0);
1447
0
    input->seek(pos+numLines*16, librevenge::RVNG_SEEK_SET);
1448
0
    f << "###lines,";
1449
0
  }
1450
175M
  for (int i = 0; i < numLines; i++)
1451
175M
    f << "line" << i << "=[" << lines[size_t(i)] << "],";
1452
1453
64.5k
  if (long(input->tell()) != data.m_endPos) {
1454
60.1k
    ascii().addDelimiter(input->tell(), '|');
1455
60.1k
    input->seek(data.m_endPos, librevenge::RVNG_SEEK_SET);
1456
60.1k
    f << "#endPos,";
1457
60.1k
  }
1458
1459
64.5k
  ascii().addPos(pos);
1460
64.5k
  ascii().addNote(f.str().c_str());
1461
1462
64.5k
  ascii().addPos(input->tell());
1463
64.5k
  ascii().addNote("_");
1464
1465
64.5k
  if (!getTextListener())
1466
0
    return true;
1467
64.5k
  std::string const &text = data.m_text;
1468
64.5k
  auto const &fonts = data.m_fonts;
1469
64.5k
  auto numChars = long(text.length());
1470
64.5k
  size_t actFont = 0, numFonts = fonts.size();
1471
64.5k
  int actLine = 0;
1472
64.5k
  numLines=int(lines.size());
1473
64.5k
  MWAWParagraph para=getParagraph(data);
1474
1475
64.5k
  if (numLines == 0 && info.m_height > 0) {
1476
37.7k
    para.setInterline(info.m_height, librevenge::RVNG_POINT);
1477
37.7k
    getTextListener()->setParagraph(para);
1478
37.7k
  }
1479
3.60M
  for (long c = 0; c < numChars; c++) {
1480
3.53M
    if (actFont < numFonts && c ==  fonts[actFont].m_firstChar)
1481
5.85k
      getTextListener()->setFont(fonts[actFont++].m_font);
1482
3.53M
    if (actLine < numLines && c == lines[size_t(actLine)].m_firstChar) {
1483
4.83k
      if (actLine) getTextListener()->insertEOL();
1484
4.83k
      if (numLines == 1 && info.m_height > lines[0].m_height) {
1485
164
        para.setInterline(info.m_height, librevenge::RVNG_POINT);
1486
164
        getTextListener()->setParagraph(para);
1487
164
      }
1488
4.67k
      else if (lines[size_t(actLine)].m_height) {
1489
3.99k
        para.setInterline(lines[size_t(actLine)].m_height, librevenge::RVNG_POINT);
1490
3.99k
        getTextListener()->setParagraph(para);
1491
3.99k
      }
1492
4.83k
      actLine++;
1493
4.83k
    }
1494
1495
3.53M
    auto ch = static_cast<unsigned char>(text[size_t(c)]);
1496
3.53M
    if (ch == 0x9)
1497
32.2k
      getTextListener()->insertTab();
1498
3.50M
    else
1499
3.50M
      getTextListener()->insertCharacter(ch);
1500
3.53M
  }
1501
64.5k
  if (info.getType() != 3)
1502
62.8k
    getTextListener()->insertEOL();
1503
1504
64.5k
  return true;
1505
64.5k
}
1506
1507
bool WriterPlsParser::readSection(WriterPlsParserInternal::ParagraphInfo const &info, bool mainBlock)
1508
29.0k
{
1509
29.0k
  WriterPlsParserInternal::ParagraphData data;
1510
1511
29.0k
  if (!info.m_pos) {
1512
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readSection: can not find the beginning pos\n"));
1513
0
    return false;
1514
0
  }
1515
1516
29.0k
  if (!readParagraphData(info, true, data))
1517
19.7k
    return false;
1518
1519
9.37k
  libmwaw::DebugStream f;
1520
1521
9.37k
  MWAWInputStreamPtr input = getInput();
1522
9.37k
  long pos = input->tell();
1523
9.37k
  f.str("");
1524
9.37k
  f << "Paragraph" << data.m_type << "(II):";
1525
1526
9.37k
  int numData = data.m_numData[1];
1527
9.37k
  if (numData != 1) {
1528
9.01k
    MWAW_DEBUG_MSG(("WriterPlsParser::readSection: unexpected num of data: %d \n", numData));
1529
9.01k
  }
1530
1531
9.37k
  std::vector<WriterPlsParserInternal::SectionInfo> sections;
1532
19.6M
  for (int i = 0; i < numData; i++) {
1533
19.6M
    WriterPlsParserInternal::SectionInfo section;
1534
58.9M
    for (int j = 0; j < 2; j++)
1535
39.3M
      section.m_flags[j] = static_cast<int>(input->readLong(2));
1536
19.6M
    section.m_numCol = static_cast<int>(input->readLong(2)); // checkme
1537
58.9M
    for (auto &dim : section.m_dim) dim = static_cast<int>(input->readLong(2));
1538
58.9M
    for (int j = 2; j < 4; j++)
1539
39.3M
      section.m_flags[j] = static_cast<int>(input->readLong(2));
1540
19.6M
    sections.push_back(section);
1541
19.6M
    if (!section.empty())
1542
189k
      f << "section" << i << "=[" << section << "],";
1543
19.6M
  }
1544
1545
9.37k
  if (long(input->tell()) != data.m_endPos) {
1546
8.31k
    ascii().addDelimiter(input->tell(), '|');
1547
8.31k
    input->seek(data.m_endPos, librevenge::RVNG_SEEK_SET);
1548
8.31k
    f << "#endPos,";
1549
8.31k
  }
1550
1551
9.37k
  if (getTextListener() && mainBlock) {
1552
9
    if (!getTextListener()->isSectionOpened())
1553
9
      getTextListener()->openSection(MWAWSection());
1554
9
  }
1555
9.37k
  ascii().addPos(pos);
1556
9.37k
  ascii().addNote(f.str().c_str());
1557
1558
9.37k
  ascii().addPos(input->tell());
1559
9.37k
  ascii().addNote("_");
1560
9.37k
  return true;
1561
29.0k
}
1562
1563
bool WriterPlsParser::readTable(WriterPlsParserInternal::ParagraphInfo const &info)
1564
147k
{
1565
147k
  WriterPlsParserInternal::ParagraphData data;
1566
1567
147k
  if (!info.m_pos) {
1568
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readTable: can not find the beginning pos\n"));
1569
0
    return false;
1570
0
  }
1571
1572
147k
  if (!readParagraphData(info, true, data))
1573
30.4k
    return false;
1574
1575
117k
  libmwaw::DebugStream f;
1576
1577
117k
  MWAWInputStreamPtr input = getInput();
1578
117k
  long pos = input->tell();
1579
117k
  f.str("");
1580
117k
  f << "Paragraph" << data.m_type << "(II):";
1581
1582
117k
  int numData = data.m_numData[1];
1583
117k
  if (numData <= 1) {
1584
84.2k
    MWAW_DEBUG_MSG(("WriterPlsParser::readTable: unexpected num of data: %d \n", numData));
1585
84.2k
  }
1586
1587
117k
  std::vector<WriterPlsParserInternal::ColumnTableInfo> columns;
1588
89.8M
  for (int i = 0; i < numData; i++) {
1589
89.7M
    WriterPlsParserInternal::ColumnTableInfo cols;
1590
89.7M
    cols.m_height = static_cast<int>(input->readLong(2));
1591
179M
    for (auto &colX : cols.m_colX) colX = static_cast<int>(input->readLong(2));
1592
89.7M
    cols.m_numData = static_cast<int>(input->readLong(2));
1593
89.7M
    cols.m_flags  = static_cast<int>(input->readLong(2));
1594
269M
    for (auto &textX : cols.m_textX) textX = static_cast<int>(input->readLong(2));
1595
1596
89.7M
    columns.push_back(cols);
1597
89.7M
    f << "col" << i << "=[" << cols << "],";
1598
89.7M
  }
1599
1600
117k
  if (getTextListener()) {
1601
117k
    std::vector<float> colSize(static_cast<size_t>(numData));
1602
89.8M
    for (int i = 0; i < numData; i++) {
1603
89.7M
      auto const &cols = columns[size_t(i)];
1604
89.7M
      colSize[size_t(i)] = float(cols.m_colX[1]-cols.m_colX[0]);
1605
89.7M
    }
1606
117k
    MWAWTable table(MWAWTable::TableDimBit);
1607
117k
    table.setColsSize(colSize);
1608
    // use the same function than getParagraph to respect alignment
1609
117k
    int left=columns.empty() ? 0 : columns[0].m_colX[0]-20-int(72.*getPageSpan().getMarginLeft());
1610
117k
    if (left)
1611
35.2k
      table.setAlignment(MWAWTable::Left, float(left));
1612
117k
    getTextListener()->openTable(table);
1613
117k
  }
1614
1615
117k
  if (long(input->tell()) != data.m_endPos) {
1616
113k
    ascii().addDelimiter(input->tell(), '|');
1617
113k
    input->seek(data.m_endPos, librevenge::RVNG_SEEK_SET);
1618
113k
    f << "#endPos,";
1619
113k
  }
1620
1621
117k
  ascii().addPos(pos);
1622
117k
  ascii().addNote(f.str().c_str());
1623
1624
117k
  ascii().addPos(input->tell());
1625
117k
  ascii().addNote("_");
1626
1627
117k
  return true;
1628
147k
}
1629
1630
bool WriterPlsParser::readGraphic(WriterPlsParserInternal::ParagraphInfo const &info)
1631
11.3k
{
1632
11.3k
  WriterPlsParserInternal::ParagraphData data;
1633
1634
11.3k
  if (!info.m_pos) {
1635
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: can not find the beginning pos\n"));
1636
0
    return false;
1637
0
  }
1638
1639
11.3k
  if (!readParagraphData(info, true, data))
1640
4.94k
    return false;
1641
1642
6.43k
  libmwaw::DebugStream f;
1643
1644
6.43k
  MWAWInputStreamPtr input = getInput();
1645
6.43k
  long pos = input->tell();
1646
6.43k
  f.str("");
1647
6.43k
  f << "Paragraph" << data.m_type << "(II):";
1648
1649
6.43k
  int numData = data.m_numData[1];
1650
6.43k
  if (numData != 1) {
1651
6.12k
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: unexpected num of data: %d \n", numData));
1652
6.12k
  }
1653
1654
6.43k
  std::vector<WriterPlsParserInternal::GraphicInfo> graphicsInfos;
1655
12.6M
  for (int i = 0; i < numData; i++) {
1656
12.5M
    WriterPlsParserInternal::GraphicInfo gInfo;
1657
12.5M
    gInfo.m_flags[0] = static_cast<int>(input->readLong(1));
1658
12.5M
    gInfo.m_width = static_cast<int>(input->readLong(2));
1659
12.5M
    gInfo.m_flags[1] = static_cast<int>(input->readULong(1)); //
1660
12.5M
    gInfo.m_graphicWidth = static_cast<int>(input->readLong(2)); // total width
1661
75.5M
    for (int j = 2; j < 7; j++)
1662
62.9M
      gInfo.m_flags[j] = static_cast<int>(input->readLong(2));
1663
12.5M
    f << "data" << i << "=[" << gInfo << "],";
1664
12.5M
    graphicsInfos.push_back(gInfo);
1665
12.5M
  }
1666
6.43k
  if (long(input->tell()) != data.m_endPos) {
1667
5.49k
    ascii().addDelimiter(input->tell(), '|');
1668
5.49k
    input->seek(data.m_endPos, librevenge::RVNG_SEEK_SET);
1669
5.49k
    f << "#endPos,";
1670
5.49k
  }
1671
1672
6.43k
  ascii().addPos(pos);
1673
6.43k
  ascii().addNote(f.str().c_str());
1674
1675
  // read the graphic:
1676
6.43k
  pos = input->tell();
1677
6.43k
  auto length = long(input->readULong(4));
1678
6.43k
  if (!length) {
1679
2.87k
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: find a zero size graphics\n"));
1680
2.87k
    ascii().addPos(pos);
1681
2.87k
    ascii().addNote("Entries(Graphic):#sz=0");
1682
2.87k
    return true;
1683
2.87k
  }
1684
3.56k
  long endPos = pos+4+length;
1685
3.56k
  input->seek(length, librevenge::RVNG_SEEK_CUR);
1686
3.56k
  if (long(input->tell()) != endPos) {
1687
2.37k
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: file is too short\n"));
1688
2.37k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1689
2.37k
    return false;
1690
2.37k
  }
1691
1692
1.18k
  f.str("");
1693
1.18k
  f << "Paragraph" << data.m_type << "(III):";
1694
1695
1.18k
  MWAWBox2f box;
1696
1.18k
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1697
1.18k
  auto res = MWAWPictData::check(input, static_cast<int>(length), box);
1698
1.18k
  if (res == MWAWPict::MWAW_R_BAD) {
1699
666
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: can not find the picture\n"));
1700
666
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1701
666
    return false;
1702
666
  }
1703
1704
523
  MWAWVec2f actualSize(0,0), naturalSize(actualSize);
1705
523
  if (box.size().x() > 0 && box.size().y()  > 0) {
1706
84
    if (actualSize.x() <= 0 || actualSize.y() <= 0) actualSize = box.size();
1707
84
    naturalSize = box.size();
1708
84
  }
1709
439
  else {
1710
439
    MWAW_DEBUG_MSG(("WriterPlsParser::readGraphic: can not find the picture size\n"));
1711
439
    actualSize = MWAWVec2f(100,100);
1712
439
  }
1713
1714
523
  MWAWPosition pictPos=MWAWPosition(MWAWVec2f(0,0),actualSize, librevenge::RVNG_POINT);
1715
523
  pictPos.setRelativePosition(MWAWPosition::Char);
1716
523
  pictPos.setNaturalSize(naturalSize);
1717
523
  f << pictPos;
1718
1719
  // get the picture
1720
523
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1721
523
  std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, static_cast<int>(length)));
1722
523
  if (getTextListener()) {
1723
523
    auto para=getTextListener()->getParagraph();
1724
523
    para.setInterline(info.m_height, librevenge::RVNG_POINT);
1725
523
    getTextListener()->setParagraph(para);
1726
523
    MWAWEmbeddedObject picture;
1727
523
    if (pict && pict->getBinary(picture))
1728
520
      getTextListener()->insertPicture(pictPos, picture);
1729
523
    getTextListener()->insertEOL();
1730
523
    para.setInterline(1.0, librevenge::RVNG_PERCENT);
1731
523
    getTextListener()->setParagraph(para);
1732
523
  }
1733
523
  if (pict)
1734
520
    ascii().skipZone(pos+4, pos+4+length-1);
1735
1736
523
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1737
1738
523
  ascii().addPos(pos);
1739
523
  ascii().addNote(f.str().c_str());
1740
1741
523
  ascii().addPos(endPos);
1742
523
  ascii().addNote("_");
1743
1744
523
  return true;
1745
1.18k
}
1746
1747
////////////////////////////////////////////////////////////
1748
// read a paragraph
1749
////////////////////////////////////////////////////////////
1750
bool WriterPlsParser::readUnknown(WriterPlsParserInternal::ParagraphInfo const &info)
1751
31.2k
{
1752
31.2k
  WriterPlsParserInternal::ParagraphData data;
1753
31.2k
  if (!readParagraphData(info, true, data))
1754
13.4k
    return false;
1755
1756
17.7k
  libmwaw::DebugStream f;
1757
1758
17.7k
  MWAWInputStreamPtr input = getInput();
1759
17.7k
  long pos = input->tell();
1760
17.7k
  f.str("");
1761
17.7k
  f << "Paragraph" << data.m_type << "(II):";
1762
1763
17.7k
  int numData = data.m_numData[1];
1764
30.0M
  for (int i = 0; i < numData; i++) {
1765
30.0M
    f << "data" << i << "=[";
1766
270M
    for (int j = 0; j < 8; j++) {
1767
240M
      auto val = static_cast<int>(input->readLong(2));
1768
240M
      if (!val) f << "_,";
1769
4.77M
      else f << val << ",";
1770
240M
    }
1771
30.0M
    f << "],";
1772
30.0M
  }
1773
17.7k
  if (long(input->tell()) != data.m_endPos) {
1774
17.4k
    ascii().addDelimiter(input->tell(), '|');
1775
17.4k
    input->seek(data.m_endPos, librevenge::RVNG_SEEK_SET);
1776
17.4k
    f << "#";
1777
17.4k
  }
1778
1779
17.7k
  ascii().addPos(pos);
1780
17.7k
  ascii().addNote(f.str().c_str());
1781
1782
17.7k
  ascii().addPos(input->tell());
1783
17.7k
  ascii().addNote("_");
1784
1785
17.7k
  return true;
1786
31.2k
}
1787
1788
////////////////////////////////////////////////////////////
1789
// read the beginning of a paragraph data
1790
////////////////////////////////////////////////////////////
1791
bool WriterPlsParser::readParagraphData(WriterPlsParserInternal::ParagraphInfo const &info, bool hasFonts,
1792
                                        WriterPlsParserInternal::ParagraphData &data)
1793
355k
{
1794
355k
  libmwaw::DebugStream f;
1795
1796
355k
  MWAWInputStreamPtr input = getInput();
1797
355k
  long pos = info.m_pos;
1798
355k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1799
1800
355k
  data = WriterPlsParserInternal::ParagraphData();
1801
355k
  auto textLength = static_cast<int>(input->readLong(2));
1802
355k
  auto length2 = static_cast<int>(input->readLong(2));
1803
355k
  data.m_endPos = pos+4+textLength+length2;
1804
1805
355k
  if (textLength < 0 || length2 < 0 || !input->checkPosition(data.m_endPos)) {
1806
126k
    MWAW_DEBUG_MSG(("WriterPlsParser::readParagraphData:  paragraph is too short\n"));
1807
126k
    return false;
1808
126k
  }
1809
228k
  if (textLength) {
1810
19.5k
    std::string &text = data.m_text;
1811
6.74M
    for (int i = 0; i < textLength; i++) {
1812
6.74M
      auto c = char(input->readULong(1));
1813
6.74M
      if (c == '\0') return false;
1814
6.72M
      text += c;
1815
6.72M
    }
1816
19.5k
  }
1817
215k
  auto type = static_cast<int>(input->readULong(2));
1818
215k
  data.m_type = (type & 7);
1819
215k
  data.m_typeFlag = (type & 0xFFF8);
1820
1821
215k
  f << "Entries(Paragraph" << data.m_type << "):";
1822
1823
  // format type
1824
215k
  if (info.m_type != data.m_type + (data.m_typeFlag!=0 ? 8 : 0)) {
1825
184k
    MWAW_DEBUG_MSG(("WriterPlsParser::readParagraph: I find an unexpected type\n"));
1826
184k
    f << "#diffType=" << info.m_type << ",";
1827
184k
  }
1828
1829
215k
  data.m_height = static_cast<int>(input->readLong(2));
1830
215k
  data.m_indent[0] = static_cast<int>(input->readLong(2)); // left indent ?
1831
215k
  data.m_width = static_cast<int>(input->readLong(2));
1832
215k
  data.m_indent[1] = static_cast<int>(input->readLong(2)); // first pos indent ?
1833
215k
  data.m_unknown = static_cast<int>(input->readLong(2));
1834
1835
430k
  for (auto &numData : data.m_numData) numData = static_cast<int>(input->readLong(2));
1836
1837
215k
  auto &fonts = data.m_fonts;
1838
215k
  if (hasFonts) {
1839
215k
    long actPos = input->tell();
1840
215k
    if (data.m_numData[0]<0 || !input->checkPosition(actPos+data.m_numData[0]*16)) {
1841
59.2k
      MWAW_DEBUG_MSG(("WriterPlsParser::readParagraph: pb reading the number of fonts\n"));
1842
59.2k
      f << "###numFonts=" << data.m_numData[0] << ",";
1843
59.2k
    }
1844
156k
    else if (!readFonts(data.m_numData[0], data.m_type, fonts)) {
1845
0
      MWAW_DEBUG_MSG(("WriterPlsParser::readParagraph: pb with the fonts\n"));
1846
0
      input->seek(actPos+data.m_numData[0]*16, librevenge::RVNG_SEEK_SET);
1847
0
    }
1848
215k
  }
1849
1850
215k
  f << data;
1851
4.80M
  for (size_t i = 0; i < fonts.size(); i++) {
1852
4.58M
    f << "font" << i << "=[";
1853
#ifdef DEBUG
1854
    f << fonts[i].m_font.getDebugString(getFontConverter());
1855
#endif
1856
4.58M
    f << fonts[i] << "],";
1857
4.58M
  }
1858
215k
  ascii().addPos(pos);
1859
215k
  ascii().addNote(f.str().c_str());
1860
1861
215k
  return true;
1862
228k
}
1863
1864
////////////////////////////////////////////////////////////
1865
// read a series of fonts
1866
////////////////////////////////////////////////////////////
1867
bool WriterPlsParser::readFonts
1868
(int nFonts, int type, std::vector<WriterPlsParserInternal::Font> &fonts)
1869
156k
{
1870
156k
  fonts.resize(0);
1871
156k
  MWAWInputStreamPtr input = getInput();
1872
156k
  bool hasFontExtra = true;
1873
156k
  switch (type) {
1874
123k
  case 0: // find in these case junk in the last part of font
1875
127k
  case 2:
1876
131k
  case 4:
1877
131k
    hasFontExtra = false;
1878
131k
    break;
1879
24.3k
  default:
1880
24.3k
    break;
1881
156k
  }
1882
156k
  int actPos = 0;
1883
156k
  libmwaw::DebugStream f;
1884
4.74M
  for (int i = 0; i < nFonts; i++) {
1885
4.58M
    if (!input->checkPosition(input->tell()+16)) {
1886
0
      MWAW_DEBUG_MSG(("WriterPlsParser::readFonts: the zone seems too short\n"));
1887
0
      break;
1888
0
    }
1889
4.58M
    WriterPlsParserInternal::Font fInfo;
1890
4.58M
    f.str("");
1891
4.58M
    auto val = static_cast<int>(input->readLong(2)); // 65|315
1892
4.58M
    if (val) f << "dim?=" << val << ",";
1893
18.3M
    for (int j = 0; j < 3; j++) { // always 0: a color ?
1894
13.7M
      val = static_cast<int>(input->readLong(1));
1895
13.7M
      if (val) f << "f" << j << "=" << val << ",";
1896
13.7M
    }
1897
4.58M
    MWAWFont &font = fInfo.m_font;
1898
4.58M
    font.setId(static_cast<int>(input->readULong(1)));
1899
4.58M
    auto flag = static_cast<int>(input->readULong(1));
1900
4.58M
    uint32_t flags = 0;
1901
4.58M
    if (flag&0x1) flags |= MWAWFont::boldBit;
1902
4.58M
    if (flag&0x2) flags |= MWAWFont::italicBit;
1903
4.58M
    if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
1904
4.58M
    if (flag&0x8) flags |= MWAWFont::embossBit;
1905
4.58M
    if (flag&0x10) flags |= MWAWFont::shadowBit;
1906
4.58M
    if (flag&0x60)
1907
945k
      f << "#fl=" << std::hex << (flag&0x60) << std::dec << ",";
1908
4.58M
    if (flag&0x80) f << "fl80,"; // frequent, find on complete line,
1909
1910
4.58M
    flag= static_cast<int>(input->readULong(1));
1911
4.58M
    if (flag&2) font.set(MWAWFont::Script::super100());
1912
4.58M
    if (flag&4) font.set(MWAWFont::Script::sub100());
1913
4.58M
    if (flag&0x10) f << "flA10,";// also frequent, find on complete line
1914
4.58M
    if (flag&0xE9) f << "#flA=" << std::hex << (flag&0xE9) << std::dec << ",";
1915
4.58M
    font.setFlags(flags);
1916
4.58M
    val = static_cast<int>(input->readLong(1));// always 0
1917
4.58M
    if (val)
1918
2.19M
      f << "#g0=" << val << ",";
1919
4.58M
    font.setSize(float(input->readLong(1)));
1920
4.58M
    fInfo.m_firstChar = actPos;
1921
4.58M
    auto nChar = static_cast<int>(input->readULong(2));
1922
4.58M
    actPos += nChar;
1923
4.58M
    if (!hasFontExtra)
1924
3.74M
      input->seek(4, librevenge::RVNG_SEEK_CUR);
1925
844k
    else { // always 0
1926
2.53M
      for (int j = 0; j < 2; j++) {
1927
1.68M
        val = static_cast<int>(input->readLong(2));
1928
1.68M
        if (val) f << "g" << j+1 << "=" << val << ",";
1929
1.68M
      }
1930
844k
    }
1931
4.58M
    font.m_extra+=f.str();
1932
4.58M
    fonts.push_back(fInfo);
1933
4.58M
  }
1934
1935
156k
  return true;
1936
156k
}
1937
1938
////////////////////////////////////////////////////////////
1939
// read a series of lines
1940
////////////////////////////////////////////////////////////
1941
bool WriterPlsParser::readLines
1942
(WriterPlsParserInternal::ParagraphInfo const &/*info*/,
1943
 int nLines, std::vector<WriterPlsParserInternal::Line> &lines)
1944
64.5k
{
1945
64.5k
  lines.resize(0);
1946
64.5k
  MWAWInputStreamPtr input = getInput();
1947
1948
64.5k
  int actPos = 0;
1949
175M
  for (int i = 0; i < nLines; i++) {
1950
175M
    WriterPlsParserInternal::Line lInfo;
1951
175M
    lInfo.m_height = static_cast<int>(input->readLong(2));
1952
175M
    lInfo.m_maxFontSize = static_cast<int>(input->readLong(2)); // checkMe
1953
175M
    lInfo.m_width = static_cast<int>(input->readLong(2));
1954
175M
    auto nChar = static_cast<int>(input->readLong(2));
1955
175M
    lInfo.m_firstChar = actPos;
1956
175M
    actPos += nChar;
1957
    /*
1958
       f0 always 0
1959
       f1 almost always 0, if not 1
1960
       f2 almost always 0, if not 2, 3, 4, c
1961
       f3 almost always 0, if not 200, 400, 6465, 7600, dfc, e03, e04, e06 : junk?
1962
     */
1963
701M
    for (auto &fl : lInfo.m_flags) fl = static_cast<int>(input->readLong(2));
1964
175M
    lines.push_back(lInfo);
1965
175M
  }
1966
64.5k
  return true;
1967
64.5k
}
1968
1969
////////////////////////////////////////////////////////////
1970
// read the print info
1971
////////////////////////////////////////////////////////////
1972
bool WriterPlsParser::readPrintInfo()
1973
31.6k
{
1974
31.6k
  MWAWInputStreamPtr input = getInput();
1975
31.6k
  long pos = input->tell();
1976
31.6k
  libmwaw::DebugStream f;
1977
  // print info
1978
31.6k
  libmwaw::PrinterInfo info;
1979
31.6k
  if (!info.read(input)) return false;
1980
31.2k
  f << "Entries(PrintInfo):"<< info;
1981
1982
31.2k
  MWAWVec2i paperSize = info.paper().size();
1983
31.2k
  MWAWVec2i pageSize = info.page().size();
1984
31.2k
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1985
30.9k
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
1986
1987
  // define margin from print info
1988
30.7k
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1989
30.7k
  MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
1990
1991
  // move margin left | top
1992
30.7k
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1993
30.7k
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1994
30.7k
  lTopMargin -= MWAWVec2i(decalX, decalY);
1995
30.7k
  rBotMargin += MWAWVec2i(decalX, decalY);
1996
1997
  // decrease right | bottom
1998
30.7k
  int rightMarg = rBotMargin.x() -50;
1999
30.7k
  if (rightMarg < 0) rightMarg=0;
2000
30.7k
  int botMarg = rBotMargin.y() -50;
2001
30.7k
  if (botMarg < 0) botMarg=0;
2002
2003
30.7k
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
2004
30.7k
  getPageSpan().setMarginBottom(botMarg/72.0);
2005
30.7k
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
2006
30.7k
  getPageSpan().setMarginRight(rightMarg/72.0);
2007
30.7k
  getPageSpan().setFormLength(paperSize.y()/72.);
2008
30.7k
  getPageSpan().setFormWidth(paperSize.x()/72.);
2009
2010
30.7k
  ascii().addPos(pos);
2011
30.7k
  ascii().addNote(f.str().c_str());
2012
2013
30.7k
  input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
2014
30.7k
  if (long(input->tell()) != pos+0x78) {
2015
0
    MWAW_DEBUG_MSG(("WriterPlsParser::readPrintInfo: file is too short\n"));
2016
0
    return false;
2017
0
  }
2018
2019
30.7k
  return true;
2020
30.7k
}
2021
2022
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: