Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/SpringBoardParser.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 <cmath>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <sstream>
39
#include <utility>
40
41
#include <librevenge/librevenge.h>
42
43
#include "MWAWGraphicListener.hxx"
44
#include "MWAWGraphicShape.hxx"
45
#include "MWAWGraphicStyle.hxx"
46
#include "MWAWHeader.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPictBitmap.hxx"
49
#include "MWAWPictData.hxx"
50
#include "MWAWPosition.hxx"
51
#include "MWAWSection.hxx"
52
#include "MWAWSubDocument.hxx"
53
54
#include "SpringBoardParser.hxx"
55
56
/** Internal: the structures of a SpringBoardParser */
57
namespace SpringBoardParserInternal
58
{
59
//! Internal: a structure used to store the frame property in SpringBoardParserInternal
60
struct Frame {
61
  //! constructor
62
  Frame()
63
0
    : m_type(-1)
64
0
    , m_style(MWAWGraphicStyle::emptyStyle())
65
0
    , m_numSubZones(0)
66
0
    , m_numColumns(1)
67
0
    , m_columnBoxes()
68
0
  {
69
0
  }
70
  //! the frame type: 0: layout, 1: text, 2: graphic
71
  int m_type;
72
  //! the frame style
73
  MWAWGraphicStyle m_style;
74
  //! the number of sub zone (for a text frame)
75
  int m_numSubZones;
76
  //! the external and the internal box
77
  MWAWBox2i m_boxes[2];
78
  //! the number of columns: for a text frame
79
  int m_numColumns;
80
  //! the child box: one by column for text and layout
81
  std::vector<MWAWBox2i> m_columnBoxes;
82
};
83
84
//! Internal: a structure used to store a link in SpringBoardParserInternal
85
struct Link {
86
  //! constructor
87
  Link()
88
0
    : m_font()
89
0
  {
90
0
    for (auto &lnk : m_links)
91
0
      lnk=std::make_pair(-1, -1);
92
0
  }
93
  //! returns true if the link stores somme text
94
  bool hasText() const
95
0
  {
96
0
    for (auto const &entry : m_texts) {
97
0
      if (entry.valid()) return true;
98
0
    }
99
0
    return false;
100
0
  }
101
  //! the font
102
  MWAWFont m_font;
103
  //! the top and bottom text
104
  MWAWEntry m_texts[2];
105
  //! the next and previous link
106
  std::pair<int, int> m_links[2];
107
};
108
//! Internal: a structure used to store the shape data in SpringBoardParserInternal
109
struct Shape {
110
  //! a paragraph contained in a SpringBoardParserInternal::Shape
111
  struct Paragraph {
112
    //! constructor
113
    Paragraph()
114
0
      : m_numChars(0)
115
0
      , m_firstChar(0)
116
0
      , m_newColumn(false)
117
0
      , m_numCharStyles(0)
118
0
      , m_textZoneId(-1)
119
0
      , m_paragraphStyle(-1)
120
0
      , m_charEntry()
121
0
    {
122
0
    }
123
    //! the number of character
124
    int m_numChars;
125
    //! the first character
126
    int m_firstChar;
127
    //! a flag to know if we need to change column: USEME
128
    bool m_newColumn;
129
    //! the number of character style
130
    int m_numCharStyles;
131
    //! the text zone id
132
    int m_textZoneId;
133
    //! the paragraph style
134
    int m_paragraphStyle;
135
    //! the character style zone
136
    MWAWEntry m_charEntry;
137
  };
138
  //! constructor
139
  Shape()
140
0
    : m_type(0)
141
0
    , m_paragraphs()
142
0
    , m_pictEntry()
143
0
  {
144
0
  }
145
  //! the shape type: 0: layout, 1: text, 2: graphic
146
  int m_type;
147
  //! the list of paragraph
148
  std::vector<Paragraph> m_paragraphs;
149
  //! the picture entry: graphic only
150
  MWAWEntry m_pictEntry;
151
};
152
153
////////////////////////////////////////
154
//! Internal: the Header/Footer of a SpringBoardParser
155
struct HeaderFooter {
156
  //! constructor
157
  HeaderFooter()
158
0
    : m_position(0)
159
0
    , m_type(0)
160
0
    , m_pageNumber(0)
161
0
    , m_font()
162
0
  {
163
0
  }
164
  //! the header/footer position 1: TC, TR, TL, BC, BR, BL, FacingT, FacingB
165
  int m_position;
166
  //! the numbering type: 0: numeric, 1/2: small/big roman, 3/4: small/big alpha, 5-7: full minu,MAJU,Title, 8: none
167
  int m_type;
168
  //! the first page numbering
169
  int m_pageNumber;
170
  //! the font
171
  MWAWFont m_font;
172
  //! the prefix/postfix zones string
173
  MWAWEntry m_zones[2];
174
};
175
176
////////////////////////////////////////
177
//! Internal: the state of a SpringBoardParser
178
struct State {
179
  //! constructor
180
  State()
181
290
    : m_numPages(1)
182
290
    , m_entriesListMap()
183
290
    , m_entries2ListMap()
184
290
    , m_pageIdToDimensionMap()
185
290
    , m_pageIdToHeaderFooterMap()
186
290
    , m_idToFrameMap()
187
290
    , m_idToShapeMap()
188
290
    , m_idToLinkMap()
189
290
    , m_idToTextEntriesMap()
190
290
    , m_idToParagraphMap()
191
192
290
    , m_parsedZonesMap()
193
290
  {
194
290
  }
195
196
  //! returns the name of a data zone
197
  std::string getDataZoneName(int id) const
198
0
  {
199
0
    char const *wh[]= {"Doc", "Page", "FramStyle", "FramLink", nullptr,
200
0
                       nullptr, nullptr, nullptr, "ParaStyle", "Text"
201
0
                      };
202
0
    if (id>=0 && id<10 && wh[id])
203
0
      return wh[id];
204
0
    std::stringstream s;
205
0
    s << "List" << id;
206
0
    return s.str();
207
0
  }
208
  //! the number of pages
209
  int m_numPages;
210
  //! a map zone id to list's entry
211
  std::map<int, MWAWEntry> m_entriesListMap;
212
  //! a map id to the last zone entries
213
  std::map<int, MWAWEntry> m_entries2ListMap;
214
  //! the map pageId to page dimension
215
  std::map<int, MWAWBox2i> m_pageIdToDimensionMap;
216
  //! the map pageId to header footer
217
  std::map<int, HeaderFooter> m_pageIdToHeaderFooterMap;
218
  //! the map (page,id) to frame map
219
  std::map<std::pair<int, int>, Frame> m_idToFrameMap;
220
  //! the map (page,id) to shape map
221
  std::map<std::pair<int, int>, Shape> m_idToShapeMap;
222
  //! the map (page,id) to link map
223
  std::map<std::pair<int, int>, Link> m_idToLinkMap;
224
  //! the map id to text entries
225
  std::map<int, MWAWEntry> m_idToTextEntriesMap;
226
  //! the map id to paragraph
227
  std::map<int, MWAWParagraph> m_idToParagraphMap;
228
229
  //! the list of parsed zone
230
  std::map<long, long> m_parsedZonesMap;
231
};
232
233
////////////////////////////////////////
234
//! Internal: the subdocument of a SpringBoardParser
235
class SubDocument final : public MWAWSubDocument
236
{
237
public:
238
  //! constructor knowning the header/footer id
239
  SubDocument(SpringBoardParser &pars, MWAWInputStreamPtr const &input, int hfId)
240
0
    : MWAWSubDocument(&pars, input, MWAWEntry())
241
0
    , m_hfId(hfId)
242
0
    , m_linkId({-1, -1})
243
0
  , m_linkTop(true)
244
0
  , m_pageId({-1, -1})
245
0
  , m_minParagraph(-1)
246
0
  , m_maxParagraph(-1)
247
0
  {
248
0
  }
249
250
  //! constructor corresponding to a layout/textbox shape
251
  SubDocument(SpringBoardParser &pars, MWAWInputStreamPtr const &input, std::pair<int, int> const &pageId,
252
              std::pair<int, int> const &paras= {-1, -1})
253
0
    : MWAWSubDocument(&pars, input, MWAWEntry())
254
0
    , m_hfId(-1)
255
0
    , m_linkId({-1, -1})
256
0
  , m_linkTop(true)
257
0
  , m_pageId(pageId)
258
0
  , m_minParagraph(paras.first)
259
0
  , m_maxParagraph(paras.second)
260
0
  {
261
0
  }
262
  //! constructor corresponding to a link shape
263
  SubDocument(SpringBoardParser &pars, MWAWInputStreamPtr const &input, std::pair<int, int> const &linkId,
264
              bool isTop)
265
0
    : MWAWSubDocument(&pars, input, MWAWEntry())
266
0
    , m_hfId(-1)
267
0
    , m_linkId(linkId)
268
0
    , m_linkTop(isTop)
269
0
    , m_pageId({-1, -1})
270
0
  , m_minParagraph(-1)
271
0
  , m_maxParagraph(-1)
272
0
  {
273
0
  }
274
  //! destructor
275
0
  ~SubDocument() final {}
276
277
  //! operator!=
278
  bool operator!=(MWAWSubDocument const &doc) const final
279
0
  {
280
0
    if (MWAWSubDocument::operator!=(doc)) return true;
281
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
282
0
    if (!sDoc) return true;
283
0
    if (sDoc->m_hfId != m_hfId) return true;
284
0
    if (sDoc->m_linkId != m_linkId) return true;
285
0
    if (sDoc->m_linkTop != m_linkTop) return true;
286
0
    if (sDoc->m_pageId != m_pageId) return true;
287
0
    if (sDoc->m_minParagraph != m_minParagraph) return true;
288
0
    if (sDoc->m_maxParagraph != m_maxParagraph) return true;
289
0
    return false;
290
0
  }
291
292
  //! the parser function
293
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
294
295
protected:
296
  //! the header/footer zone id
297
  int m_hfId;
298
  //! the text link id
299
  std::pair<int, int> m_linkId;
300
  //! a flag to know if we need to send the top or the bottom text
301
  bool m_linkTop;
302
  //! the text page id
303
  std::pair<int, int> m_pageId;
304
  //! the minimum and maximum paragraph
305
  int m_minParagraph, m_maxParagraph;
306
private:
307
  SubDocument(SubDocument const &orig) = delete;
308
  SubDocument &operator=(SubDocument const &orig) = delete;
309
};
310
311
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType)
312
0
{
313
0
  if (!listener || !listener->canWriteText()) {
314
0
    MWAW_DEBUG_MSG(("SpringBoardParserInternal::SubDocument::parse: no listener\n"));
315
0
    return;
316
0
  }
317
0
  auto parser=dynamic_cast<SpringBoardParser *>(m_parser);
318
0
  if (!parser) {
319
0
    MWAW_DEBUG_MSG(("SpringBoardParserInternal::SubDocument::parse: no parser\n"));
320
0
    return;
321
0
  }
322
0
  long pos = m_input->tell();
323
0
  if (m_hfId>=0)
324
0
    parser->sendHeaderFooter(m_hfId);
325
0
  else if (m_linkId.first != -1)
326
0
    parser->sendLinkShape(m_linkId, m_linkTop);
327
0
  else
328
0
    parser->sendTextShape(m_pageId, m_minParagraph, m_maxParagraph);
329
0
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
330
0
}
331
332
333
}
334
335
////////////////////////////////////////////////////////////
336
// constructor/destructor, ...
337
////////////////////////////////////////////////////////////
338
SpringBoardParser::SpringBoardParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
339
138
  : MWAWGraphicParser(input, rsrcParser, header)
340
138
  , m_state(new SpringBoardParserInternal::State)
341
138
{
342
138
  setAsciiName("main-1");
343
344
138
  getPageSpan().setMargins(0.1);
345
138
}
346
347
SpringBoardParser::~SpringBoardParser()
348
138
{
349
138
}
350
351
bool SpringBoardParser::isPositionValid(long pos) const
352
0
{
353
0
  MWAWEntry entry;
354
0
  entry.setBegin(pos);
355
0
  entry.setLength(0);
356
0
  return isEntryValid(entry);
357
0
}
358
359
bool SpringBoardParser::isEntryValid(MWAWEntry const &entry) const
360
7
{
361
7
  auto input=const_cast<SpringBoardParser *>(this)->getInput();
362
7
  if (!input || entry.begin()<0x80 || !input->checkPosition(entry.end()))
363
6
    return false;
364
1
  auto it=m_state->m_parsedZonesMap.upper_bound(entry.begin());
365
1
  if (it!=m_state->m_parsedZonesMap.begin())
366
0
    --it;
367
1
  while (it!=m_state->m_parsedZonesMap.end()) {
368
0
    if (it->first>=entry.end())
369
0
      return true;
370
0
    if (it->second>entry.begin())
371
0
      return false;
372
0
    ++it;
373
0
  }
374
1
  return true;
375
1
}
376
377
////////////////////////////////////////////////////////////
378
// the parser
379
////////////////////////////////////////////////////////////
380
void SpringBoardParser::parse(librevenge::RVNGDrawingInterface *docInterface)
381
14
{
382
14
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
383
14
  bool ok = false;
384
14
  try {
385
    // create the asciiFile
386
14
    ascii().setStream(getInput());
387
14
    ascii().open(asciiName());
388
14
    checkHeader(nullptr);
389
14
    ok = createZones();
390
14
    if (ok) {
391
0
      createDocument(docInterface);
392
393
0
      auto listener=getGraphicListener();
394
0
      if (!listener)
395
0
        ok=false;
396
0
      else {
397
0
        for (int pg=0; pg<m_state->m_numPages; ++pg) {
398
0
          if (pg)
399
0
            listener->insertBreak(MWAWListener::PageBreak);
400
0
          auto fIt=m_state->m_idToFrameMap.lower_bound(std::make_pair(pg+1, -1));
401
0
          while (fIt!=m_state->m_idToFrameMap.end() && fIt->first.first==pg+1)
402
0
            sendFrame(fIt++->first);
403
0
        }
404
0
      }
405
0
    }
406
14
    ascii().reset();
407
14
  }
408
14
  catch (...) {
409
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parse: exception catched when parsing\n"));
410
0
    ok = false;
411
0
  }
412
413
14
  resetGraphicListener();
414
14
  if (!ok) throw(libmwaw::ParseException());
415
14
}
416
417
////////////////////////////////////////////////////////////
418
// create the document
419
////////////////////////////////////////////////////////////
420
void SpringBoardParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
421
0
{
422
0
  if (!documentInterface) return;
423
0
  if (getGraphicListener()) {
424
0
    MWAW_DEBUG_MSG(("SpringBoardParser::createDocument: listener already exist\n"));
425
0
    return;
426
0
  }
427
428
  // create the page list
429
0
  int numPages=std::max<int>(1,m_state->m_numPages);
430
0
  auto fIt=m_state->m_idToFrameMap.rbegin();
431
0
  if (fIt!=m_state->m_idToFrameMap.rend()) {
432
0
    if (fIt->first.first>numPages) {
433
0
      MWAW_DEBUG_MSG(("SpringBoardParser::createDocument: oops, find some frame which are on unknown page\n"));
434
0
    }
435
0
    else if (fIt->first.first<numPages && fIt->first.first>1)
436
0
      numPages=fIt->first.first;
437
0
  }
438
  // FIXME: we must also look if we find some page numbering with pageId>numPages
439
0
  m_state->m_numPages=numPages;
440
0
  std::vector<MWAWPageSpan> pageList;
441
0
  MWAWPageSpan ps;
442
0
  for (int pg=1; pg<=numPages; ++pg) {
443
0
    ps=getPageSpan();
444
0
    auto dimIt=m_state->m_pageIdToDimensionMap.find(pg);
445
0
    if (dimIt!=m_state->m_pageIdToDimensionMap.end()) {
446
0
      auto const &sz=dimIt->second[1];
447
0
      if (sz[0]>0 && sz[1]>0) {
448
0
        ps.setFormWidth(double(sz[0])/72);
449
0
        ps.setFormLength(double(sz[1])/72);
450
0
      }
451
0
    }
452
    // FIXME: look like a header/footer in page N is also replicated as header/footer for page N+1, N+2, ...
453
0
    auto hfIt=m_state->m_pageIdToHeaderFooterMap.find(pg);
454
0
    if (hfIt!=m_state->m_pageIdToHeaderFooterMap.end()) {
455
0
      auto const &hf=hfIt->second;
456
0
      if (hf.m_type>0 && hf.m_type<=8) {
457
0
        MWAWHeaderFooter hF((hf.m_type<=3 || hf.m_type==7) ? MWAWHeaderFooter::HEADER : MWAWHeaderFooter::FOOTER,
458
0
                            MWAWHeaderFooter::ALL);
459
0
        auto subdoc=std::make_shared<SpringBoardParserInternal::SubDocument>(*this, getInput(), pg);
460
0
        hF.m_subDocument=subdoc;
461
0
        ps.setHeaderFooter(hF);
462
0
      }
463
0
      else {
464
0
        MWAW_DEBUG_MSG(("SpringBoardParser::createDocument: oops, find unknown hf type=%d\n", hf.m_type));
465
0
      }
466
0
    }
467
0
    pageList.push_back(ps);
468
0
  }
469
470
0
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
471
0
  setGraphicListener(listen);
472
0
  listen->startDocument();
473
0
}
474
475
476
////////////////////////////////////////////////////////////
477
//
478
// Intermediate level
479
//
480
////////////////////////////////////////////////////////////
481
bool SpringBoardParser::createZones()
482
14
{
483
14
  MWAWInputStreamPtr input = getInput();
484
14
  input->seek(4, librevenge::RVNG_SEEK_SET);
485
486
14
  libmwaw::DebugStream f;
487
14
  f << "limits=[";
488
28
  for (int i=0; i<2; ++i) {
489
22
    long ptr=long(input->readULong(4));
490
22
    f << std::hex << ptr << std::dec << ",";
491
22
    if (ptr<0x80 || !input->checkPosition(ptr)) {
492
8
      MWAW_DEBUG_MSG(("SpringBoardParser::createZones: find bad limits\n"));
493
8
      f << "###";
494
8
      ascii().addPos(0);
495
8
      ascii().addNote(f.str().c_str());
496
8
      return false;
497
8
    }
498
14
    ascii().addPos(ptr);
499
14
    ascii().addNote(i==0 ? "[A]" : "[B]");
500
14
  }
501
6
  f << "],";
502
503
6
  int val;
504
6
  MWAWEntry entry;
505
6
  entry.setBegin(long(input->readULong(4)));
506
6
  entry.setLength(long(input->readULong(4)));
507
6
  if (entry.valid()) {
508
2
    f << "pagNumb=" << std::hex << entry.begin() << "<->" << entry.end() << std::dec << ",";
509
2
    if (!isEntryValid(entry)) {
510
1
      MWAW_DEBUG_MSG(("SpringBoardParser::createZones: find bad entries for page numbering\n"));
511
1
      f << "###";
512
1
      return false;
513
1
    }
514
1
    m_state->m_parsedZonesMap[entry.begin()]=entry.end();
515
1
    long actPos=input->tell();
516
1
    parsePageNumbering(entry);
517
1
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
518
1
  }
519
23
  for (int i=0; i<10; ++i) {
520
23
    entry.setBegin(long(input->readULong(4)));
521
23
    entry.setLength(long(input->readULong(2)));
522
23
    if (!entry.valid())
523
18
      continue;
524
5
    char const *wh[]= {
525
5
      "doc", "page", "framstyle", "framlink", nullptr,
526
5
      nullptr, nullptr, nullptr, "parastyle", "text"
527
5
    };
528
5
    if (wh[i])
529
4
      f << wh[i] << "=" << std::hex << entry.begin() << "<->" << entry.end() << std::dec << ",";
530
1
    else
531
1
      f << "list" << i << "=" << std::hex << entry.begin() << "<->" << entry.end() << std::dec << ",";
532
5
    if (!isEntryValid(entry)) {
533
5
      MWAW_DEBUG_MSG(("SpringBoardParser::createZones: find bad entries %d\n", i));
534
5
      f << "###";
535
5
      ascii().addPos(0);
536
5
      ascii().addNote(f.str().c_str());
537
5
      return false;
538
5
    }
539
0
    m_state->m_parsedZonesMap[entry.begin()]=entry.end();
540
0
    m_state->m_entriesListMap[i]=entry;
541
0
  }
542
0
  for (int i=0; i<3; ++i) {
543
0
    val=int(input->readLong(2));
544
0
    if (val)
545
0
      f << "f" << i+4 << "=" << val << ",";
546
0
  }
547
0
  for (int i=0; i<3; ++i) {
548
0
    entry.setBegin(long(input->readULong(4)));
549
0
    entry.setLength(long(input->readULong(4)));
550
0
    if (!entry.valid())
551
0
      continue;
552
0
    f << (i==0 ? "shape" : i==1 ? "txtPos" : "frame") << "=" << std::hex << entry.begin() << "<->" << entry.end() << std::dec << ",";
553
0
    if (!isEntryValid(entry)) {
554
0
      MWAW_DEBUG_MSG(("SpringBoardParser::createZones: find bad entries %d\n", i));
555
0
      f << "###";
556
0
      ascii().addPos(0);
557
0
      ascii().addNote(f.str().c_str());
558
0
      return false;
559
0
    }
560
0
    m_state->m_parsedZonesMap[entry.begin()]=entry.end();
561
0
    m_state->m_entries2ListMap[i]=entry;
562
0
  }
563
0
  for (int i=0; i<3; ++i) {
564
0
    val=int(input->readLong(2));
565
0
    if (val)
566
0
      f << "g" << i << "=" << val << ",";
567
0
  }
568
0
  val=int(input->readULong(4)); // 0 or 68ad08
569
0
  if (val)
570
0
    f << "unkn=" << std::hex << val << std::dec << ",";
571
0
  for (int i=0; i<3; ++i) { // g3=0|8
572
0
    val=int(input->readLong(2));
573
0
    if (val)
574
0
      f << "g" << i+3 << "=" << val << ",";
575
0
  }
576
0
  f << "num[shapes]=" << input->readLong(2) << ",";
577
0
  ascii().addPos(0);
578
0
  ascii().addNote(f.str().c_str());
579
580
0
  for (auto const &it : m_state->m_entriesListMap)
581
0
    parseDataList(it.first, it.second);
582
583
0
  for (auto const &it : m_state->m_entries2ListMap)
584
0
    parseLastZone(it.first, it.second);
585
0
  return true;
586
0
}
587
588
bool SpringBoardParser::readFont(MWAWFont &font, int szFieldSize)
589
0
{
590
0
  font=MWAWFont();
591
0
  MWAWInputStreamPtr input = getInput();
592
0
  if (!input)
593
0
    return false;
594
0
  long pos=input->tell();
595
0
  if ((szFieldSize!=1 && szFieldSize!=2) || !input->checkPosition(pos+4+szFieldSize)) {
596
0
    MWAW_DEBUG_MSG(("SpringBoardParser::readFont: the zone seems bad\n"));
597
0
    return false;
598
0
  }
599
600
0
  libmwaw::DebugStream f;
601
0
  font.setId(int(input->readULong(2)));
602
0
  int val=int(input->readULong(2));
603
0
  uint32_t flags=0;
604
0
  if (val&0x1) flags |= MWAWFont::boldBit;
605
0
  if (val&0x2) flags |= MWAWFont::italicBit;
606
0
  if (val&0x4) {
607
0
    font.setUnderlineStyle(MWAWFont::Line::Simple);
608
0
    if (val&0x80)
609
0
      f << "underline[char],";
610
0
    if (val&0x100)
611
0
      f << "underline[word],";
612
    // &0x8000 all
613
0
    val&=0x7e7f;
614
0
  }
615
0
  if (val&0x8) flags |= MWAWFont::embossBit;
616
0
  if (val&0x10) flags |= MWAWFont::shadowBit;
617
0
  if (val&0x20)
618
0
    font.set(MWAWFont::Script::super100());
619
0
  if (val&0x40)
620
0
    font.set(MWAWFont::Script::sub100());
621
0
  if ((val&0x600)==0x600) {
622
0
    flags |= MWAWFont::reverseVideoBit;
623
0
    f << "pat[inverse]=" << ((val&0x7800)>>11) << ","; // FIXME use pattern
624
0
    val &= 0x81ff;
625
0
  }
626
0
  if (val&0xff80) f << "font[fl]=#" << std::hex << (val&0xff80) << std::dec << ",";
627
0
  font.setSize(float(input->readLong(szFieldSize)));
628
0
  font.setFlags(flags);
629
0
  font.m_extra=f.str();
630
0
  return true;
631
0
}
632
633
bool SpringBoardParser::parsePageNumbering(MWAWEntry const &entry)
634
1
{
635
1
  MWAWInputStreamPtr input = getInput();
636
1
  if (!input)
637
0
    return false;
638
1
  if (!entry.valid() || (entry.length()%98)!=0 || !input->checkPosition(entry.end())) {
639
1
    MWAW_DEBUG_MSG(("SpringBoardParser::parsePageNumbering: find unvalid entry\n"));
640
1
    return false;
641
1
  }
642
0
  ascii().addPos(entry.end());
643
0
  ascii().addNote("_");
644
645
0
  libmwaw::DebugStream f;
646
0
  f << "Entries(PagNumbering):";
647
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
648
0
  ascii().addPos(entry.begin());
649
0
  ascii().addNote(f.str().c_str());
650
0
  int N=int(entry.length()/98);
651
0
  int val;
652
0
  for (int i=0; i<N; ++i) {
653
0
    long pos=input->tell();
654
0
    f.str("");
655
0
    f << "PagNumbering-" << i << ":";
656
0
    int pg=int(input->readLong(2));
657
0
    f << "page=" << pg << ",";
658
0
    SpringBoardParserInternal::HeaderFooter hf;
659
0
    hf.m_type=int(input->readLong(2));
660
0
    if (hf.m_type) f << "number[format]=" << hf.m_type << ",";
661
0
    hf.m_pageNumber=int(input->readLong(2));
662
0
    if (hf.m_pageNumber!=pg) f << "page[number]=" << hf.m_pageNumber << ",";
663
0
    hf.m_position=int(input->readLong(2));
664
0
    f << "pos=" << hf.m_position << ",";
665
666
0
    readFont(hf.m_font, 2);
667
0
    f << hf.m_font.getDebugString(getFontConverter())  << ",";
668
0
    for (int j=0; j<2; ++j) {
669
0
      long actPos=input->tell();
670
0
      int cLen=int(input->readULong(1));
671
0
      if (cLen>40) {
672
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parsePageNumbering: can not read a string\n"));
673
0
        f << "###cLen" << j << "=" << cLen << ",";
674
0
        cLen=0;
675
0
      }
676
0
      hf.m_zones[j].setBegin(actPos+1);
677
0
      hf.m_zones[j].setLength(cLen);
678
0
      std::string text;
679
0
      for (int c=0; c<cLen; ++c)
680
0
        text+=char(input->readULong(1));
681
0
      f << text << ",";
682
0
      input->seek(actPos+40, librevenge::RVNG_SEEK_SET);
683
0
    }
684
0
    for (int j=0; j<2; ++j) {
685
0
      val=int(input->readLong(2));
686
0
      if (val!=(j==0 ? 50 : 90))
687
0
        f << "from[" << (j==0 ? "bottom" : "right") << "]=" << val << ",";
688
0
    }
689
0
    if (m_state->m_pageIdToHeaderFooterMap.count(pg)) {
690
0
      f << "###dup";
691
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parsePageNumbering: an header/footer already exists for the page %d\n", pg));
692
0
    }
693
0
    else
694
0
      m_state->m_pageIdToHeaderFooterMap[pg]=hf;
695
0
    ascii().addPos(pos);
696
0
    ascii().addNote(f.str().c_str());
697
0
    input->seek(pos+98, librevenge::RVNG_SEEK_SET);
698
0
  }
699
0
  return true;
700
1
}
701
702
bool SpringBoardParser::parseDataList(int id, MWAWEntry const &entry)
703
0
{
704
0
  MWAWInputStreamPtr input = getInput();
705
0
  if (!input)
706
0
    return false;
707
0
  if (id<0 || id>=10 || !entry.valid() || !input->checkPosition(entry.end())) {
708
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseDataList: find unvalid entry for id=%d\n", id));
709
0
    return false;
710
0
  }
711
0
  ascii().addPos(entry.end());
712
0
  ascii().addNote("_");
713
714
0
  libmwaw::DebugStream f;
715
0
  std::string const what=m_state->getDataZoneName(id);
716
0
  f << "Entries(" << what << "):";
717
0
  if ((entry.length()%16)!=0) {
718
0
    f << "###";
719
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseDataList: find unexpected size for zone %s\n", what.c_str()));
720
0
    ascii().addPos(entry.begin());
721
0
    ascii().addNote(f.str().c_str());
722
0
    return false;
723
0
  }
724
725
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
726
0
  int num=int(entry.length()/16);
727
0
  std::map<int, std::pair<MWAWVec2i, MWAWEntry> > listZones;
728
0
  for (int st=0; st<num; ++st) {
729
0
    long pos=input->tell();
730
0
    f.str("");
731
0
    if (st==0)
732
0
      f << "Entries(" << what << "):";
733
0
    else
734
0
      f << what << "[st=" << st << "]:";
735
0
    int firstId=int(input->readLong(4));
736
0
    if (firstId)
737
0
      f << "id[first]=" << firstId << ",";
738
0
    MWAWEntry data;
739
0
    data.setBegin(long(input->readULong(4)));
740
0
    data.setLength(long(input->readULong(4)));
741
0
    f << "zone=" << std::hex << data.begin() << "x" << data.end() << std::dec << ",";
742
0
    int nextId=int(input->readLong(4));
743
0
    f << "next[id]=" << nextId << ",";
744
0
    if (!isEntryValid(data)) {
745
0
      f << "###";
746
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseDataList: find unexpected zone for zone %s\n", what.c_str()));
747
0
      return false;
748
0
    }
749
0
    m_state->m_parsedZonesMap[entry.begin()]=entry.end();
750
0
    listZones[st]=std::make_pair(MWAWVec2i(firstId,nextId), data);
751
0
    ascii().addPos(pos);
752
0
    ascii().addNote(f.str().c_str());
753
0
  }
754
0
  for (auto const &it : listZones) {
755
0
    MWAWEntry data;
756
0
    MWAWVec2i indices;
757
0
    std::tie(indices,data)=it.second;
758
0
    if (id==8)
759
0
      parseParagraphStyle(data, indices);
760
0
    else
761
0
      parseData(id, data, indices);
762
0
  }
763
0
  return true;
764
0
}
765
766
bool SpringBoardParser::parseData(int id, MWAWEntry const &entry, MWAWVec2i const &indices)
767
0
{
768
0
  MWAWInputStreamPtr input = getInput();
769
0
  if (!input)
770
0
    return false;
771
0
  if (id<0 || id>=10 || !entry.valid() || !input->checkPosition(entry.end())) {
772
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseData: find unvalid entry for id=%d\n", id));
773
0
    return false;
774
0
  }
775
776
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
777
0
  long pos=input->tell();
778
0
  ascii().addPos(entry.end());
779
0
  ascii().addNote("_");
780
781
0
  libmwaw::DebugStream f;
782
0
  std::string const what=m_state->getDataZoneName(id);
783
0
  int const expectedSize[]= {6, 10, 26, 182, -1,
784
0
                             -1, -1, -1, -1, 512
785
0
                            };
786
0
  if (expectedSize[id]<=0) {
787
0
    f << what << "[header,index=" << indices << "]:";
788
0
    ascii().addPos(pos);
789
0
    ascii().addNote(f.str().c_str());
790
0
    return true;
791
0
  }
792
0
  if (indices[1]<indices[0] || indices[1]-indices[0]<entry.length()/expectedSize[id]) {
793
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseData: find unexpected length for data zone %s\n", what.c_str()));
794
0
    ascii().addPos(pos);
795
0
    ascii().addNote("###");
796
0
    return false;
797
0
  }
798
0
  for (int i=indices[0]; i<indices[1]; ++i) {
799
0
    pos=input->tell();
800
0
    f.str("");
801
0
    f << what << "-dt" << i << "]:";
802
0
    int val;
803
0
    switch (id) {
804
0
    case 0: { // Doc
805
0
      for (int j=0; j<3; ++j) {
806
0
        val=int(input->readLong(2));
807
0
        if (val==1)
808
0
          continue;
809
0
        if (j==2) {
810
0
          m_state->m_numPages=val;
811
0
          f << "num[pages]=" << val << ",";
812
0
        }
813
0
        else
814
0
          f << "num" << j << "=" << val << ",";
815
0
      }
816
0
      break;
817
0
    }
818
0
    case 1: { // Page
819
0
      for (int j=0; j<5; ++j) {
820
0
        val=int(input->readLong(2));
821
0
        int const expected[]= {0,0,0,0, -1};
822
0
        if (val==expected[j])
823
0
          continue;
824
0
        if (j==0)
825
0
          f << "page=" << val << ",";
826
0
        else if (j==3)
827
0
          f << "first[shape]=" << val << ",";
828
0
        else
829
0
          f << "f" << j << "=" << val << ",";
830
0
      }
831
0
      break;
832
0
    }
833
0
    case 2: { // FrameStyle
834
0
      SpringBoardParserInternal::Frame frame;
835
0
      int pageId=int(input->readLong(1));
836
0
      f << "page[id]=" << pageId << ",";
837
0
      val=int(input->readULong(1));
838
0
      frame.m_type=val&3;
839
0
      f << "type=" << frame.m_type << ",";
840
0
      if (val&0x80) f << "crop[image],";
841
0
      val&=0x7c;
842
      // checkme what means type+0x10: multicolumn?
843
0
      f << "fl=" << std::hex << val << std::dec << ","; // 0: layout, 1: text, 2: graphic
844
0
      val=int(input->readULong(1));
845
0
      if (val==0x40)
846
0
        f << "crop[image],"; // checkme
847
0
      else if (val)
848
0
        f << "f0=" << val << ",";
849
0
      auto &style=frame.m_style;
850
0
      int bStyle=int(input->readLong(1));
851
0
      f << "border[style]=" << bStyle << ","; // 0: single, 1: double, 2: 2,1,1, 3: 1,1,2, 4: 1,1,2,1,1, 5: dashed, 6; dotted, 7: big dotted
852
0
      style.m_lineWidth=float(input->readLong(1));
853
0
      if (style.m_lineWidth>0) {
854
0
        f << "line[width]=" << style.m_lineWidth << ",";
855
0
        if (bStyle>=1 && bStyle<=4)
856
0
          style.m_lineWidth*=2;
857
0
        else if (bStyle==5)
858
0
          style.m_lineDashWidth= {10,10};
859
0
        else if (bStyle>=6 && bStyle<=7)
860
0
          style.m_lineDashWidth= {2,2};
861
0
      }
862
0
      val=int(input->readLong(1));
863
0
      if (val!=1) f << "line[pat]=" << val << ",";
864
0
      int page=int(input->readLong(2));
865
0
      f << "page=" << page << ",";
866
0
      for (int j=0; j<5; ++j) { // f5=0|b, f6=0|12, f7=0|100
867
0
        val=int(input->readLong(2));
868
0
        if (!val)
869
0
          continue;
870
0
        if (j==1) {
871
0
          frame.m_numSubZones=val;
872
0
          f << "num[subZones]=" << val << ",";
873
0
        }
874
0
        else if (j==4)
875
0
          f << "gray[scale]=" << val << ",";
876
0
        else
877
0
          f << "f" << j+3 << "=" << val << ",";
878
0
      }
879
0
      for (int j=0; j<2; ++j) {
880
0
        val=int(input->readLong(2));
881
0
        if (val==-1)
882
0
          continue;
883
0
        f << "g" << j << "=" << val << ",";
884
0
      }
885
0
      val=int(input->readLong(4));
886
0
      if (val!=-1) f << "next=F"  << val << ",";
887
0
      auto index=std::make_pair(page, pageId);
888
0
      if (m_state->m_idToFrameMap.count(index)==0)
889
0
        m_state->m_idToFrameMap[index]=frame;
890
0
      else {
891
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseData: find a duplicated frame with id=%dx%d\n", page, pageId));
892
0
        f << "###dup,";
893
0
      }
894
0
      break;
895
0
    }
896
0
    case 3: { // frame header/footer link
897
0
      SpringBoardParserInternal::Link link;
898
0
      f << "unkn=" << std::hex << input->readLong(2) << std::dec << ",";
899
0
      val=int(input->readULong(2));
900
0
      if (val!=1)
901
0
        f << "f0=" << val << ",";
902
0
      readFont(link.m_font, 2);
903
0
      f << link.m_font.getDebugString(getFontConverter())  << ",";
904
905
0
      for (int j=0; j<2; ++j) {
906
0
        long actPos=input->tell();
907
0
        int cLen=int(input->readULong(1));
908
0
        if (cLen>80) {
909
0
          MWAW_DEBUG_MSG(("SpringBoardParser::parseData: can not read a string\n"));
910
0
          f << "###cLen" << j << "=" << cLen << ",";
911
0
          cLen=0;
912
0
        }
913
0
        link.m_texts[j].setBegin(actPos+1);
914
0
        link.m_texts[j].setLength(cLen);
915
0
        std::string text;
916
0
        for (int c=0; c<cLen; ++c) text+=char(input->readULong(1));
917
0
        if (!text.empty())
918
0
          f << (j==0 ? "top" : "bottom") << "[text]=" << text << ",";
919
0
        input->seek(actPos+80, librevenge::RVNG_SEEK_SET);
920
0
      }
921
0
      std::pair<int, int> index;
922
0
      for (int j=0; j<3; ++j) {
923
0
        int pageId[2];
924
0
        for (auto &w : pageId) w=int(input->readLong(2));
925
0
        if (pageId[0]==-1 && pageId[1]==-1) continue;
926
0
        char const *wh[]= {"id", "prev[id]", "next[id]"};
927
0
        if (j==0)
928
0
          index=std::make_pair(pageId[0], pageId[1]);
929
0
        else
930
0
          link.m_links[j-1]=std::make_pair(pageId[0], pageId[1]);
931
0
        f << wh[j] << "=" << MWAWVec2i(pageId[0], pageId[1]) << ",";
932
0
      }
933
0
      if (m_state->m_idToLinkMap.count(index)==0)
934
0
        m_state->m_idToLinkMap[index]=link;
935
0
      else {
936
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseData: find a duplicated link with id=%dx%d\n", index.first, index.second));
937
0
        f << "###dup,";
938
0
      }
939
0
      break;
940
0
    }
941
    // 8: paragraph style, already done
942
0
    case 9: { // Text
943
0
      if (m_state->m_idToTextEntriesMap.count(i)) {
944
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseData: a text entry with id=%d already exists\n", i));
945
0
      }
946
0
      else {
947
0
        MWAWEntry textEntry;
948
0
        textEntry.setBegin(pos);
949
0
        textEntry.setLength(512);
950
0
        m_state->m_idToTextEntriesMap[i]=textEntry;
951
0
      }
952
0
      std::string text;
953
0
      for (int j=0; j<512; ++j) {
954
0
        char c=char(input->readULong(1));
955
0
        if (!c)
956
0
          break;
957
0
        text+=c;
958
0
      }
959
0
      f << text << ",";
960
0
      break;
961
0
    }
962
0
    default:
963
0
      break;
964
0
    }
965
0
    input->seek(pos+expectedSize[id], librevenge::RVNG_SEEK_SET);
966
0
    ascii().addPos(pos);
967
0
    ascii().addNote(f.str().c_str());
968
0
  }
969
0
  return true;
970
0
}
971
972
bool SpringBoardParser::parseParagraphStyle(MWAWEntry const &entry, MWAWVec2i const &indices)
973
0
{
974
0
  MWAWInputStreamPtr input = getInput();
975
0
  if (!input)
976
0
    return false;
977
0
  int const N=indices[1]-indices[0];
978
0
  if (!entry.valid() || !input->checkPosition(entry.end()) || N<0 || entry.length()<4*N) {
979
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: find invalid entry\n"));
980
0
    return false;
981
0
  }
982
0
  ascii().addPos(entry.end());
983
0
  ascii().addNote("_");
984
985
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
986
0
  long pos=input->tell();
987
0
  libmwaw::DebugStream f;
988
0
  f << "ParaStyle[" << N << "]:zones=[";
989
0
  std::map<int, long> ptrs;
990
0
  for (int i=indices[0]; i<indices[1]; ++i) {
991
0
    long ptr=long(input->readULong(4));
992
0
    f << std::hex << ptr << std::dec << ",";
993
0
    if (ptr>=entry.begin()+4*N && ptr+16<=entry.end())
994
0
      ptrs[i]=ptr;
995
0
    else {
996
0
      f << "###";
997
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: find bad ptr\n"));
998
0
    }
999
0
  }
1000
0
  f << "],";
1001
0
  ascii().addPos(pos);
1002
0
  ascii().addNote(f.str().c_str());
1003
0
  int val;
1004
0
  for (auto const &it : ptrs) {
1005
0
    f.str("");
1006
0
    f << "ParaStyle-P" << it.first << ":";
1007
0
    MWAWParagraph para;
1008
0
    for (int i=0; i<4; ++i) {
1009
0
      val=int(input->readULong(1));
1010
0
      if (val==(i==3 ? 1 : 0)) continue;
1011
0
      if (i==0) {
1012
0
        switch (val) {
1013
0
        case 1:
1014
0
          para.m_justify = MWAWParagraph::JustificationCenter;
1015
0
          break;
1016
0
        case 2:
1017
0
          para.m_justify = MWAWParagraph::JustificationRight;
1018
0
          break;
1019
0
        case 3:
1020
0
          para.m_justify = MWAWParagraph::JustificationFull;
1021
0
          break;
1022
0
        default:
1023
0
          MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: find unknown justification\n"));
1024
0
          f << "###align=" << val << ","; // 1: center, 2:right, 3: justify?
1025
0
          break;
1026
0
        }
1027
0
      }
1028
0
      else if (i==1 || i==2)
1029
0
        para.m_spacings[i]=12*float(val)/72; // in percent, so asume font size=12
1030
0
      else
1031
0
        f << "f0=" << val << ",";
1032
0
    }
1033
0
    para.m_marginsUnit=librevenge::RVNG_POINT;
1034
0
    for (int i=0; i<5; ++i) {
1035
0
      val=int(input->readULong(2));
1036
0
      int const expected[]= {1,0,0,0,0};
1037
0
      if (val==expected[i])
1038
0
        continue;
1039
0
      if (i==1) {
1040
0
        if (val&0x8000)
1041
0
          para.m_spacings[2]=12*float(val&0x7fff)/72;
1042
0
        else
1043
0
          para.setInterline(1+float(val), librevenge::RVNG_PERCENT);
1044
0
      }
1045
0
      else if (i>=2 && i<=4)
1046
0
        para.m_margins[i-2]=float(val);
1047
0
      else
1048
0
        f << "f" << i+1 << "=" << val << ","; // 8: related to char style
1049
0
    }
1050
0
    int nTabs=int(input->readULong(2));
1051
0
    if (nTabs) {
1052
0
      if (pos+16+4*nTabs>entry.end()) {
1053
0
        f << "###nTabs=" << nTabs << ",";
1054
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: the number of tabs seems bad\n"));
1055
0
        nTabs=0;
1056
0
      }
1057
0
      for (int i=0; i<nTabs; ++i) {
1058
0
        MWAWTabStop tab;
1059
0
        char c=char(input->readLong(1));
1060
0
        if (c>=0x20 && c<0x7f)
1061
0
          tab.m_leaderCharacter=uint16_t(c);
1062
0
        else {
1063
0
          static bool first=true;
1064
0
          if (first) {
1065
0
            MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: find unexpected leader characters\n"));
1066
0
            first=false;
1067
0
          }
1068
0
          f << "###tab" << i << "=" << int(c) << ",";
1069
0
        }
1070
0
        input->seek(1, librevenge::RVNG_SEEK_CUR);
1071
0
        tab.m_position=float(input->readLong(2))/72;
1072
0
      }
1073
0
    }
1074
0
    f << para;
1075
0
    if (m_state->m_idToParagraphMap.count(it.first)) {
1076
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseParagraphStyle: oops a paragraph with id=%d already exists\n", it.first));
1077
0
      f << "###dup";
1078
0
    }
1079
0
    else
1080
0
      m_state->m_idToParagraphMap[it.first]=para;
1081
0
    ascii().addPos(it.second);
1082
0
    ascii().addNote(f.str().c_str());
1083
0
  }
1084
0
  return true;
1085
0
}
1086
1087
bool SpringBoardParser::parseLastZone(int id, MWAWEntry const &entry)
1088
0
{
1089
0
  MWAWInputStreamPtr input = getInput();
1090
0
  if (!input)
1091
0
    return false;
1092
0
  if (id<0 || id>=3 || !entry.valid() || !input->checkPosition(entry.end())) {
1093
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: find invalid entry for id=%d\n", id));
1094
0
    return false;
1095
0
  }
1096
0
  ascii().addPos(entry.end());
1097
0
  ascii().addNote("_");
1098
1099
0
  libmwaw::DebugStream f, f2;
1100
0
  char const *wh[]= {"Shape", "TxtPos", "Frame"};
1101
0
  std::string const what(wh[id]);
1102
0
  f << "Entries(" << what << "):";
1103
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1104
0
  switch (id) {
1105
0
  case 0: {
1106
0
    if ((entry.length()%8)!=0) {
1107
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: unexpected size\n"));
1108
0
      f << "###";
1109
0
      break;
1110
0
    }
1111
0
    int N=int(entry.length()/8);
1112
0
    std::map<std::pair<int, int>, long> idToPtrs;
1113
0
    for (int i=0; i<N; ++i) {
1114
0
      long pos=input->tell();
1115
0
      f2.str("");
1116
0
      f2 << what << "-" << i << ":";
1117
0
      long beg=long(input->readULong(4));
1118
0
      f2 << "pos=" << std::hex << beg << std::dec << ",";
1119
0
      int pg=int(input->readLong(2));
1120
0
      int pgId=int(input->readLong(2));
1121
0
      if (!isPositionValid(beg) || !input->checkPosition(beg+4)) {
1122
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: a shape position seems bad\n"));
1123
0
        f2 << "###";
1124
0
      }
1125
0
      else
1126
0
        idToPtrs[std::make_pair(pg,pgId)]=beg;
1127
0
      f2 << "page=" << pg << ",";
1128
0
      f2 << "id=" << pgId << ",";
1129
0
      ascii().addPos(pos);
1130
0
      ascii().addNote(f2.str().c_str());
1131
0
    }
1132
0
    for (auto const &it : idToPtrs)
1133
0
      parseShape(it.second, it.first);
1134
0
    break;
1135
0
  }
1136
0
  case 1: { // checkme maybe link
1137
0
    if ((entry.length()%6)!=0) {
1138
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: unexpected size\n"));
1139
0
      f << "###";
1140
0
      break;
1141
0
    }
1142
0
    int N=int(entry.length()/6);
1143
0
    f << "unkn=[";
1144
0
    for (int i=0; i<N; ++i) {
1145
0
      int val=int(input->readLong(4));
1146
0
      f << "last[char]=" << input->readLong(2);
1147
0
      if (val!=-1)
1148
0
        f << ":" << val;
1149
0
      f << ",";
1150
0
    }
1151
0
    f << "],";
1152
0
    break;
1153
0
  }
1154
0
  case 2: { // a list of pages
1155
0
    f << "list,";
1156
0
    if (entry.length()<2) {
1157
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: unexpected size\n"));
1158
0
      f << "###";
1159
0
      break;
1160
0
    }
1161
0
    int N=int(input->readLong(2));
1162
0
    f << "N=" << N << ",";
1163
0
    if (2+8*N>entry.length()) {
1164
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: unexpected N\n"));
1165
0
      f << "###";
1166
0
      break;
1167
0
    }
1168
0
    std::map<int, long> positions;
1169
0
    for (int i=0; i<N; ++i) {
1170
0
      long pos=input->tell();
1171
0
      f2.str("");
1172
0
      f2 << what << "-" << i << "[list]:";
1173
0
      int pg=int(input->readLong(2));
1174
0
      f2 << "page=" << pg << ",";
1175
0
      int val=int(input->readLong(2));
1176
0
      if (val!=pg) f2 << "page2=" << val << ",";
1177
0
      long beg=long(input->readULong(4));
1178
0
      f2 << "pos=" << std::hex << beg << std::dec << ",";
1179
0
      if (beg<entry.begin() || beg>=entry.end()) {
1180
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseLastZone: a position seems bad\n"));
1181
0
        f2 << "###";
1182
0
      }
1183
0
      else
1184
0
        positions[pg]=beg;
1185
0
      ascii().addPos(pos);
1186
0
      ascii().addNote(f2.str().c_str());
1187
0
    }
1188
0
    for (auto const &it : positions)
1189
0
      parseFrames(it.first, it.second);
1190
0
    break;
1191
0
  }
1192
0
  default:
1193
0
    break;
1194
0
  }
1195
0
  ascii().addPos(entry.begin());
1196
0
  ascii().addNote(f.str().c_str());
1197
0
  return true;
1198
0
}
1199
1200
bool SpringBoardParser::parseShape(long begPos, std::pair<int, int> const &pageId)
1201
0
{
1202
0
  MWAWInputStreamPtr input = getInput();
1203
0
  if (!input)
1204
0
    return false;
1205
0
  if (begPos<0x80 || !input->checkPosition(begPos+4)) {
1206
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: the begin position seems bad\n"));
1207
0
    return false;
1208
0
  }
1209
0
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
1210
0
  int type=-1;
1211
0
  auto const fIt=m_state->m_idToFrameMap.find(pageId);
1212
0
  if (fIt==m_state->m_idToFrameMap.end()) {
1213
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: can not find the shape %d-%d\n", pageId.first, pageId.second));
1214
0
  }
1215
0
  else
1216
0
    type=fIt->second.m_type;
1217
0
  SpringBoardParserInternal::Shape shape;
1218
0
  shape.m_type=type;
1219
1220
0
  libmwaw::DebugStream f;
1221
0
  f << "Shape-" << pageId.first << "x" << pageId.second << "[type=" << type << "]:";
1222
0
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
1223
0
  bool asciiUpdated=false;
1224
0
  switch (type) {
1225
0
  case 0:
1226
0
  case 1: {
1227
0
    int N=int(input->readULong(4));
1228
0
    f << "N=" << N << ",";
1229
0
    if (N<0 || N+1>(input->size()-begPos)/4 || !isPositionValid(begPos+4+4*N)) {
1230
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: can not read the number of shapes\n"));
1231
0
      f << "###";
1232
0
      N=0;
1233
0
    }
1234
0
    std::vector<long> listPtrs;
1235
0
    for (int i=0; i<N; ++i) listPtrs.push_back(long(input->readULong(4)));
1236
0
    ascii().addPos(begPos);
1237
0
    ascii().addNote(f.str().c_str());
1238
0
    asciiUpdated=true;
1239
1240
0
    for (long ptr : listPtrs) {
1241
0
      if (!isPositionValid(ptr) || !input->checkPosition(ptr+24)) {
1242
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: a text pointer seems bad\n"));
1243
0
        if (ptr>0)
1244
0
          break;
1245
0
        continue;
1246
0
      }
1247
0
      f.str("");
1248
0
      f << "Shape-" << pageId.first << "x" << pageId.second << ":text,";
1249
0
      SpringBoardParserInternal::Shape::Paragraph para;
1250
0
      input->seek(ptr, librevenge::RVNG_SEEK_SET);
1251
0
      int val=int(input->readULong(2));
1252
0
      if (val&0x8000) {
1253
0
        para.m_newColumn=true;
1254
0
        f << "new[column],";
1255
0
        val &= 0x7fff;
1256
0
      }
1257
0
      if (val)
1258
0
        f << "fl=" << std::hex << val << std::dec << ",";
1259
0
      para.m_numChars=int(input->readULong(2));
1260
0
      f << "num[char]=" << para.m_numChars << ",";
1261
0
      for (int i=0; i<2; ++i) {
1262
0
        val=int(input->readLong(2));
1263
0
        if (!val) continue;
1264
0
        if (i==0) {
1265
0
          para.m_firstChar=val;
1266
0
          f << "first[char]=" << val << ",";
1267
0
        }
1268
0
        else
1269
0
          f << "y[pos]=" << val << ",";
1270
0
      }
1271
0
      val=int(input->readLong(4));
1272
0
      if (val!=ptr) f << "ptr=" << std::hex << val << std::dec << ",";
1273
0
      para.m_numCharStyles=int(input->readLong(4));
1274
0
      f << "num[style]=" << para.m_numCharStyles << ",";
1275
0
      para.m_paragraphStyle=int(input->readLong(4));
1276
0
      f << "para[style]=" << para.m_paragraphStyle << ",";
1277
0
      para.m_textZoneId=int(input->readLong(4));
1278
0
      if (para.m_textZoneId!=-1)
1279
0
        f << "text[id]=" << para.m_textZoneId << ",";
1280
0
      if (ptr+24+10*para.m_numCharStyles<ptr+24 || (input->size()-24-ptr)/10<para.m_numCharStyles ||
1281
0
          !input->checkPosition(ptr+24+10*para.m_numCharStyles)) {
1282
0
        f << "###";
1283
0
        MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: the number of style seems bad\n"));
1284
0
        para.m_numCharStyles=0;
1285
0
      }
1286
0
      para.m_charEntry.setBegin(input->tell());
1287
0
      para.m_charEntry.setLength(10*para.m_numCharStyles);
1288
0
      shape.m_paragraphs.push_back(para);
1289
0
      ascii().addPos(ptr);
1290
0
      ascii().addNote(f.str().c_str());
1291
0
    }
1292
0
    break;
1293
0
  }
1294
0
  case 2: {
1295
0
    int val=int(input->readULong(4));
1296
0
    if (val)
1297
0
      f << "f0=" << val << ",";
1298
0
    long len=long(input->readULong(4));
1299
0
    f << "len=" << len << ",";
1300
0
    if ((len && len<10) || begPos+12+len<begPos+12 || !input->checkPosition(begPos+12+len)) {
1301
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: can not read the picture length\n"));
1302
0
      f << "###";
1303
0
      break;
1304
0
    }
1305
0
    shape.m_pictEntry.setBegin(begPos+12);
1306
0
    shape.m_pictEntry.setLength(len);
1307
0
    val=int(input->readULong(4));
1308
0
    if (val)
1309
0
      f << "f1=" << val << ",";
1310
0
    break;
1311
0
  }
1312
0
  default:
1313
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: find unknown type of shapes\n"));
1314
0
    f << "###";
1315
0
    break;
1316
0
  }
1317
0
  if (m_state->m_idToShapeMap.count(pageId)) {
1318
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: find a duplicated shape %d:%d\n", pageId.first, pageId.second));
1319
0
    f << "###";
1320
0
  }
1321
0
  else
1322
0
    m_state->m_idToShapeMap[pageId]=shape;
1323
0
  if (!asciiUpdated) {
1324
0
    ascii().addPos(begPos);
1325
0
    ascii().addNote(f.str().c_str());
1326
0
  }
1327
0
  return true;
1328
0
}
1329
1330
bool SpringBoardParser::parseFrames(int page, long begPos)
1331
0
{
1332
0
  MWAWInputStreamPtr input = getInput();
1333
0
  if (!input)
1334
0
    return false;
1335
0
  if (begPos<0x80 || !input->checkPosition(begPos+14)) {
1336
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: the begin position seems bad\n"));
1337
0
    return false;
1338
0
  }
1339
0
  libmwaw::DebugStream f;
1340
0
  f << "Entries(Frame):page=" << page << ",";
1341
0
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
1342
0
  int val;
1343
0
  for (int i=0; i<2; ++i) { // f0=0|-4|10
1344
0
    val=int(input->readLong(2));
1345
0
    if (val!=i)
1346
0
      f << "f" << i << "=" << val << ",";
1347
0
  }
1348
0
  int dim[4];
1349
0
  for (auto &d : dim) d=int(input->readLong(2));
1350
0
  MWAWBox2i dimension=MWAWBox2i(MWAWVec2i(dim[1], dim[0]),MWAWVec2i(dim[3], dim[2]));
1351
0
  f << "box=" << dimension << ",";
1352
0
  if (m_state->m_pageIdToDimensionMap.count(page)) {
1353
0
    f << "###dupl,";
1354
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: the page %d dimension is already set\n", page));
1355
0
  }
1356
0
  else
1357
0
    m_state->m_pageIdToDimensionMap[page]=dimension;
1358
0
  int N=int(input->readULong(2));
1359
0
  f << "N=" << N << ",";
1360
0
  if (!input->checkPosition(begPos+14+N*28)) {
1361
0
    MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: can not read N\n"));
1362
0
    f << "###";
1363
0
    ascii().addPos(begPos);
1364
0
    ascii().addNote(f.str().c_str());
1365
0
    return false;
1366
0
  }
1367
0
  ascii().addPos(begPos);
1368
0
  ascii().addNote(f.str().c_str());
1369
1370
0
  SpringBoardParserInternal::Frame dummy;
1371
0
  for (int i=0; i<N; ++i) {
1372
0
    long pos=input->tell();
1373
0
    f.str("");
1374
0
    int id=int(input->readLong(1));
1375
0
    f << "Frame-" << page << "x" << id << ":";
1376
0
    auto fIt=m_state->m_idToFrameMap.find(std::make_pair(page,id));
1377
0
    auto &frame=fIt!=m_state->m_idToFrameMap.end() ? fIt->second : dummy;
1378
0
    if (fIt==m_state->m_idToFrameMap.end() && (page!=0 || id!=0)) { // 0x0 seems to be the default layout
1379
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: can not find frame %dx%d\n", page, id));
1380
0
    }
1381
0
    val=int(input->readLong(1));
1382
0
    switch (val) {
1383
0
    case 0:
1384
0
      f << "layout,";
1385
0
      break;
1386
0
    case 1:
1387
0
      f << "text,";
1388
0
      break;
1389
0
    case 2:
1390
0
      f << "graphics,";
1391
0
      break;
1392
0
    default:
1393
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: find unknown frame type\n"));
1394
0
      f << "###type=" << val << ",";
1395
0
      break;
1396
0
    }
1397
0
    for (int st=0; st<2; ++st) {
1398
0
      for (auto &d : dim) d=int(input->readLong(2));
1399
0
      frame.m_boxes[st]=MWAWBox2i(MWAWVec2i(dim[1], dim[0]),MWAWVec2i(dim[3], dim[2]));
1400
0
      if (st==0)
1401
0
        f << "box=" << frame.m_boxes[0] << ",";
1402
0
      else if (frame.m_boxes[0]!=frame.m_boxes[1])
1403
0
        f << "box[internal]=" << frame.m_boxes[1] << ",";
1404
0
    }
1405
0
    for (int j=0; j<4; ++j) {
1406
0
      val=int(input->readLong(2));
1407
0
      if (val==0) continue;
1408
0
      f << "f" << j << "=" << val << ",";
1409
0
    }
1410
0
    frame.m_numColumns=int(input->readULong(2));
1411
0
    if (frame.m_numColumns!=1)
1412
0
      f << "N[col]=" << frame.m_numColumns << ",";
1413
0
    if (!input->checkPosition(pos+28+frame.m_numColumns*10)) {
1414
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseFrames: find unexpected subzone N\n"));
1415
0
      f << "###";
1416
0
      ascii().addPos(pos);
1417
0
      ascii().addNote(f.str().c_str());
1418
0
      return false;
1419
0
    }
1420
0
    ascii().addPos(pos);
1421
0
    ascii().addNote(f.str().c_str());
1422
1423
0
    for (int col=0; col<frame.m_numColumns; ++col) {
1424
0
      pos=input->tell();
1425
0
      f.str("");
1426
0
      f << "Frame-" << page << "x" << id << "[" << col << "]:";
1427
0
      val=int(input->readULong(1));
1428
0
      if (val)
1429
0
        f << "f0=" << val << ",";
1430
0
      val=int(input->readULong(1));
1431
0
      if (val!=1)
1432
0
        f << "col=" << val << ",";
1433
0
      for (auto &d : dim) d=int(input->readLong(2));
1434
      // checkme can we have some non increasing columns ?
1435
0
      frame.m_columnBoxes.push_back(MWAWBox2i(MWAWVec2i(dim[1], dim[0]),MWAWVec2i(dim[3], dim[2])));
1436
0
      f << "box=" << frame.m_columnBoxes.back() << ",";
1437
0
      ascii().addPos(pos);
1438
0
      ascii().addNote(f.str().c_str());
1439
0
    }
1440
0
  }
1441
0
  return true;
1442
0
}
1443
1444
////////////////////////////////////////////////////////////
1445
// send shapes
1446
////////////////////////////////////////////////////////////
1447
bool SpringBoardParser::sendFrame(std::pair<int, int> const &pageId)
1448
0
{
1449
0
  auto input=getInput();
1450
0
  auto listener=getGraphicListener();
1451
0
  if (!input || !listener) {
1452
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendFrame: can not find the listener\n"));
1453
0
    return false;
1454
0
  }
1455
0
  auto fIt=m_state->m_idToFrameMap.find(pageId);
1456
0
  if (fIt==m_state->m_idToFrameMap.end()) {
1457
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendFrame: can not find any frame for %d:%d\n", pageId.first, pageId.second));
1458
0
    return false;
1459
0
  }
1460
0
  auto lIt=m_state->m_idToLinkMap.find(pageId);
1461
0
  int whichBox = (lIt!=m_state->m_idToLinkMap.end() && lIt->second.hasText()) ? 1 : 0;
1462
0
  SpringBoardParserInternal::Frame const &frame=fIt->second;
1463
0
  MWAWPosition pos(MWAWVec2f(frame.m_boxes[whichBox][0]), MWAWVec2f(frame.m_boxes[whichBox].size()), librevenge::RVNG_POINT);
1464
0
  pos.setRelativePosition(MWAWPosition::Page);
1465
1466
0
  auto sIt=m_state->m_idToShapeMap.find(pageId);
1467
0
  if (sIt==m_state->m_idToShapeMap.end()) {
1468
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendFrame: can not find any shape for %d:%d\n", pageId.first, pageId.second));
1469
0
    auto gShape=MWAWGraphicShape::rectangle(MWAWBox2f(frame.m_boxes[whichBox]));
1470
0
    listener->insertShape(pos, gShape, frame.m_style);
1471
0
    return false;
1472
0
  }
1473
1474
0
  if (whichBox==1) {
1475
0
    auto const &link=lIt->second;
1476
0
    for (int p=0; p<2; ++p) {
1477
0
      if (!link.m_texts[p].valid())
1478
0
        continue;
1479
0
      int limits[]= {p==0 ? frame.m_boxes[0][0][1] : frame.m_boxes[1][1][1],
1480
0
                     p==0 ? frame.m_boxes[1][0][1] : frame.m_boxes[0][1][1]
1481
0
                    };
1482
0
      MWAWPosition posL(MWAWVec2f((float)frame.m_boxes[0][0][0], (float)limits[0]),
1483
0
                        MWAWVec2f((float)frame.m_boxes[0].size()[0],float(limits[1]-limits[0])), librevenge::RVNG_POINT);
1484
0
      posL.setRelativePosition(MWAWPosition::Page);
1485
0
      auto subdoc=std::make_shared<SpringBoardParserInternal::SubDocument>(*this, getInput(), pageId, p==0);
1486
0
      listener->insertTextBox(posL, subdoc, MWAWGraphicStyle::emptyStyle());
1487
0
    }
1488
0
  }
1489
0
  SpringBoardParserInternal::Shape const &shape=sIt->second;
1490
0
  switch (shape.m_type) {
1491
0
  case 0: { // layout
1492
0
    auto subdoc=std::make_shared<SpringBoardParserInternal::SubDocument>(*this, getInput(), pageId);
1493
0
    listener->insertTextBox(pos, subdoc, frame.m_style);
1494
0
    return true;
1495
0
  }
1496
0
  case 1: { // text zone
1497
0
    size_t numCols=frame.m_columnBoxes.size();
1498
0
    std::vector<int> paraLimits;
1499
0
    paraLimits.push_back(0);
1500
0
    for (size_t p=0; p<shape.m_paragraphs.size(); ++p) {
1501
0
      if (shape.m_paragraphs[p].m_newColumn)
1502
0
        paraLimits.push_back(int(p));
1503
0
    }
1504
0
    if (paraLimits.size()>numCols)
1505
0
      paraLimits.resize(numCols);
1506
1507
0
    for (size_t c=0; c<std::max<size_t>(1,numCols); ++c) {
1508
0
      MWAWPosition posi;
1509
0
      if (numCols) {
1510
0
        posi.setUnit(librevenge::RVNG_POINT);
1511
0
        posi.setOrigin(MWAWVec2f(frame.m_boxes[whichBox][0]+frame.m_columnBoxes[c][0]));
1512
0
        posi.setSize(MWAWVec2f(frame.m_columnBoxes[c].size()));
1513
0
        posi.setRelativePosition(MWAWPosition::Page);
1514
0
      }
1515
0
      int limits[]= {0, -1}; // ie. all
1516
0
      if (c+1<paraLimits.size()) {
1517
0
        limits[0]=paraLimits[c];
1518
0
        limits[1]=paraLimits[c+1]-1;
1519
0
      }
1520
0
      else if (c<paraLimits.size()) {
1521
0
        limits[0]=paraLimits[c];
1522
0
        limits[1]=-1; // ie. to last paragraph
1523
0
      }
1524
0
      else if (c)
1525
0
        limits[0]=int(paraLimits.size()); // ie. nothing to retrieve
1526
0
      auto subdoc=std::make_shared<SpringBoardParserInternal::SubDocument>(*this, getInput(), pageId, std::make_pair(limits[0], limits[1]));
1527
0
      listener->insertTextBox(numCols==0 ? pos : posi, subdoc, frame.m_style);
1528
0
    }
1529
0
    return true;
1530
0
  }
1531
0
  case 2: {
1532
0
    if (!shape.m_pictEntry.valid())
1533
0
      break;
1534
0
    input->seek(shape.m_pictEntry.begin(), librevenge::RVNG_SEEK_SET);
1535
0
    std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, int(shape.m_pictEntry.length())));
1536
0
    MWAWEmbeddedObject image;
1537
0
    if (pict && pict->getBinary(image) && !image.m_dataList.empty()) {
1538
#ifdef DEBUG_WITH_FILES
1539
      static int volatile pictName = 0;
1540
      libmwaw::DebugStream f2;
1541
      f2 << "PICT-" << ++pictName << ".pct";
1542
      libmwaw::Debug::dumpFile(image.m_dataList[0], f2.str().c_str());
1543
      ascii().skipZone(shape.m_pictEntry.begin(), shape.m_pictEntry.end()-1);
1544
#endif
1545
0
      listener->insertPicture(pos, image, frame.m_style);
1546
0
      return true;
1547
0
    }
1548
0
    else {
1549
0
      MWAW_DEBUG_MSG(("SpringBoardParser::parseShape: sorry, can not retrieve a picture\n"));
1550
0
    }
1551
0
    break;
1552
0
  }
1553
0
  default:
1554
0
    break;
1555
0
  }
1556
0
  auto gShape=MWAWGraphicShape::rectangle(MWAWBox2f(frame.m_boxes[0]));
1557
0
  listener->insertShape(pos, gShape, frame.m_style);
1558
0
  return true;
1559
0
}
1560
1561
bool SpringBoardParser::sendLinkShape(std::pair<int, int> const &linkId, bool isTop)
1562
0
{
1563
0
  auto input=getInput();
1564
0
  auto listener=getGraphicListener();
1565
0
  if (!input || !listener) {
1566
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendTextLink: can not find the listener\n"));
1567
0
    return false;
1568
0
  }
1569
0
  auto lIt=m_state->m_idToLinkMap.find(linkId);
1570
0
  if (lIt==m_state->m_idToLinkMap.end()) {
1571
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendTextLink: can not find any link for %d:%d\n", linkId.first, linkId.second));
1572
0
    return false;
1573
0
  }
1574
0
  SpringBoardParserInternal::Link const &link=lIt->second;
1575
0
  listener->setFont(link.m_font);
1576
1577
0
  MWAWEntry const &entry=link.m_texts[isTop ? 0 : 1];
1578
0
  if (!entry.valid()) {
1579
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendTextLink: can not find text for link for %d:%d\n", linkId.first, linkId.second));
1580
0
    return false;
1581
0
  }
1582
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1583
0
  for (long i=0; i<entry.length(); ++i) {
1584
0
    unsigned char c=(unsigned char)(input->readLong(1));
1585
0
    if (c == 0x9)
1586
0
      listener->insertTab();
1587
0
    else if (c == 0xd)
1588
0
      listener->insertEOL();
1589
0
    else if (c<0x1f) {
1590
0
      MWAW_DEBUG_MSG(("SpringBoardParser::sendTextLink: find bad character %d\n", int(c)));
1591
0
    }
1592
0
    else
1593
0
      listener->insertCharacter(c);
1594
0
  }
1595
0
  return true;
1596
0
}
1597
1598
bool SpringBoardParser::sendTextShape(std::pair<int, int> const &pageId, int minParagraph, int maxParagraph)
1599
0
{
1600
0
  auto input=getInput();
1601
0
  auto listener=getGraphicListener();
1602
0
  if (!input || !listener) {
1603
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: can not find the listener\n"));
1604
0
    return false;
1605
0
  }
1606
0
  auto sIt=m_state->m_idToShapeMap.find(pageId);
1607
0
  if (sIt==m_state->m_idToShapeMap.end()) {
1608
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: can not find any shape for %d:%d\n", pageId.first, pageId.second));
1609
0
    return false;
1610
0
  }
1611
0
  SpringBoardParserInternal::Shape const &shape=sIt->second;
1612
0
  if (shape.m_paragraphs.empty() || minParagraph>=int(shape.m_paragraphs.size()))
1613
0
    return true;
1614
0
  if (minParagraph<0) minParagraph=0;
1615
0
  if (maxParagraph<minParagraph || maxParagraph>=int(shape.m_paragraphs.size()))
1616
0
    maxParagraph=int(shape.m_paragraphs.size()-1);
1617
0
  int textZoneId=-1;
1618
0
  for (int p=0; p<minParagraph; ++p) {
1619
0
    auto const &para = shape.m_paragraphs[size_t(p)];
1620
0
    if (para.m_textZoneId!=-1)
1621
0
      textZoneId=para.m_textZoneId;
1622
0
  }
1623
0
  for (int p=minParagraph; p<=maxParagraph; ++p) {
1624
0
    auto const &para = shape.m_paragraphs[size_t(p)];
1625
0
    auto const &pIt=m_state->m_idToParagraphMap.find(para.m_paragraphStyle);
1626
0
    if (pIt==m_state->m_idToParagraphMap.end()) {
1627
0
      MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: unknown paragraph=%d\n", para.m_paragraphStyle));
1628
0
    }
1629
0
    else
1630
0
      listener->setParagraph(pIt->second);
1631
0
    if (para.m_textZoneId!=-1)
1632
0
      textZoneId=para.m_textZoneId;
1633
0
    if (textZoneId==-1)
1634
0
      continue;
1635
0
    auto const &tIt=m_state->m_idToTextEntriesMap.find(textZoneId);
1636
0
    if (tIt==m_state->m_idToTextEntriesMap.end() || !tIt->second.valid()) {
1637
0
      MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: unknown text id=%d\n", textZoneId));
1638
0
      continue;
1639
0
    }
1640
1641
    // now retrieve the font styles
1642
0
    input->seek(para.m_charEntry.begin(), librevenge::RVNG_SEEK_SET);
1643
0
    std::map<int, MWAWFont> posToCharMap;
1644
0
    int cPos=0;
1645
0
    libmwaw::DebugStream f;
1646
0
    for (int i=0; i<para.m_numCharStyles; ++i) {
1647
0
      long pos=input->tell();
1648
0
      f.str("");
1649
0
      f << "Shape-char[" << i << "]:";
1650
0
      f << "cPos=" << cPos << ",";
1651
0
      int newPos=cPos+int(input->readLong(2));
1652
0
      MWAWFont font;
1653
0
      readFont(font,1);
1654
0
      int val=int(input->readLong(2));
1655
0
      if (val) {
1656
0
        MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: unknown styles=%d\n", val));
1657
0
        f << "#f0=" << val << ",";
1658
0
      }
1659
0
      val=int(input->readLong(1));
1660
0
      if (val>=0 && val<63)
1661
0
        font.setDeltaLetterSpacing(float(val));
1662
0
      else {
1663
0
        MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: unexpected char spacing=%d\n", val));
1664
0
        f << "##char[spacing]=" << val << ",";
1665
0
      }
1666
0
      f << font.getDebugString(getFontConverter())  << ",";
1667
0
      input->seek(pos+10, librevenge::RVNG_SEEK_SET);
1668
0
      posToCharMap[cPos]=font;
1669
0
      cPos=newPos;
1670
0
      ascii().addPos(pos);
1671
0
      ascii().addNote(f.str().c_str());
1672
0
    }
1673
1674
0
    MWAWEntry const textZone=tIt->second;
1675
0
    input->seek(textZone.begin()+para.m_firstChar, librevenge::RVNG_SEEK_SET);
1676
0
    for (int l=0; l<para.m_numChars; ++l) {
1677
0
      auto cIt=posToCharMap.find(l);
1678
0
      if (cIt!=posToCharMap.end())
1679
0
        listener->setFont(cIt->second);
1680
0
      unsigned char c=(unsigned char)(input->readLong(1));
1681
0
      if (c == 0x9)
1682
0
        listener->insertTab();
1683
0
      else if (c == 0xd)
1684
0
        listener->insertEOL();
1685
0
      else if (c<0x1f) {
1686
0
        MWAW_DEBUG_MSG(("SpringBoardParser::sendTextShape: find bad character %d\n", int(c)));
1687
0
      }
1688
0
      else
1689
0
        listener->insertCharacter(c);
1690
0
    }
1691
0
  }
1692
0
  return true;
1693
0
}
1694
1695
bool SpringBoardParser::sendHeaderFooter(int hfId)
1696
0
{
1697
0
  auto input=getInput();
1698
0
  auto listener=getGraphicListener();
1699
0
  if (!input || !listener) {
1700
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendHeaderFooter: can not find the listener\n"));
1701
0
    return false;
1702
0
  }
1703
0
  auto hfIt=m_state->m_pageIdToHeaderFooterMap.find(hfId);
1704
0
  if (hfIt==m_state->m_pageIdToHeaderFooterMap.end()) {
1705
0
    MWAW_DEBUG_MSG(("SpringBoardParser::sendHeaderFooter: can not find the header footer for id=%d\n", hfId));
1706
0
    return false;
1707
0
  }
1708
0
  auto const &hf=hfIt->second;
1709
0
  listener->setFont(hf.m_font);
1710
0
  MWAWParagraph para; // FIXME: this does nothing, find another way to send center and right header/footer
1711
0
  if (hf.m_type==1 || hf.m_type==4)
1712
0
    para.m_justify = MWAWParagraph::JustificationCenter;
1713
0
  else if (hf.m_type==2 || hf.m_type==5)
1714
0
    para.m_justify = MWAWParagraph::JustificationRight;
1715
0
  listener->setParagraph(para);
1716
0
  if (hf.m_zones[0].valid()) { // prefix
1717
0
    input->seek(hf.m_zones[0].begin(), librevenge::RVNG_SEEK_SET);
1718
0
    for (long l=0; l<hf.m_zones[0].length(); ++l) {
1719
0
      unsigned char c=(unsigned char)(input->readLong(1));
1720
0
      if (c == 0x9)
1721
0
        listener->insertTab();
1722
0
      else if (c == 0xd)
1723
0
        listener->insertEOL();
1724
0
      else if (c<0x1f) {
1725
0
        MWAW_DEBUG_MSG(("SpringBoardParser::sendHeaderFooter: find bad character %d\n", int(c)));
1726
0
      }
1727
0
      else
1728
0
        listener->insertCharacter(c);
1729
0
    }
1730
0
  }
1731
0
  MWAWField pageNumber(MWAWField::PageNumber);
1732
0
  switch (hf.m_type) {
1733
0
  case 1:
1734
0
    pageNumber.m_numberingType=libmwaw::LOWERCASE_ROMAN;
1735
0
    break;
1736
0
  case 2:
1737
0
    pageNumber.m_numberingType=libmwaw::UPPERCASE_ROMAN;
1738
0
    break;
1739
0
  case 3:
1740
0
    pageNumber.m_numberingType=libmwaw::LOWERCASE;
1741
0
    break;
1742
0
  case 4:
1743
0
    pageNumber.m_numberingType=libmwaw::UPPERCASE;
1744
0
    break;
1745
0
  default: // also 5-7 full number minuscule, majuscule, title
1746
0
    break;
1747
0
  }
1748
0
  if (pageNumber.m_type!=8)
1749
0
    listener->insertField(pageNumber);
1750
0
  if (hf.m_zones[1].valid()) { // suffix
1751
0
    input->seek(hf.m_zones[1].begin(), librevenge::RVNG_SEEK_SET);
1752
0
    for (long l=0; l<hf.m_zones[1].length(); ++l) {
1753
0
      unsigned char c=(unsigned char)(input->readLong(1));
1754
0
      if (c == 0x9)
1755
0
        listener->insertTab();
1756
0
      else if (c == 0xd)
1757
0
        listener->insertEOL();
1758
0
      else if (c<0x1f) {
1759
0
        MWAW_DEBUG_MSG(("SpringBoardParser::sendHeaderFooter: find bad character %d\n", int(c)));
1760
0
      }
1761
0
      else
1762
0
        listener->insertCharacter(c);
1763
0
    }
1764
0
  }
1765
0
  return true;
1766
0
}
1767
1768
1769
////////////////////////////////////////////////////////////
1770
// read shapes
1771
////////////////////////////////////////////////////////////
1772
1773
////////////////////////////////////////////////////////////
1774
// read the header
1775
////////////////////////////////////////////////////////////
1776
bool SpringBoardParser::checkHeader(MWAWHeader *header, bool strict)
1777
152
{
1778
152
  *m_state = SpringBoardParserInternal::State();
1779
152
  MWAWInputStreamPtr input = getInput();
1780
152
  if (!input || !input->hasDataFork() || !input->checkPosition(128))
1781
19
    return false;
1782
1783
133
  libmwaw::DebugStream f;
1784
133
  f << "FileHeader:";
1785
133
  input->seek(0, librevenge::RVNG_SEEK_SET);
1786
133
  if (input->readULong(2)!=0xcd90)
1787
0
    return false;
1788
399
  for (int i=0; i<2; ++i) {
1789
266
    int val=int(input->readLong(1));
1790
266
    if (val==i) continue;
1791
159
    if (i==0)
1792
46
      f << "rev" << val << ","; // look like a counter (modulo 10)
1793
113
    else
1794
113
      f << "f" << i << "=" << val << ",";
1795
159
  }
1796
133
  if ((input->readULong(2)&0xff00)!=0) return false;
1797
1798
133
  if (strict) {
1799
55
    input->seek(20, librevenge::RVNG_SEEK_SET);
1800
204
    for (int i=0; i<10; ++i) {
1801
202
      long beg=long(input->readULong(4));
1802
202
      long len=long(input->readULong(2));
1803
202
      if (!len)
1804
118
        continue;
1805
84
      if (beg<=0 || beg+len<=0 || !input->checkPosition(beg+len)) {
1806
53
        MWAW_DEBUG_MSG(("SpringBoardParser::checkHeader: find unexpected position: %d\n", int(i)));
1807
53
        f << "###";
1808
53
        ascii().addPos(0);
1809
53
        ascii().addNote(f.str().c_str());
1810
1811
53
        return false;
1812
53
      }
1813
84
    }
1814
55
  }
1815
1816
80
  ascii().addPos(0);
1817
80
  ascii().addNote(f.str().c_str());
1818
80
  if (header)
1819
52
    header->reset(MWAWDocument::MWAW_T_SPRINGBOARD_PUBLISHER, 2, MWAWDocument::MWAW_K_DRAW);
1820
80
  input->seek(4, librevenge::RVNG_SEEK_SET);
1821
1822
80
  return true;
1823
133
}
1824
1825
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: