Coverage Report

Created: 2026-03-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libstaroffice/src/lib/StarObjectText.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
/* libstaroffice
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 <memory>
39
#include <sstream>
40
41
#include <librevenge/librevenge.h>
42
43
#include "STOFFList.hxx"
44
#include "STOFFOLEParser.hxx"
45
#include "STOFFPageSpan.hxx"
46
#include "STOFFParagraph.hxx"
47
#include "STOFFSection.hxx"
48
#include "STOFFSubDocument.hxx"
49
#include "STOFFTextListener.hxx"
50
51
#include "SWFieldManager.hxx"
52
53
#include "StarAttribute.hxx"
54
#include "StarFormatManager.hxx"
55
#include "StarObject.hxx"
56
#include "StarFileManager.hxx"
57
#include "StarGraphicStruct.hxx"
58
#include "StarItemPool.hxx"
59
#include "StarLayout.hxx"
60
#include "StarObjectChart.hxx"
61
#include "StarObjectMath.hxx"
62
#include "StarObjectModel.hxx"
63
#include "StarObjectNumericRuler.hxx"
64
#include "StarObjectPageStyle.hxx"
65
#include "StarObjectSpreadsheet.hxx"
66
#include "StarState.hxx"
67
#include "StarTable.hxx"
68
#include "StarWriterStruct.hxx"
69
#include "StarZone.hxx"
70
71
#include "StarObjectText.hxx"
72
73
/** Internal: the structures of a StarObjectText */
74
namespace StarObjectTextInternal
75
{
76
////////////////////////////////////////
77
//! Internal: the subdocument of a StarObjectSpreadsheet
78
class SubDocument final : public STOFFSubDocument
79
{
80
public:
81
  explicit SubDocument(StarObjectTextInternal::Content const &content, StarState &state) :
82
113
    STOFFSubDocument(nullptr, STOFFInputStreamPtr(), STOFFEntry()), m_content(content), m_state(state) {}
83
84
  //! destructor
85
0
  ~SubDocument() final {}
86
87
  //! operator!=
88
  bool operator!=(STOFFSubDocument const &doc) const final
89
0
  {
90
0
    if (STOFFSubDocument::operator!=(doc)) return true;
91
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
92
0
    if (!sDoc) return true;
93
0
    if (&m_content != &sDoc->m_content) return true;
94
0
    return false;
95
0
  }
96
97
  //! the parser function
98
  void parse(STOFFListenerPtr &listener, libstoff::SubDocumentType type) final;
99
100
protected:
101
  //! the content
102
  StarObjectTextInternal::Content const &m_content;
103
  //! the state
104
  StarState &m_state;
105
private:
106
  SubDocument(SubDocument const &);
107
  SubDocument &operator=(SubDocument const &);
108
};
109
110
void SubDocument::parse(STOFFListenerPtr &listener, libstoff::SubDocumentType /*type*/)
111
113
{
112
113
  if (!listener.get()) {
113
0
    STOFF_DEBUG_MSG(("StarObjectSpreadsheetInternal::SubDocument::parse: no listener\n"));
114
0
    return;
115
0
  }
116
113
  m_content.send(listener, m_state);
117
113
}
118
119
////////////////////////////////////////
120
// Zone, Content function
121
Zone::~Zone()
122
177k
{
123
177k
}
124
125
Content::~Content()
126
36.8k
{
127
36.8k
}
128
129
void Content::inventoryPages(StarState &state) const
130
5.42k
{
131
5.42k
  if (!state.m_global->m_pool) {
132
3.39k
    STOFF_DEBUG_MSG(("StarObjectTextInternal::Content::inventoryPages: can not find the pool\n"));
133
3.39k
    return;
134
3.39k
  }
135
27.1k
  for (auto &z : m_zoneList) {
136
27.1k
    if (z)
137
27.1k
      z->inventoryPage(state);
138
27.1k
    if (state.m_global->m_pageNameList.empty())
139
1.88k
      state.m_global->m_pageNameList.push_back("");
140
27.1k
  }
141
2.02k
}
142
143
////////////////////////////////////////
144
//! Internal: a formatZone of StarObjectTextInteral
145
struct FormatZone final : public Zone {
146
  //! constructor
147
  explicit FormatZone(std::shared_ptr<StarFormatManagerInternal::FormatDef> &format)
148
1.03k
    : Zone()
149
1.03k
    , m_format(format)
150
1.03k
  {
151
1.03k
  }
152
  //! try to send the data to a listener
153
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
154
  //! the format
155
  std::shared_ptr<StarFormatManagerInternal::FormatDef> m_format;
156
};
157
158
bool FormatZone::send(STOFFListenerPtr &listener, StarState &state) const
159
236
{
160
236
  if (!listener) {
161
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::FormatZone::send: call without listener\n"));
162
0
    return false;
163
0
  }
164
236
  if (!m_format) {
165
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::FormatZone::send: can not find the format\n"));
166
0
    return false;
167
0
  }
168
236
  StarState cState(*state.m_global);
169
236
  return m_format->send(listener, cState);
170
236
}
171
172
////////////////////////////////////////
173
//! Internal: a graphZone of StarObjectTextInteral
174
struct GraphZone final : public Zone {
175
  //! constructor
176
  explicit GraphZone(std::shared_ptr<STOFFOLEParser> &oleParser)
177
3.15k
    : Zone()
178
3.15k
    , m_oleParser(oleParser)
179
3.15k
    , m_attributeList()
180
3.15k
    , m_contour()
181
3.15k
  {
182
3.15k
  }
183
  //! try to send the data to a listener
184
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
185
  //! the ole parser
186
  std::shared_ptr<STOFFOLEParser> m_oleParser;
187
  //! the graph name, the fltName, the replace text
188
  librevenge::RVNGString m_names[3];
189
  //! the attributes list
190
  std::vector<StarWriterStruct::Attribute> m_attributeList;
191
  //! the contour(useme)
192
  StarGraphicStruct::StarPolygon m_contour;
193
};
194
195
bool GraphZone::send(STOFFListenerPtr &listener, StarState &state) const
196
1.82k
{
197
1.82k
  if (!listener) {
198
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::GraphZone::send: call without listener\n"));
199
0
    return false;
200
0
  }
201
1.82k
  if (m_names[0].empty()) {
202
294
    STOFF_DEBUG_MSG(("StarObjectTextInternal::GraphZone::send: can not find the graph name\n"));
203
294
    return false;
204
294
  }
205
1.53k
  STOFFEmbeddedObject localPicture;
206
1.53k
  if (!m_oleParser || !StarFileManager::readEmbeddedPicture(m_oleParser, m_names[0].cstr(), localPicture) || localPicture.isEmpty()) {
207
1.26k
    STOFF_DEBUG_MSG(("StarObjectTextInternal: sorry, can not find object %s\n", m_names[0].cstr()));
208
1.26k
    return false;
209
1.26k
  }
210
268
  STOFFGraphicStyle style=state.m_graphic;
211
268
  state.m_frame.addTo(style.m_propertyList);
212
268
  listener->insertPicture(state.m_frame, localPicture, style);
213
268
  return true;
214
1.53k
}
215
216
////////////////////////////////////////
217
//! Internal: a OLEZone of StarObjectTextInteral
218
struct OLEZone final : public Zone {
219
  //! constructor
220
  OLEZone()
221
35.9k
    : Zone()
222
35.9k
    , m_name("")
223
35.9k
    , m_replaceText("")
224
35.9k
    , m_oleParser()
225
35.9k
  {
226
35.9k
  }
227
  //! try to send the data to a listener
228
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
229
  //! the OLE name
230
  librevenge::RVNGString m_name;
231
  //! the replacement text
232
  librevenge::RVNGString m_replaceText;
233
  //! the ole parser
234
  std::shared_ptr<STOFFOLEParser> m_oleParser;
235
};
236
237
bool OLEZone::send(STOFFListenerPtr &listener, StarState &state) const
238
6.43k
{
239
6.43k
  if (!listener) {
240
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: call without listener\n"));
241
0
    return false;
242
0
  }
243
6.43k
  if (m_name.empty()) {
244
72
    STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: call without object name\n"));
245
72
    return false;
246
72
  }
247
6.36k
  if (!m_oleParser) {
248
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: call without ole parser\n"));
249
0
    return false;
250
0
  }
251
6.36k
  STOFFEmbeddedObject localPicture;
252
6.36k
  std::shared_ptr<StarObject> localObj;
253
6.36k
  auto dir=m_oleParser->getDirectory(m_name.cstr());
254
6.36k
  STOFFGraphicStyle style=state.m_graphic;
255
6.36k
  state.m_frame.addTo(style.m_propertyList);
256
6.36k
  if (!dir || !StarFileManager::readOLEDirectory(m_oleParser, dir, localPicture, localObj) || localPicture.isEmpty()) {
257
5.75k
    if (!localObj) {
258
1.26k
      STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: sorry, can not find object %s\n", m_name.cstr()));
259
1.26k
      return false;
260
1.26k
    }
261
4.49k
    auto chart=std::dynamic_pointer_cast<StarObjectChart>(localObj);
262
4.49k
    if (chart && chart->send(listener, state.m_frame, style))
263
0
      return true;
264
4.49k
    auto math=std::dynamic_pointer_cast<StarObjectMath>(localObj);
265
4.49k
    if (math && math->send(listener, state.m_frame, style))
266
556
      return true;
267
3.93k
    if (std::dynamic_pointer_cast<StarObjectText>(localObj)) {
268
3.83k
      STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: sorry, unsure how to send a text object %s\n", m_name.cstr()));
269
3.83k
    }
270
102
    else {
271
102
      STOFF_DEBUG_MSG(("StarObjectTextInternal::OLEZone::send: sorry, find unexpected object for %s\n", m_name.cstr()));
272
102
    }
273
3.93k
    return false;
274
4.49k
  }
275
610
  listener->insertPicture(state.m_frame, localPicture, style);
276
277
610
  return true;
278
6.36k
}
279
280
////////////////////////////////////////
281
//! Internal: a sectionZone of StarObjectTextInteral
282
struct SectionZone final : public Zone {
283
  //! constructor
284
  SectionZone()
285
20.9k
    : Zone()
286
20.9k
    , m_name("")
287
20.9k
    , m_condition("")
288
20.9k
    , m_linkName("")
289
20.9k
    , m_type(0)
290
20.9k
    , m_flags(0)
291
20.9k
    , m_format()
292
20.9k
    , m_content()
293
20.9k
  {
294
20.9k
  }
295
  //! try to send the data to a listener
296
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
297
  //! the section name
298
  librevenge::RVNGString m_name;
299
  //! the section condition
300
  librevenge::RVNGString m_condition;
301
  //! the section link name
302
  librevenge::RVNGString m_linkName;
303
  //! the section type
304
  int m_type;
305
  //! the section flag
306
  int m_flags;
307
  //! the format
308
  std::shared_ptr<StarFormatManagerInternal::FormatDef> m_format;
309
  //! the content
310
  std::shared_ptr<Content> m_content;
311
};
312
313
bool SectionZone::send(STOFFListenerPtr &listener, StarState &state) const
314
3.34k
{
315
3.34k
  if (!listener) {
316
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::SectionZone::send: call without listener\n"));
317
0
    return false;
318
0
  }
319
  // checkme: do we need to create a new section here
320
3.34k
  if (m_content)
321
174
    m_content->send(listener, state);
322
3.16k
  else {
323
3.16k
    STOFF_DEBUG_MSG(("StarObjectTextInternal::SectionZone::send: call without content\n"));
324
3.16k
  }
325
3.34k
  return true;
326
3.34k
}
327
328
////////////////////////////////////////
329
//! Internal: a textZone of StarObjectTextInteral
330
struct TextZone final : public Zone {
331
  //! constructor
332
  TextZone()
333
110k
    : Zone()
334
110k
    , m_text()
335
110k
    , m_textSourcePosition()
336
110k
    , m_styleName("")
337
110k
    , m_level(-1)
338
110k
    , m_charAttributeList()
339
110k
    , m_formatList()
340
110k
    , m_list()
341
110k
    , m_markList()
342
110k
  {
343
110k
  }
344
  //! try to inventory the different pages
345
  void inventoryPage(StarState &state) const final;
346
  //! try to send the data to a listener
347
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
348
  //! the text
349
  std::vector<uint32_t> m_text;
350
  //! the text initial position
351
  std::vector<size_t> m_textSourcePosition;
352
  //! the style name
353
  librevenge::RVNGString m_styleName;
354
  //! the level -1=none, 200: keep in list with no bullet
355
  int m_level;
356
  //! the character item list
357
  std::vector<StarWriterStruct::Attribute> m_charAttributeList;
358
  //! the format
359
  std::vector<std::shared_ptr<StarFormatManagerInternal::FormatDef> > m_formatList;
360
  //! the list (if defined)
361
  std::shared_ptr<STOFFList> m_list;
362
  //! the mark
363
  std::vector<StarWriterStruct::Mark> m_markList;
364
};
365
366
void TextZone::inventoryPage(StarState &state) const
367
23.2k
{
368
23.2k
  size_t numPages=state.m_global->m_pageNameList.size();
369
23.2k
  if (state.m_styleName!=m_styleName) {
370
6.62k
    state.reinitializeLineData();
371
6.62k
    state.m_styleName=m_styleName;
372
6.62k
    if (state.m_global->m_pool && !m_styleName.empty()) { // checkme
373
6.09k
      auto const *style=state.m_global->m_pool->findStyleWithFamily(m_styleName, StarItemStyle::F_Paragraph);
374
6.09k
      if (style) {
375
15.2k
        for (auto it : style->m_itemSet.m_whichToItemMap) {
376
15.2k
          if (it.second && it.second->m_attribute)
377
14.4k
            it.second->m_attribute->addTo(state);
378
15.2k
        }
379
3.09k
      }
380
2.99k
      else {
381
2.99k
        STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::inventoryPage: can not find style %s\n", m_styleName.cstr()));
382
2.99k
      }
383
6.09k
    }
384
6.62k
  }
385
23.2k
  StarState lineState(state);
386
49.6k
  for (auto const &attrib : m_charAttributeList) {
387
49.6k
    if ((attrib.m_position[1]<0 && attrib.m_position[0]>0) || attrib.m_position[0]>0)
388
7.44k
      continue;
389
42.1k
    if (!attrib.m_attribute)
390
604
      continue;
391
41.5k
    attrib.m_attribute->addTo(lineState);
392
41.5k
  }
393
23.2k
  if (lineState.m_global->m_pageNameList.size()!=state.m_global->m_pageNameList.size()) {
394
0
    state.m_global->m_pageName=lineState.m_global->m_pageName;
395
0
    state.m_global->m_pageNameList.push_back(state.m_global->m_pageName);
396
0
  }
397
23.2k
  else if (lineState.m_global->m_pageNameList.size()==numPages && lineState.m_break==4)
398
98
    state.m_global->m_pageNameList.push_back("");
399
23.2k
}
400
401
bool TextZone::send(STOFFListenerPtr &listener, StarState &state) const
402
72.8k
{
403
72.8k
  if (!listener || !listener->canWriteText()) {
404
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: call without listener\n"));
405
0
    return false;
406
0
  }
407
408
72.8k
  if (m_list) state.m_global->m_list=listener->getListManager()->addList(m_list);
409
72.8k
  size_t numPages=state.m_global->m_pageNameList.size();
410
72.8k
  if (state.m_styleName!=m_styleName) {
411
25.0k
    state.reinitializeLineData();
412
25.0k
    state.m_paragraph=STOFFParagraph();
413
25.0k
    state.m_styleName=m_styleName;
414
25.0k
    if (state.m_global->m_pool && !m_styleName.empty()) { // checkme
415
18.7k
      StarItemStyle const *style=state.m_global->m_pool->findStyleWithFamily(m_styleName, StarItemStyle::F_Paragraph);
416
18.7k
      if (style) {
417
9.06k
        if (style->m_outlineLevel>=0 && style->m_outlineLevel<20) {
418
502
          state.m_paragraph.m_outline=true;
419
502
          state.m_paragraph.m_listLevelIndex=style->m_outlineLevel+1;
420
502
        }
421
52.5k
        for (auto it : style->m_itemSet.m_whichToItemMap) {
422
52.5k
          if (it.second && it.second->m_attribute)
423
50.9k
            it.second->m_attribute->addTo(state);
424
52.5k
        }
425
#if 0
426
        std::cerr << "Para[" << m_styleName.cstr() << "]:" << style->m_itemSet.printChild() << "\n";
427
#endif
428
9.06k
      }
429
9.64k
      else {
430
9.64k
        STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: can not find style %s\n", m_styleName.cstr()));
431
9.64k
      }
432
18.7k
    }
433
25.0k
  }
434
72.8k
  STOFFFont mainFont=state.m_font;
435
72.8k
  listener->setFont(mainFont);
436
72.8k
  if (!m_markList.empty()) {
437
1.12k
    static bool first=true;
438
1.12k
    if (first) {
439
1
      STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: sorry mark are not implemented\n"));
440
1
      first=false;
441
1
    }
442
1.12k
  }
443
72.8k
  if (state.m_flyCnt || state.m_footnote || state.m_field) {
444
451
    STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: find a data in mainFont\n"));
445
451
  }
446
72.8k
  if (!state.m_link.empty()) {
447
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: find a link in mainFont\n"));
448
0
  }
449
72.8k
  if (!state.m_refMark.empty()) {
450
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: find a refMark in mainFont\n"));
451
0
  }
452
72.8k
  std::set<size_t> modPosSet;
453
72.8k
  modPosSet.insert(0);
454
119k
  for (auto const &attrib : m_charAttributeList) {
455
119k
    if (attrib.m_position[0]>0)
456
13.7k
      modPosSet.insert(size_t(attrib.m_position[0]));
457
119k
    if (attrib.m_position[1]>0)
458
5.65k
      modPosSet.insert(size_t(attrib.m_position[1]));
459
119k
  }
460
72.8k
  std::multimap<size_t, std::shared_ptr<StarFormatManagerInternal::FormatDef> > posToFormat;
461
72.8k
  for (auto const &c : m_formatList) {
462
1.82k
    if (!c) continue;
463
    // either a paragraph anchor or a "at char" anchor
464
1.82k
    StarState fState(state);
465
1.82k
    c->updateState(fState);
466
1.82k
    size_t lastIndex=m_textSourcePosition.empty() ? 0 : m_textSourcePosition.back();
467
1.82k
    size_t cPos=fState.m_frame.m_anchorIndex<0 ? 0 : fState.m_frame.m_anchorIndex>int(lastIndex) ? lastIndex :
468
104
                size_t(fState.m_frame.m_anchorIndex);
469
1.82k
    posToFormat.insert(std::multimap<size_t, std::shared_ptr<StarFormatManagerInternal::FormatDef> >::value_type(cPos, c));
470
1.82k
  }
471
72.8k
  auto posSetIt=modPosSet.begin();
472
72.8k
  int endLinkPos=-1, endRefMarkPos=-1;
473
72.8k
  librevenge::RVNGString refMarkString;
474
72.8k
  StarState lineState(state);
475
72.8k
  state.m_break=0;
476
72.8k
  bool newPage=false;
477
13.2M
  for (size_t c=0; c<= m_text.size(); ++c) {
478
13.2M
    bool fontChange=false;
479
13.2M
    size_t srcPos=c<m_textSourcePosition.size() ? m_textSourcePosition[c] : m_textSourcePosition.empty() ? 0 : 10000;
480
13.3M
    while (posSetIt!=modPosSet.end() && *posSetIt <= srcPos) {
481
89.5k
      ++posSetIt;
482
89.5k
      fontChange=true;
483
89.5k
    }
484
13.2M
    std::shared_ptr<StarAttribute> flyCnt;
485
13.2M
    std::shared_ptr<StarAttribute> footnote;
486
13.2M
    std::shared_ptr<SWFieldManagerInternal::Field> field;
487
13.2M
    librevenge::RVNGString linkString;
488
13.2M
    bool startRefMark=false;
489
13.2M
    bool softHyphen=false;
490
13.2M
    bool hardBlank=false;
491
13.2M
    if (fontChange) {
492
89.3k
      lineState.reinitializeLineData();
493
89.3k
      lineState.m_font=mainFont;
494
89.3k
      STOFFFont &font=lineState.m_font;
495
257k
      for (auto const &attrib : m_charAttributeList) {
496
257k
        if ((attrib.m_position[1]<0 && attrib.m_position[0]>=0 && attrib.m_position[0]!=int(srcPos)) ||
497
184k
            (attrib.m_position[0]>=0 && attrib.m_position[0]>int(srcPos)) ||
498
174k
            (attrib.m_position[1]>=0 && attrib.m_position[1]<=int(srcPos)))
499
96.7k
          continue;
500
160k
        if (!attrib.m_attribute)
501
3.69k
          continue;
502
156k
        attrib.m_attribute->addTo(lineState);
503
156k
        if (!footnote && lineState.m_footnote)
504
3.32k
          footnote=attrib.m_attribute;
505
156k
        if (!flyCnt && lineState.m_flyCnt)
506
2.18k
          flyCnt=attrib.m_attribute;
507
156k
        if (c==0) {
508
103k
          switch (lineState.m_break) {
509
102k
          case 0:
510
102k
            break;
511
63
          case 1:
512
63
            listener->insertBreak(STOFFListener::ColumnBreak);
513
63
            break;
514
320
          case 4:
515
320
            newPage=true;
516
320
            listener->insertBreak(STOFFListener::PageBreak);
517
320
            if (state.m_global->m_pageNameList.size()==numPages)
518
256
              state.m_global->m_pageNameList.push_back("");
519
320
            break;
520
49
          default: {
521
49
            static bool first=true;
522
49
            if (first) {
523
1
              first=false;
524
1
              STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: unexpected break\n"));
525
1
            }
526
49
            break;
527
0
          }
528
103k
          }
529
103k
          lineState.m_break=0;
530
103k
        }
531
156k
        if (lineState.m_field) {
532
581
          if (int(srcPos)==attrib.m_position[0])
533
555
            field=lineState.m_field;
534
581
          lineState.m_field.reset();
535
581
        }
536
156k
        if (!lineState.m_link.empty()) {
537
411
          if (endLinkPos<0) {
538
384
            linkString=lineState.m_link;
539
384
            endLinkPos=int(attrib.m_position[1]<0 ? attrib.m_position[0] : attrib.m_position[1]);
540
384
          }
541
411
          lineState.m_link.clear();
542
411
        }
543
156k
        if (!lineState.m_refMark.empty()) {
544
31
          if (endRefMarkPos<0) {
545
24
            refMarkString=lineState.m_refMark;
546
24
            endRefMarkPos=int(attrib.m_position[1]<0 ? attrib.m_position[0] : attrib.m_position[1]);
547
24
            startRefMark=true;
548
24
          }
549
7
          else {
550
7
            STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: multiple refmark is not implemented\n"));
551
7
          }
552
31
          lineState.m_refMark.clear();
553
31
        }
554
156k
      }
555
89.3k
      softHyphen=font.m_softHyphen;
556
89.3k
      hardBlank=font.m_hardBlank;
557
89.3k
      listener->setFont(font);
558
89.3k
      if (c==0) {
559
72.8k
        int level=m_level;
560
72.8k
        if (level==200) {
561
0
          level=state.m_global->m_listLevel;
562
0
          lineState.m_paragraph.m_bulletVisible=true; // useMe
563
0
        }
564
72.8k
        if (!lineState.m_paragraph.m_outline) {
565
72.0k
          if (level>=0 && (!state.m_global->m_list || state.m_global->m_list->numLevels()<=int(level))) {
566
2.11k
            STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: oops can not find the list\n"));
567
2.11k
            level=-1;
568
2.11k
          }
569
72.0k
          if (level>=0) {
570
5.17k
            lineState.m_paragraph.m_listLevel = state.m_global->m_list->getLevel(level);
571
5.17k
            lineState.m_paragraph.m_listId = state.m_global->m_list->getId();
572
5.17k
            lineState.m_paragraph.m_listLevelIndex = level+1;
573
5.17k
          }
574
66.8k
          else
575
66.8k
            lineState.m_paragraph.m_listLevelIndex=0;
576
72.0k
        }
577
72.8k
        listener->setParagraph(lineState.m_paragraph);
578
72.8k
      }
579
89.3k
      static bool first=true;
580
89.3k
      if (first && lineState.m_content) {
581
1
        first=false;
582
1
        STOFF_DEBUG_MSG(("StarObjectTextInternal::TextZone::send: find unexpected content zone\n"));
583
1
      }
584
89.3k
    }
585
13.2M
    if (c==0 && !newPage && numPages && numPages!=lineState.m_global->m_pageNameList.size())
586
61
      listener->insertBreak(STOFFListener::SoftPageBreak);
587
13.2M
    for (auto it=posToFormat.lower_bound(srcPos); it!=posToFormat.upper_bound(srcPos); ++it) {
588
1.81k
      StarState cState(*lineState.m_global);
589
1.81k
      it->second->send(listener, cState);
590
1.81k
    }
591
592
13.2M
    if (!linkString.empty()) {
593
384
      STOFFLink link;
594
384
      link.m_HRef=linkString.cstr();
595
384
      listener->openLink(link);
596
384
    }
597
13.2M
    if (!refMarkString.empty() && startRefMark) {
598
24
      STOFFField cField;
599
24
      cField.m_propertyList.insert("librevenge:field-type", "text:reference-mark-start");
600
24
      cField.m_propertyList.insert("text:name", refMarkString);
601
24
      listener->insertField(cField);
602
24
    }
603
13.2M
    if (endLinkPos>=0 && int(c)==endLinkPos) {
604
183
      listener->closeLink();
605
183
      endLinkPos=-1;
606
183
    }
607
13.2M
    if (endRefMarkPos>=0 && int(c)==endRefMarkPos) {
608
9
      STOFFField cField;
609
9
      cField.m_propertyList.insert("librevenge:field-type", "text:reference-mark-end");
610
9
      cField.m_propertyList.insert("text:name", refMarkString);
611
9
      listener->insertField(cField);
612
9
      endRefMarkPos=-1;
613
9
    }
614
13.2M
    if (footnote) {
615
3.32k
      StarState cState(*state.m_global);
616
3.32k
      footnote->send(listener, cState);
617
3.32k
    }
618
13.2M
    else if (flyCnt) {
619
2.18k
      StarState cState(*state.m_global);
620
2.18k
      flyCnt->send(listener, cState);
621
2.18k
    }
622
13.2M
    else if (field) {
623
555
      StarState cState(*state.m_global);
624
555
      field->send(listener, cState);
625
555
    }
626
13.2M
    else if (c==m_text.size())
627
72.6k
      break;
628
13.1M
    else if (hardBlank)
629
60
      listener->insertUnicode(0xa0);
630
13.1M
    else if (softHyphen)
631
5.28k
      listener->insertUnicode(0xad);
632
13.1M
    else if (m_text[c]==0x9)
633
55.9k
      listener->insertTab();
634
13.1M
    else if (m_text[c]==0xa)
635
46.3k
      listener->insertEOL(true);
636
13.0M
    else
637
13.0M
      listener->insertUnicode(m_text[c]);
638
13.2M
  }
639
72.8k
  if (endLinkPos>=0) // check that not link is opened
640
193
    listener->closeLink();
641
72.8k
  if (endRefMarkPos>=0) { // check that not refMark is opened
642
15
    STOFFField cField;
643
15
    cField.m_propertyList.insert("librevenge:field-type", "text:reference-mark-end");
644
15
    cField.m_propertyList.insert("text:name", refMarkString);
645
15
    listener->insertField(cField);
646
15
  }
647
72.8k
  return true;
648
72.8k
}
649
650
//! Internal: a table of StarObjectTextInteral
651
struct Table final : public Zone {
652
  //! constructor
653
  Table()
654
5.81k
    : Zone()
655
5.81k
    , m_table()
656
5.81k
  {
657
5.81k
  }
658
  //! try to send the data to a listener
659
  bool send(STOFFListenerPtr &listener, StarState &state) const final;
660
  //! the table
661
  std::shared_ptr<StarTable> m_table;
662
};
663
664
bool Table::send(STOFFListenerPtr &listener, StarState &state) const
665
4.32k
{
666
4.32k
  if (!listener) {
667
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::Table::send: call without listener\n"));
668
0
    return false;
669
0
  }
670
4.32k
  if (!m_table) {
671
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::Table::send: can not find the table\n"));
672
0
    return false;
673
0
  }
674
4.32k
  return m_table->send(listener, state);
675
4.32k
}
676
677
bool Content::send(STOFFListenerPtr &listener, StarState &state, bool isFlyer) const
678
30.2k
{
679
30.2k
  if (!listener) {
680
0
    STOFF_DEBUG_MSG(("StarObjectTextInternal::Content::send: call without listener\n"));
681
0
    return false;
682
0
  }
683
30.2k
  if (isFlyer) {
684
    // check if we need to create a textbox
685
6.82k
    for (size_t t=0; t<m_zoneList.size(); ++t) {
686
3.45k
      if (!std::dynamic_pointer_cast<TextZone>(m_zoneList[t]))
687
3.33k
        continue;
688
113
      StarState cState(state.m_global);
689
113
      auto subDoc = std::make_shared<SubDocument>(*this, cState);
690
113
      STOFFGraphicStyle style=cState.m_graphic;
691
113
      state.m_frame.addTo(style.m_propertyList);
692
113
      listener->insertTextBox(state.m_frame, subDoc, style);
693
113
      return true;
694
3.45k
    }
695
3.49k
  }
696
30.1k
  StarState cState(state.m_global);
697
30.1k
  cState.m_frame=state.m_frame;
698
119k
  for (size_t t=0; t<m_zoneList.size(); ++t) {
699
89.0k
    if (m_zoneList[t])
700
89.0k
      m_zoneList[t]->send(listener, cState);
701
89.0k
    if (t+1!=m_zoneList.size())
702
59.7k
      listener->insertEOL();
703
89.0k
  }
704
30.1k
  return true;
705
30.2k
}
706
707
////////////////////////////////////////
708
//! Internal: the state of a StarObjectText
709
struct State {
710
  //! constructor
711
  State()
712
37.0k
    : m_numPages(0)
713
37.0k
    , m_numGraphicPages(0)
714
37.0k
    , m_mainContent()
715
37.0k
    , m_flyList()
716
37.0k
    , m_numericRuler()
717
37.0k
    , m_pageStyle()
718
37.0k
    , m_model()
719
37.0k
  {
720
37.0k
  }
721
  //! the number of pages
722
  int m_numPages;
723
  //! the graphic number of pages
724
  int m_numGraphicPages;
725
  //! the main content
726
  std::shared_ptr<Content> m_mainContent;
727
  //! the list of fly zone
728
  std::vector<std::shared_ptr<StarFormatManagerInternal::FormatDef> > m_flyList;
729
  //! the numeric ruler
730
  std::shared_ptr<StarObjectNumericRuler> m_numericRuler;
731
  //! the page style
732
  std::shared_ptr<StarObjectPageStyle> m_pageStyle;
733
  //! the drawing model
734
  std::shared_ptr<StarObjectModel> m_model;
735
};
736
737
}
738
739
////////////////////////////////////////////////////////////
740
// constructor/destructor, ...
741
////////////////////////////////////////////////////////////
742
StarObjectText::StarObjectText(StarObject const &orig, bool duplicateState)
743
37.0k
  : StarObject(orig, duplicateState)
744
37.0k
  , m_textState(new StarObjectTextInternal::State)
745
37.0k
{
746
37.0k
}
747
748
StarObjectText::~StarObjectText()
749
37.0k
{
750
37.0k
  cleanPools();
751
37.0k
}
752
753
////////////////////////////////////////////////////////////
754
// send the data
755
////////////////////////////////////////////////////////////
756
bool StarObjectText::updatePageSpans(std::vector<STOFFPageSpan> &pageSpan, int &numPages)
757
18.8k
{
758
18.8k
  numPages=0;
759
760
18.8k
  auto pool=findItemPool(StarItemPool::T_WriterPool, false);
761
18.8k
  StarState state(pool.get(), *this);
762
18.8k
  state.m_global->m_objectModel=m_textState->m_model;
763
18.8k
  if (m_textState->m_mainContent)
764
5.42k
    m_textState->m_mainContent->inventoryPages(state);
765
18.8k
  if (m_textState->m_pageStyle)
766
1.47k
    m_textState->m_pageStyle->updatePageSpans(state.m_global->m_pageNameList, pageSpan, numPages);
767
17.4k
  else {
768
17.4k
    numPages=1000;
769
17.4k
    STOFFPageSpan ps;
770
17.4k
    ps.m_pageSpan=numPages;
771
17.4k
    pageSpan.clear();
772
17.4k
    pageSpan.push_back(ps);
773
17.4k
  }
774
18.8k
  m_textState->m_numPages=numPages;
775
18.8k
  if (m_textState->m_model) {
776
604
    std::vector<STOFFPageSpan> modelPageSpan;
777
604
    m_textState->m_model->updatePageSpans(modelPageSpan, m_textState->m_numGraphicPages);
778
604
  }
779
18.8k
  return numPages>0;
780
18.8k
}
781
782
bool StarObjectText::sendPages(STOFFTextListenerPtr &listener)
783
18.8k
{
784
18.8k
  if (!listener) {
785
0
    STOFF_DEBUG_MSG(("StarObjectText::sendPages: can not find the listener\n"));
786
0
    return false;
787
0
  }
788
18.8k
  if (!m_textState->m_mainContent) {
789
13.4k
    STOFF_DEBUG_MSG(("StarObjectText::sendPages: can not find any content\n"));
790
13.4k
    return true;
791
13.4k
  }
792
  /*
793
  if (m_textState->m_model) {
794
    // send the graphics which are in the model
795
    for (int i=0; i<=m_textState->m_numGraphicPages; ++i)
796
      m_textState->m_model->sendPage(i, listener);
797
  }
798
  */
799
5.42k
  auto pool=findItemPool(StarItemPool::T_WriterPool, false);
800
  // then send the frames relative to the page
801
5.42k
  for (auto fly : m_textState->m_flyList) {
802
1.42k
    if (!fly) continue;
803
1.42k
    StarState state(pool.get(), *this);
804
1.42k
    state.m_global->m_objectModel=m_textState->m_model;
805
1.42k
    fly->send(listener, state);
806
1.42k
  }
807
  // finally send the text content
808
5.42k
  StarState state(pool.get(), *this);
809
5.42k
  state.m_global->m_objectModel=m_textState->m_model;
810
5.42k
  state.m_global->m_numericRuler=m_textState->m_numericRuler;
811
5.42k
  STOFFListenerPtr basicListener(listener);
812
5.42k
  m_textState->m_mainContent->send(basicListener, state);
813
5.42k
  return true;
814
18.8k
}
815
816
////////////////////////////////////////////////////////////
817
// the parser
818
////////////////////////////////////////////////////////////
819
bool StarObjectText::parse()
820
22.7k
{
821
22.7k
  if (!getOLEDirectory() || !getOLEDirectory()->m_input) {
822
0
    STOFF_DEBUG_MSG(("StarObjectText::parser: error, incomplete document\n"));
823
0
    return false;
824
0
  }
825
22.7k
  auto &directory=*getOLEDirectory();
826
22.7k
  StarObject::parse();
827
22.7k
  auto unparsedOLEs=directory.getUnparsedOles();
828
22.7k
  STOFFInputStreamPtr input=directory.m_input;
829
22.7k
  StarFileManager fileManager;
830
22.7k
  STOFFInputStreamPtr mainOle; // let store the StarWriterDocument to read it in last position
831
22.7k
  std::string mainName;
832
97.9k
  for (auto const &name : unparsedOLEs) {
833
97.9k
    STOFFInputStreamPtr ole = input->getSubStreamByName(name.c_str());
834
97.9k
    if (!ole.get()) {
835
30.6k
      STOFF_DEBUG_MSG(("StarObjectText::parse: error: can not find OLE part: \"%s\"\n", name.c_str()));
836
30.6k
      continue;
837
30.6k
    }
838
839
67.3k
    auto pos = name.find_last_of('/');
840
67.3k
    std::string base;
841
67.3k
    if (pos == std::string::npos) base = name;
842
1
    else if (pos == 0) base = name.substr(1);
843
1
    else
844
1
      base = name.substr(pos+1);
845
67.3k
    ole->setReadInverted(true);
846
67.3k
    if (base=="SwNumRules") {
847
1.07k
      try {
848
1.07k
        StarZone zone(ole, name, "StarNumericList", getPassword());
849
1.07k
        std::shared_ptr<StarObjectNumericRuler> numericRuler(new StarObjectNumericRuler(*this,true));
850
1.07k
        if (numericRuler->read(zone))
851
779
          m_textState->m_numericRuler=numericRuler;
852
1.07k
      }
853
1.07k
      catch (...) {
854
0
      }
855
1.07k
      continue;
856
1.07k
    }
857
66.2k
    if (base=="SwPageStyleSheets") {
858
2.73k
      try {
859
2.73k
        StarZone zone(ole, name, "StarPageStyleSheets", getPassword());
860
2.73k
        std::shared_ptr<StarObjectPageStyle> pageStyle(new StarObjectPageStyle(*this,true));
861
2.73k
        if (pageStyle->read(zone))
862
1.56k
          m_textState->m_pageStyle=pageStyle;
863
2.73k
      }
864
2.73k
      catch (...) {
865
0
      }
866
2.73k
      continue;
867
2.73k
    }
868
869
63.5k
    if (base=="DrawingLayer") {
870
7.18k
      readDrawingLayer(ole,name);
871
7.18k
      continue;
872
7.18k
    }
873
56.3k
    if (base=="SfxStyleSheets") {
874
19.4k
      readSfxStyleSheets(ole,name);
875
19.4k
      continue;
876
19.4k
    }
877
36.8k
    if (base=="StarWriterDocument") {
878
22.9k
      mainOle=ole;
879
22.9k
      mainName=name;
880
22.9k
      continue;
881
22.9k
    }
882
13.9k
    if (base!="BasicManager2") {
883
12.8k
      STOFF_DEBUG_MSG(("StarObjectText::parse: find unexpected ole %s\n", name.c_str()));
884
12.8k
    }
885
13.9k
    libstoff::DebugFile asciiFile(ole);
886
13.9k
    asciiFile.open(name);
887
888
13.9k
    libstoff::DebugStream f;
889
13.9k
    f << "Entries(" << base << "):";
890
13.9k
    asciiFile.addPos(0);
891
13.9k
    asciiFile.addNote(f.str().c_str());
892
13.9k
    asciiFile.reset();
893
13.9k
  }
894
22.7k
  if (!mainOle) {
895
0
    STOFF_DEBUG_MSG(("StarObjectText::parser: can not find the main writer document\n"));
896
0
    return false;
897
0
  }
898
22.7k
  readWriterDocument(mainOle,mainName);
899
22.7k
  return true;
900
22.7k
}
901
902
bool StarObjectText::readSfxStyleSheets(STOFFInputStreamPtr input, std::string const &name)
903
19.4k
{
904
19.4k
  StarZone zone(input, name, "SfxStyleSheets", getPassword());
905
19.4k
  input->seek(0, librevenge::RVNG_SEEK_SET);
906
19.4k
  libstoff::DebugFile &ascFile=zone.ascii();
907
19.4k
  ascFile.open(name);
908
909
19.4k
  if (getDocumentKind()!=STOFFDocument::STOFF_K_TEXT) {
910
0
    STOFF_DEBUG_MSG(("StarObjectText::readSfxStyleSheets: called with unexpected document\n"));
911
0
    ascFile.addPos(0);
912
0
    ascFile.addNote("Entries(SfxStyleSheets)");
913
0
    return false;
914
0
  }
915
  // sd_sdbinfilter.cxx SdBINFilter::Import: one pool followed by a pool style
916
  // chart sch_docshell.cxx SchChartDocShell::Load
917
19.4k
  auto pool=getNewItemPool(StarItemPool::T_WriterPool);
918
19.4k
  auto mainPool=pool;
919
21.5k
  while (!input->isEnd()) {
920
    // REMOVEME: remove this loop, when creation of secondary pool is checked
921
21.5k
    long pos=input->tell();
922
21.5k
    bool extraPool=false;
923
21.5k
    if (!pool) {
924
2.08k
      extraPool=true;
925
2.08k
      pool=getNewItemPool(StarItemPool::T_Unknown);
926
2.08k
    }
927
21.5k
    if (pool && pool->read(zone)) {
928
2.08k
      if (extraPool) {
929
3
        STOFF_DEBUG_MSG(("StarObjectText::readSfxStyleSheets: create extra pool of type %d\n", int(pool->getType())));
930
3
      }
931
2.08k
      if (!mainPool) mainPool=pool;
932
2.08k
      pool.reset();
933
2.08k
      continue;
934
2.08k
    }
935
19.4k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
936
19.4k
    break;
937
21.5k
  }
938
19.4k
  if (input->isEnd()) return true;
939
19.4k
  long pos=input->tell();
940
19.4k
  if (!mainPool || !mainPool->readStyles(zone, *this)) {
941
134
    STOFF_DEBUG_MSG(("StarObjectText::readSfxStyleSheets: can not read a style pool\n"));
942
134
    input->seek(pos, librevenge::RVNG_SEEK_SET);
943
134
  }
944
19.4k
  mainPool->updateStyles();
945
19.4k
  if (!input->isEnd()) {
946
3.03k
    STOFF_DEBUG_MSG(("StarObjectText::readSfxStyleSheets: find extra data\n"));
947
3.03k
    ascFile.addPos(input->tell());
948
3.03k
    ascFile.addNote("Entries(SfxStyleSheets):###extra");
949
3.03k
  }
950
19.4k
  return true;
951
19.4k
}
952
953
////////////////////////////////////////////////////////////
954
//
955
// Intermediate level
956
//
957
////////////////////////////////////////////////////////////
958
bool StarObjectText::readSWContent(StarZone &zone, std::shared_ptr<StarObjectTextInternal::Content> &content)
959
74.9k
{
960
74.9k
  STOFFInputStreamPtr input=zone.input();
961
74.9k
  libstoff::DebugFile &ascFile=zone.ascii();
962
74.9k
  unsigned char type;
963
74.9k
  long pos=input->tell();
964
74.9k
  if (input->peek()!='N' || !zone.openSWRecord(type)) {
965
10.0k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
966
10.0k
    return false;
967
10.0k
  }
968
  // sw_sw3sectn.cxx: InContents
969
64.9k
  if (content) {
970
28.0k
    STOFF_DEBUG_MSG(("StarObjectText::readSWContent: oops, the content zone is already created\n"));
971
28.0k
  }
972
36.8k
  else
973
36.8k
    content.reset(new StarObjectTextInternal::Content);
974
64.9k
  libstoff::DebugStream f;
975
64.9k
  f << "Entries(SWContent)[" << zone.getRecordLevel() << "]:";
976
64.9k
  if (zone.isCompatibleWith(5))
977
64.8k
    zone.openFlagZone();
978
64.9k
  int nNodes;
979
64.9k
  if (zone.isCompatibleWith(0x201))
980
38.1k
    nNodes=int(input->readULong(4));
981
26.7k
  else {
982
26.7k
    if (zone.isCompatibleWith(5)) {
983
26.6k
      auto id=int(input->readULong(2));
984
      // dummy sectid, so probably ok if we do not find the pool name
985
26.6k
      if (id>=zone.getNumPoolNames() || !zone.getPoolName(id, content->m_sectionName))
986
20.7k
        f << "#sectId=" << id << ",";
987
5.91k
      else
988
5.91k
        f << "section[name]=" << content->m_sectionName.cstr() << ",";
989
26.6k
    }
990
26.7k
    nNodes=int(input->readULong(2));
991
26.7k
  }
992
64.9k
  f << "N=" << nNodes << ",";
993
64.9k
  if (zone.isCompatibleWith(5))
994
64.8k
    zone.closeFlagZone();
995
64.9k
  ascFile.addPos(pos);
996
64.9k
  ascFile.addNote(f.str().c_str());
997
998
64.9k
  long lastPos=zone.getRecordLastPosition();
999
307k
  for (int i=0; i<nNodes; ++i) {
1000
280k
    if (input->tell()>=lastPos) break;
1001
278k
    pos=input->tell();
1002
278k
    int cType=input->peek();
1003
278k
    bool done=false;
1004
278k
    switch (cType) {
1005
6.38k
    case 'E': {
1006
6.38k
      std::shared_ptr<StarTable> table(new StarTable);
1007
6.38k
      done=table->read(zone, *this);
1008
6.38k
      if (done) {
1009
5.81k
        std::shared_ptr<StarObjectTextInternal::Table> tableZone(new StarObjectTextInternal::Table);
1010
5.81k
        tableZone->m_table=table;
1011
5.81k
        content->m_zoneList.push_back(tableZone);
1012
5.81k
      }
1013
6.38k
      break;
1014
0
    }
1015
3.43k
    case 'G': {
1016
3.43k
      std::shared_ptr<StarObjectTextInternal::GraphZone> graph;
1017
3.43k
      done=readSWGraphNode(zone, graph);
1018
3.43k
      if (done && graph)
1019
3.15k
        content->m_zoneList.push_back(graph);
1020
3.43k
      break;
1021
0
    }
1022
21.3k
    case 'I': {
1023
21.3k
      std::shared_ptr<StarObjectTextInternal::SectionZone> section;
1024
21.3k
      done=readSWSection(zone, section);
1025
21.3k
      if (done && section)
1026
20.9k
        content->m_zoneList.push_back(section);
1027
21.3k
      break;
1028
0
    }
1029
36.6k
    case 'O': {
1030
36.6k
      std::shared_ptr<StarObjectTextInternal::OLEZone> ole;
1031
36.6k
      done=readSWOLENode(zone, ole);
1032
36.6k
      if (done && ole)
1033
35.9k
        content->m_zoneList.push_back(ole);
1034
36.6k
      break;
1035
0
    }
1036
111k
    case 'T': {
1037
111k
      std::shared_ptr<StarObjectTextInternal::TextZone> text;
1038
111k
      done=readSWTextZone(zone, text);
1039
111k
      if (done && text)
1040
110k
        content->m_zoneList.push_back(text);
1041
111k
      break;
1042
0
    }
1043
1.02k
    case 'l': // related to link
1044
1.75k
    case 'o': { // format: safe to ignore
1045
1.75k
      std::shared_ptr<StarFormatManagerInternal::FormatDef> format;
1046
1.75k
      done=getFormatManager()->readSWFormatDef(zone,static_cast<unsigned char>(cType),format, *this);
1047
1.75k
      if (done && format) {
1048
1.03k
        std::shared_ptr<StarObjectTextInternal::FormatZone> formatZone;
1049
1.03k
        formatZone.reset(new StarObjectTextInternal::FormatZone(format));
1050
1.03k
        content->m_zoneList.push_back(formatZone);
1051
1.03k
      }
1052
1.75k
      break;
1053
1.02k
    }
1054
408
    case 'v': {
1055
408
      StarWriterStruct::NodeRedline redline;
1056
408
      done=redline.read(zone);
1057
408
      break;
1058
1.02k
    }
1059
97.2k
    default:
1060
97.2k
      break;
1061
278k
    }
1062
278k
    if (done) continue;
1063
100k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1064
100k
    if (!zone.openSWRecord(type)) {
1065
36.1k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1066
36.1k
      break;
1067
36.1k
    }
1068
64.3k
    f.str("");
1069
64.3k
    f << "SWContent[" << type << "-" << zone.getRecordLevel() << "]:";
1070
64.3k
    switch (cType) {
1071
2.36k
    case 'i':
1072
      // sw_sw3node.cxx InRepTxtNode
1073
2.36k
      f << "repTxtNode,";
1074
2.36k
      f << "rep=" << input->readULong(4) << ",";
1075
2.36k
      break;
1076
61.9k
    default:
1077
61.9k
      STOFF_DEBUG_MSG(("StarObjectText::readSWContent: find unexpected type\n"));
1078
61.9k
      f << "###";
1079
64.3k
    }
1080
64.3k
    ascFile.addPos(pos);
1081
64.3k
    ascFile.addNote(f.str().c_str());
1082
64.3k
    zone.closeSWRecord(type, "SWContent");
1083
64.3k
  }
1084
64.9k
  zone.closeSWRecord('N', "SWContent");
1085
64.9k
  return true;
1086
64.9k
}
1087
1088
bool StarObjectText::readSWGraphNode(StarZone &zone, std::shared_ptr<StarObjectTextInternal::GraphZone> &graphZone)
1089
3.43k
{
1090
3.43k
  STOFFInputStreamPtr input=zone.input();
1091
3.43k
  libstoff::DebugFile &ascFile=zone.ascii();
1092
3.43k
  unsigned char type;
1093
3.43k
  long pos=input->tell();
1094
3.43k
  if (input->peek()!='G' || !zone.openSWRecord(type)) {
1095
286
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1096
286
    return false;
1097
286
  }
1098
  // sw_sw3nodes.cxx: InGrfNode
1099
3.15k
  libstoff::DebugStream f;
1100
3.15k
  f << "Entries(SWGraphNode)[" << zone.getRecordLevel() << "]:";
1101
3.15k
  graphZone.reset(new StarObjectTextInternal::GraphZone(m_oleParser));
1102
3.15k
  std::vector<uint32_t> text;
1103
3.15k
  int fl=zone.openFlagZone();
1104
3.15k
  if (fl&0x10) f << "link,";
1105
3.15k
  if (fl&0x20) f << "empty,";
1106
3.15k
  if (fl&0x40) f << "serverMap,";
1107
3.15k
  zone.closeFlagZone();
1108
8.28k
  for (int i=0; i<2; ++i) {
1109
5.76k
    if (!zone.readString(text)) {
1110
634
      STOFF_DEBUG_MSG(("StarObjectText::readSWGraphNode: can not read a string\n"));
1111
634
      f << "###string";
1112
634
      ascFile.addPos(pos);
1113
634
      ascFile.addNote(f.str().c_str());
1114
634
      zone.closeSWRecord('G', "SWGraphNode");
1115
634
      return true;
1116
634
    }
1117
5.13k
    if (!text.empty()) {
1118
2.95k
      graphZone->m_names[i]=libstoff::getString(text);
1119
2.95k
      f << (i==0 ? "grfName" : "fltName") << "=" << graphZone->m_names[i].cstr() << ",";
1120
2.95k
    }
1121
5.13k
  }
1122
2.51k
  if (zone.isCompatibleWith(0x101)) {
1123
1.64k
    if (!zone.readString(text)) {
1124
164
      STOFF_DEBUG_MSG(("StarObjectText::readSWGraphNode: can not read a objName\n"));
1125
164
      f << "###textRepl";
1126
164
      ascFile.addPos(pos);
1127
164
      ascFile.addNote(f.str().c_str());
1128
164
      zone.closeSWRecord('G', "SWGraphNode");
1129
164
      return true;
1130
164
    }
1131
1.48k
    if (!text.empty()) {
1132
252
      graphZone->m_names[2]=libstoff::getString(text);
1133
252
      f << "textRepl=" << graphZone->m_names[2].cstr() << ",";
1134
252
    }
1135
1.48k
  }
1136
2.35k
  ascFile.addPos(pos);
1137
2.35k
  ascFile.addNote(f.str().c_str());
1138
2.35k
  long lastPos=zone.getRecordLastPosition();
1139
3.39k
  while (input->tell() < lastPos) {
1140
1.38k
    pos=input->tell();
1141
1.38k
    bool done=false;
1142
1.38k
    int rType=input->peek();
1143
1144
1.38k
    switch (rType) {
1145
912
    case 'S':
1146
912
      done=StarWriterStruct::Attribute::readList(zone, graphZone->m_attributeList, *this);
1147
912
      break;
1148
117
    case 'X': // store me
1149
117
      done=readSWImageMap(zone);
1150
117
      break;
1151
355
    default:
1152
355
      break;
1153
1.38k
    }
1154
1.38k
    if (done)
1155
1.00k
      continue;
1156
377
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1157
377
    if (!zone.openSWRecord(type)) {
1158
346
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1159
346
      break;
1160
346
    }
1161
31
    f.str("");
1162
31
    f << "SWGraphNode[" << type << "-" << zone.getRecordLevel() << "]:";
1163
31
    switch (type) {
1164
0
    case 'k': {
1165
      // sw_sw3nodes.cxx InContour
1166
0
      int polyFl=zone.openFlagZone();
1167
0
      zone.closeFlagZone();
1168
0
      if (polyFl&0x10) {
1169
        // poly2.cxx operator>>
1170
0
        auto numPoly=int(input->readULong(2));
1171
0
        for (int i=0; i<numPoly; ++i) {
1172
0
          f << "poly" << i << "=[";
1173
          // poly.cxx operator>>
1174
0
          auto numPoints=int(input->readULong(2));
1175
0
          if (input->tell()+8*numPoints>lastPos) {
1176
0
            STOFF_DEBUG_MSG(("StarObjectText::readSWGraphNode: can not read a polygon\n"));
1177
0
            f << "###poly";
1178
0
            break;
1179
0
          }
1180
0
          for (int p=0; p<numPoints; ++p) {
1181
0
            int dim[2];
1182
0
            for (int &j : dim) j=int(input->readLong(4));
1183
0
            graphZone->m_contour.m_points.push_back(StarGraphicStruct::StarPolygon::Point(STOFFVec2i(dim[0],dim[1])));
1184
0
            f << STOFFVec2i(dim[0],dim[1]) << ",";
1185
0
          }
1186
0
          f << "],";
1187
0
        }
1188
0
      }
1189
0
      break;
1190
0
    }
1191
31
    default:
1192
31
      STOFF_DEBUG_MSG(("StarObjectText::readSWGraphNode: find unexpected type\n"));
1193
31
      f << "###";
1194
31
      break;
1195
31
    }
1196
31
    ascFile.addPos(pos);
1197
31
    ascFile.addNote(f.str().c_str());
1198
31
    zone.closeSWRecord(type, "SWGraphNode");
1199
31
  }
1200
1201
2.35k
  zone.closeSWRecord('G', "SWGraphNode");
1202
2.35k
  return true;
1203
2.35k
}
1204
1205
bool StarObjectText::readSWImageMap(StarZone &zone)
1206
203
{
1207
203
  STOFFInputStreamPtr input=zone.input();
1208
203
  libstoff::DebugFile &ascFile=zone.ascii();
1209
203
  unsigned char type;
1210
203
  long pos=input->tell();
1211
203
  if (input->peek()!='X' || !zone.openSWRecord(type)) {
1212
94
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1213
94
    return false;
1214
94
  }
1215
1216
109
  libstoff::DebugStream f;
1217
109
  f << "Entries(SWImageMap)[" << zone.getRecordLevel() << "]:";
1218
  // sw_sw3nodes.cxx InImageMap
1219
109
  int flag=zone.openFlagZone();
1220
109
  if (flag&0xF0) f << "fl=" << flag << ",";
1221
109
  zone.closeFlagZone();
1222
109
  std::vector<uint32_t> string;
1223
109
  if (!zone.readString(string)) {
1224
18
    STOFF_DEBUG_MSG(("StarObjectText::readSWImageMap: can not read url\n"));
1225
18
    f << "###url";
1226
18
    ascFile.addPos(pos);
1227
18
    ascFile.addNote(f.str().c_str());
1228
1229
18
    zone.closeSWRecord('X', "SWImageMap");
1230
18
    return true;
1231
18
  }
1232
91
  if (!string.empty())
1233
74
    f << "url=" << libstoff::getString(string).cstr() << ",";
1234
91
  if (zone.isCompatibleWith(0x11,0x22, 0x101)) {
1235
162
    for (int i=0; i<2; ++i) {
1236
119
      if (!zone.readString(string)) {
1237
23
        STOFF_DEBUG_MSG(("StarObjectText::readSWImageMap: can not read string\n"));
1238
23
        f << "###string";
1239
23
        ascFile.addPos(pos);
1240
23
        ascFile.addNote(f.str().c_str());
1241
1242
23
        zone.closeSWRecord('X', "SWImageMap");
1243
23
        return true;
1244
23
      }
1245
96
      if (string.empty()) continue;
1246
34
      f << (i==0 ? "target" : "dummy") << "=" << libstoff::getString(string).cstr() << ",";
1247
34
    }
1248
66
  }
1249
68
  if (flag&0x20) {
1250
    // svt_imap.cxx: ImageMap::Read
1251
56
    std::string cMagic("");
1252
392
    for (int i=0; i<6; ++i) cMagic+=char(input->readULong(1));
1253
56
    if (cMagic!="SDIMAP") {
1254
38
      STOFF_DEBUG_MSG(("StarObjectText::readSWImageMap: cMagic is bad\n"));
1255
38
      f << "###cMagic=" << cMagic << ",";
1256
38
    }
1257
18
    else {
1258
18
      input->seek(2, librevenge::RVNG_SEEK_CUR);
1259
47
      for (int i=0; i<3; ++i) {
1260
40
        if (!zone.readString(string)) {
1261
11
          STOFF_DEBUG_MSG(("StarObjectText::readSWImageMap: can not read string\n"));
1262
11
          f << "###string";
1263
11
          ascFile.addPos(pos);
1264
11
          ascFile.addNote(f.str().c_str());
1265
1266
11
          zone.closeSWRecord('X', "SWImageMap");
1267
11
          return true;
1268
11
        }
1269
29
        if (!string.empty())
1270
8
          f << (i==0 ? "target" : i==1 ? "dummy1" : "dummy2") << "=" << libstoff::getString(string).cstr() << ",";
1271
29
        if (i==1)
1272
8
          f << "nCount=" << input->readULong(2) << ",";
1273
29
      }
1274
7
      if (input->tell()<zone.getRecordLastPosition()) {
1275
0
        STOFF_DEBUG_MSG(("StarObjectText::readSWImageMap: find imapCompat data, not implemented\n"));
1276
        // svt_imap3.cxx IMapCompat::IMapCompat
1277
0
        ascFile.addPos(input->tell());
1278
0
        ascFile.addNote("SWImageMap:###IMapCompat");
1279
0
        input->seek(zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
1280
0
      }
1281
7
    }
1282
56
  }
1283
57
  ascFile.addPos(pos);
1284
57
  ascFile.addNote(f.str().c_str());
1285
57
  zone.closeSWRecord('X', "SWImageMap");
1286
57
  return true;
1287
68
}
1288
1289
bool StarObjectText::readSWJobSetUp(StarZone &zone)
1290
2.40k
{
1291
2.40k
  STOFFInputStreamPtr input=zone.input();
1292
2.40k
  libstoff::DebugFile &ascFile=zone.ascii();
1293
2.40k
  unsigned char type;
1294
2.40k
  long pos=input->tell();
1295
2.40k
  if (input->peek()!='J' || !zone.openSWRecord(type)) {
1296
100
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1297
100
    return false;
1298
100
  }
1299
1300
2.30k
  libstoff::DebugStream f;
1301
2.30k
  zone.openFlagZone();
1302
2.30k
  zone.closeFlagZone();
1303
2.30k
  if (input->tell()==zone.getRecordLastPosition()) // empty
1304
8
    f << "Entries(JobSetUp)[" << zone.getRecordLevel() << "]:";
1305
2.29k
  else {
1306
2.29k
    f << "JobSetUp[container-" << zone.getRecordLevel() << "]:";
1307
2.29k
    StarFileManager fileManager;
1308
2.29k
    fileManager.readJobSetUp(zone, false);
1309
2.29k
  }
1310
2.30k
  ascFile.addPos(pos);
1311
2.30k
  ascFile.addNote(f.str().c_str());
1312
1313
2.30k
  zone.closeSWRecord(type, "JobSetUp[container]");
1314
2.30k
  return true;
1315
2.40k
}
1316
1317
bool StarObjectText::readSWOLENode(StarZone &zone, std::shared_ptr<StarObjectTextInternal::OLEZone> &ole)
1318
36.6k
{
1319
36.6k
  STOFFInputStreamPtr input=zone.input();
1320
36.6k
  libstoff::DebugFile &ascFile=zone.ascii();
1321
36.6k
  unsigned char type;
1322
36.6k
  long pos=input->tell();
1323
36.6k
  if (input->peek()!='O' || !zone.openSWRecord(type)) {
1324
313
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1325
313
    return false;
1326
313
  }
1327
  // sw_sw3nodes.cxx: InOLENode
1328
36.3k
  libstoff::DebugStream f;
1329
36.3k
  f << "Entries(SWOLENode)[" << zone.getRecordLevel() << "]:";
1330
1331
36.3k
  std::vector<uint32_t> text;
1332
36.3k
  if (!zone.readString(text)) {
1333
350
    STOFF_DEBUG_MSG(("StarObjectText::readSWOLENode: can not read a objName\n"));
1334
350
    f << "###objName";
1335
350
    ascFile.addPos(pos);
1336
350
    ascFile.addNote(f.str().c_str());
1337
350
    zone.closeSWRecord('O', "SWOLENode");
1338
350
    return true;
1339
350
  }
1340
35.9k
  ole.reset(new StarObjectTextInternal::OLEZone);
1341
35.9k
  ole->m_oleParser=m_oleParser;
1342
35.9k
  if (!text.empty()) {
1343
35.9k
    ole->m_name=libstoff::getString(text);
1344
35.9k
    f << "objName=" << ole->m_name.cstr() << ",";
1345
35.9k
  }
1346
35.9k
  if (zone.isCompatibleWith(0x101)) {
1347
30.3k
    if (!zone.readString(text)) {
1348
19.3k
      STOFF_DEBUG_MSG(("StarObjectText::readSWOLENode: can not read a objName\n"));
1349
19.3k
      f << "###textRepl";
1350
19.3k
      ascFile.addPos(pos);
1351
19.3k
      ascFile.addNote(f.str().c_str());
1352
19.3k
      zone.closeSWRecord('O', "SWOLENode");
1353
19.3k
      return true;
1354
19.3k
    }
1355
10.9k
    if (!text.empty()) {
1356
5.88k
      ole->m_replaceText=libstoff::getString(text);
1357
5.88k
      f << "textRepl=" << ole->m_replaceText.cstr() << ",";
1358
5.88k
    }
1359
10.9k
  }
1360
16.5k
  ascFile.addPos(pos);
1361
16.5k
  ascFile.addNote(f.str().c_str());
1362
16.5k
  zone.closeSWRecord('O', "SWOLENode");
1363
16.5k
  return true;
1364
35.9k
}
1365
1366
bool StarObjectText::readSWSection(StarZone &zone, std::shared_ptr<StarObjectTextInternal::SectionZone> &section)
1367
21.3k
{
1368
21.3k
  STOFFInputStreamPtr input=zone.input();
1369
21.3k
  libstoff::DebugFile &ascFile=zone.ascii();
1370
21.3k
  unsigned char type;
1371
21.3k
  long pos=input->tell();
1372
21.3k
  if (input->peek()!='I' || !zone.openSWRecord(type)) {
1373
429
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1374
429
    return false;
1375
429
  }
1376
  // sw_sw3sectn.cxx: InSection
1377
20.9k
  libstoff::DebugStream f;
1378
20.9k
  f << "Entries(SWSection)[" << zone.getRecordLevel() << "]:";
1379
20.9k
  section.reset(new StarObjectTextInternal::SectionZone);
1380
20.9k
  std::vector<uint32_t> text;
1381
53.6k
  for (int i=0; i<2; ++i) {
1382
39.9k
    if (!zone.readString(text)) {
1383
7.29k
      STOFF_DEBUG_MSG(("StarObjectText::readSWSection: can not read a string\n"));
1384
7.29k
      f << "###string";
1385
7.29k
      ascFile.addPos(pos);
1386
7.29k
      ascFile.addNote(f.str().c_str());
1387
7.29k
      zone.closeSWRecord('I', "SWSection");
1388
7.29k
      return true;
1389
7.29k
    }
1390
32.6k
    if (text.empty()) continue;
1391
21.9k
    if (i==0)
1392
13.1k
      section->m_name=libstoff::getString(text);
1393
8.74k
    else
1394
8.74k
      section->m_condition=libstoff::getString(text);
1395
21.9k
    f << (i==0 ? "name" : "cond") << "=" << libstoff::getString(text).cstr() << ",";
1396
21.9k
  }
1397
13.6k
  int fl=section->m_flags=zone.openFlagZone();
1398
13.6k
  if (fl&0x10) f << "hidden,";
1399
13.6k
  if (fl&0x20) f << "protect,";
1400
13.6k
  if (fl&0x40) f << "condHidden,";
1401
13.6k
  if (fl&0x80) f << "connectFlag,";
1402
13.6k
  section->m_type=int(input->readULong(2));
1403
13.6k
  if (section->m_type) f << "nType=" << section->m_type << ",";
1404
13.6k
  zone.closeFlagZone();
1405
13.6k
  long lastPos=zone.getRecordLastPosition();
1406
17.1k
  while (input->tell()<lastPos) {
1407
5.46k
    long actPos=input->tell();
1408
5.46k
    int c=input->peek();
1409
5.46k
    bool done=false;
1410
5.46k
    switch (c) { // checkme: unsure which data can be found here
1411
2.69k
    case 's':
1412
2.69k
      done=getFormatManager()->readSWFormatDef(zone,'s', section->m_format, *this);
1413
2.69k
      break;
1414
1.42k
    case 'N':
1415
1.42k
      done=readSWContent(zone, section->m_content);
1416
1.42k
      break;
1417
1.34k
    default:
1418
1.34k
      break;
1419
5.46k
    }
1420
5.46k
    if (!done || input->tell()<=actPos || input->tell()>lastPos) {
1421
1.99k
      input->seek(actPos, librevenge::RVNG_SEEK_SET);
1422
1.99k
      break;
1423
1.99k
    }
1424
5.46k
  }
1425
13.6k
  if (zone.isCompatibleWith(0xd)) {
1426
13.3k
    if (!zone.readString(text)) {
1427
4.69k
      STOFF_DEBUG_MSG(("StarObjectText::readSWSection: can not read a linkName\n"));
1428
4.69k
      f << "###linkName";
1429
4.69k
      ascFile.addPos(pos);
1430
4.69k
      ascFile.addNote(f.str().c_str());
1431
4.69k
      zone.closeSWRecord('I', "SWSection");
1432
4.69k
      return true;
1433
4.69k
    }
1434
8.67k
    else if (!text.empty()) {
1435
2.66k
      section->m_linkName=libstoff::getString(text);
1436
2.66k
      f << "linkName=" << section->m_linkName.cstr() << ",";
1437
2.66k
    }
1438
13.3k
  }
1439
8.98k
  ascFile.addPos(pos);
1440
8.98k
  ascFile.addNote(f.str().c_str());
1441
8.98k
  zone.closeSWRecord('I', "SWSection");
1442
8.98k
  return true;
1443
13.6k
}
1444
1445
bool StarObjectText::readSWTextZone(StarZone &zone, std::shared_ptr<StarObjectTextInternal::TextZone> &textZone)
1446
111k
{
1447
111k
  STOFFInputStreamPtr input=zone.input();
1448
111k
  libstoff::DebugFile &ascFile=zone.ascii();
1449
111k
  unsigned char type;
1450
111k
  long pos=input->tell();
1451
111k
  if (input->peek()!='T' || !zone.openSWRecord(type)) {
1452
823
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1453
823
    return false;
1454
823
  }
1455
  // sw_sw3nodes.cxx: InTxtNode
1456
110k
  libstoff::DebugStream f;
1457
110k
  f << "Entries(SWText)[" << zone.getRecordLevel() << "]:";
1458
110k
  textZone.reset(new StarObjectTextInternal::TextZone);
1459
110k
  int fl=zone.openFlagZone();
1460
110k
  auto poolId=int(input->readULong(2));
1461
110k
  if (!zone.getPoolName(poolId, textZone->m_styleName))
1462
60.1k
    f << "###nPoolId=" << poolId << ",";
1463
50.3k
  else
1464
50.3k
    f << textZone->m_styleName.cstr() << ",";
1465
110k
  if (fl&0x10 && !zone.isCompatibleWith(0x201)) {
1466
4.38k
    auto val=int(input->readULong(1));
1467
4.38k
    if (val==200 && zone.isCompatibleWith(0xf,0x101) && input->tell() < zone.getFlagLastPosition())
1468
4
      val=int(input->readULong(1));
1469
4.38k
    if (val!=200) {
1470
4.36k
      textZone->m_level=val&0x1f;
1471
4.36k
      f << "nLevel=" << val << ",";
1472
4.36k
    }
1473
4.38k
  }
1474
110k
  if (zone.isCompatibleWith(0x19,0x22, 0x101))
1475
77.4k
    f << "nCondColl=" << input->readULong(2) << ",";
1476
110k
  zone.closeFlagZone();
1477
1478
110k
  if (!zone.readString(textZone->m_text, textZone->m_textSourcePosition, -1, true)) {
1479
14.2k
    STOFF_DEBUG_MSG(("StarObjectText::readSWTextZone: can not read main text\n"));
1480
14.2k
    f << "###text";
1481
14.2k
    ascFile.addPos(pos);
1482
14.2k
    ascFile.addNote(f.str().c_str());
1483
14.2k
    zone.closeSWRecord('T', "SWText");
1484
14.2k
    return true;
1485
14.2k
  }
1486
96.3k
  else if (!textZone->m_text.empty())
1487
72.5k
    f << libstoff::getString(textZone->m_text).cstr();
1488
1489
96.3k
  ascFile.addPos(pos);
1490
96.3k
  ascFile.addNote(f.str().c_str());
1491
1492
96.3k
  long lastPos=zone.getRecordLastPosition();
1493
183k
  while (input->tell()<lastPos) {
1494
98.5k
    pos=input->tell();
1495
1496
98.5k
    bool done=false;
1497
98.5k
    int rType=input->peek();
1498
1499
98.5k
    switch (rType) {
1500
19.2k
    case 'A': {
1501
19.2k
      StarWriterStruct::Attribute attrib;
1502
19.2k
      done=attrib.read(zone, *this);
1503
19.2k
      if (done)
1504
18.1k
        textZone->m_charAttributeList.push_back(attrib);
1505
19.2k
      break;
1506
0
    }
1507
2.20k
    case 'K': {
1508
2.20k
      StarWriterStruct::Mark mark;
1509
2.20k
      done=mark.read(zone);
1510
2.20k
      if (done) textZone->m_markList.push_back(mark);
1511
2.20k
      break;
1512
0
    }
1513
278
    case '0':
1514
3.53k
    case 'R': {
1515
3.53k
      std::shared_ptr<STOFFList> list;
1516
3.53k
      done=StarObjectNumericRuler::readList(zone,list);
1517
3.53k
      if (done && list) textZone->m_list=list;
1518
3.53k
      break;
1519
278
    }
1520
50.3k
    case 'S':
1521
50.3k
      done=StarWriterStruct::Attribute::readList(zone, textZone->m_charAttributeList, *this);
1522
50.3k
      break;
1523
1.54k
    case 'l': { // related to link
1524
1.54k
      std::shared_ptr<StarFormatManagerInternal::FormatDef> format;
1525
1.54k
      done=getFormatManager()->readSWFormatDef(zone,'l', format, *this);
1526
1.54k
      if (done && format)
1527
1.49k
        textZone->m_formatList.push_back(format);
1528
1.54k
      break;
1529
278
    }
1530
924
    case 'o': { //
1531
924
      std::shared_ptr<StarFormatManagerInternal::FormatDef> format;
1532
924
      done=getFormatManager()->readSWFormatDef(zone,'o', format, *this);
1533
924
      if (done && format)
1534
327
        textZone->m_formatList.push_back(format);
1535
924
      break;
1536
278
    }
1537
115
    case 'v': {
1538
115
      StarWriterStruct::NodeRedline redline;
1539
115
      done=redline.read(zone);
1540
115
      break;
1541
278
    }
1542
20.6k
    default:
1543
20.6k
      break;
1544
98.5k
    }
1545
98.5k
    if (done)
1546
74.8k
      continue;
1547
23.7k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1548
23.7k
    if (!zone.openSWRecord(type)) {
1549
11.5k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1550
11.5k
      break;
1551
11.5k
    }
1552
12.2k
    f.str("");
1553
12.2k
    f << "SWText[" << type << "-" << zone.getRecordLevel() << "]:";
1554
12.2k
    switch (type) {
1555
3.41k
    case '3': {
1556
      // sw_sw3num InNodeNum
1557
3.41k
      f << "nodeNum,";
1558
3.41k
      int cFlag=zone.openFlagZone();
1559
3.41k
      auto nLevel=int(input->readULong(1));
1560
3.41k
      if (nLevel!=201) {
1561
3.41k
        int level=(nLevel&0x1f);
1562
3.41k
        if (level>=10) {
1563
82
          level=9;
1564
82
          if (nLevel&0x20) level |= 0x20;
1565
82
        }
1566
3.41k
        textZone->m_level=level;
1567
3.41k
        f << "nLevel=" << level<< ",";
1568
3.41k
      }
1569
3.41k
      if (cFlag&0x20) f << "nSetValue=" << input->readULong(2) << ",";
1570
3.41k
      zone.closeFlagZone();
1571
3.41k
      if (nLevel!=201) {
1572
3.41k
        int N=int(zone.getRecordLastPosition()-input->tell())/2;
1573
3.41k
        f << "level=[";
1574
7.61k
        for (int i=0; i<N; ++i)
1575
4.20k
          f << input->readULong(2) << ",";
1576
3.41k
        f << "],";
1577
3.41k
      }
1578
3.41k
      break;
1579
0
    }
1580
6.97k
    case 'w': { // wrong list
1581
      // sw_sw3nodes.cxx in text node
1582
6.97k
      f << "wrongList,";
1583
6.97k
      int cFlag=zone.openFlagZone();
1584
6.97k
      if (cFlag&0xf0) f << "flag=" << (cFlag>>4) << ",";
1585
6.97k
      f << "nBeginInv=" << input->readULong(2) << ",";
1586
6.97k
      f << "nEndInc=" << input->readULong(2) << ",";
1587
6.97k
      zone.closeFlagZone();
1588
6.97k
      auto N =int(input->readULong(2));
1589
6.97k
      if (input->tell()+4*N>zone.getRecordLastPosition()) {
1590
60
        STOFF_DEBUG_MSG(("StarObjectText::readSWTextZone: find bad count\n"));
1591
60
        f << "###N=" << N << ",";
1592
60
        break;
1593
60
      }
1594
6.91k
      f << "nWrong=[";
1595
24.6k
      for (int i=0; i<N; ++i) f << input->readULong(4) << ",";
1596
6.91k
      f << "],";
1597
6.91k
      break;
1598
6.97k
    }
1599
1.83k
    default:
1600
1.83k
      STOFF_DEBUG_MSG(("StarObjectText::readSWTextZone: find unexpected type\n"));
1601
1.83k
      f << "###";
1602
12.2k
    }
1603
12.2k
    ascFile.addPos(pos);
1604
12.2k
    ascFile.addNote(f.str().c_str());
1605
12.2k
    zone.closeSWRecord(type, "SWText");
1606
12.2k
  }
1607
96.3k
  zone.closeSWRecord('T', "SWText");
1608
96.3k
  return true;
1609
96.3k
}
1610
1611
////////////////////////////////////////////////////////////
1612
// drawing layer
1613
////////////////////////////////////////////////////////////
1614
bool StarObjectText::readDrawingLayer(STOFFInputStreamPtr input, std::string const &name)
1615
7.18k
try
1616
7.18k
{
1617
7.18k
  StarZone zone(input, name, "DrawingLayer", getPassword());
1618
7.18k
  input->seek(0, librevenge::RVNG_SEEK_SET);
1619
7.18k
  libstoff::DebugFile &ascFile=zone.ascii();
1620
7.18k
  ascFile.open(name);
1621
  // sw_sw3imp.cxx Sw3IoImp::LoadDrawingLayer
1622
1623
  // create this pool from the main's SWG pool
1624
7.18k
  auto pool=getNewItemPool(StarItemPool::T_XOutdevPool);
1625
7.18k
  pool->setRelativeUnit(0.05);
1626
7.18k
  pool->addSecondaryPool(getNewItemPool(StarItemPool::T_EditEnginePool));
1627
1628
7.93k
  while (!input->isEnd()) {
1629
    // REMOVEME: remove this loop, when creation of secondary pool is checked
1630
7.93k
    long pos=input->tell();
1631
7.93k
    bool extraPool=false;
1632
7.93k
    if (!pool) {
1633
747
      extraPool=true;
1634
747
      pool=getNewItemPool(StarItemPool::T_Unknown);
1635
747
    }
1636
7.93k
    if (pool && pool->read(zone)) {
1637
747
      if (extraPool) {
1638
0
        STOFF_DEBUG_MSG(("StarObjectText::readDrawingLayer: create extra pool for %d of type %d\n",
1639
0
                         int(getDocumentKind()), int(pool->getType())));
1640
0
      }
1641
747
      pool.reset();
1642
747
      continue;
1643
747
    }
1644
7.18k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1645
7.18k
    break;
1646
7.93k
  }
1647
7.18k
  long pos=input->tell();
1648
7.18k
  std::shared_ptr<StarObjectModel> model(new StarObjectModel(*this, true));
1649
7.18k
  if (!model->read(zone)) {
1650
6.51k
    STOFF_DEBUG_MSG(("StarObjectText::readDrawingLayer: can not read the drawing model\n"));
1651
6.51k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1652
6.51k
    ascFile.addPos(input->tell());
1653
6.51k
    ascFile.addNote("Entries(DrawingLayer):###extra");
1654
6.51k
    return true;
1655
6.51k
  }
1656
674
  if (m_textState->m_model) {
1657
0
    STOFF_DEBUG_MSG(("StarObjectText::readDrawingLayer: oops the drawing model is already defined\n"));
1658
0
  }
1659
674
  else
1660
674
    m_textState->m_model=model;
1661
674
  if (input->isEnd()) return true;
1662
674
  pos=input->tell();
1663
674
  uint16_t nSign;
1664
674
  *input >> nSign;
1665
674
  libstoff::DebugStream f;
1666
674
  f << "Entries(DrawingLayer):";
1667
674
  bool ok=true;
1668
674
  std::set<long> ids;
1669
674
  if (nSign!=0x444D && nSign!=0) // 0 seems ok if followed by 0
1670
225
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1671
449
  else {
1672
449
    uint16_t n;
1673
449
    *input >> n;
1674
449
    if (pos+4+4*long(n)>input->size()) {
1675
28
      STOFF_DEBUG_MSG(("StarObjectText::readDrawingLayer: bad n frame\n"));
1676
28
      f << "###pos";
1677
28
      ok=false;
1678
28
    }
1679
421
    else {
1680
421
      f << "framePos=[";
1681
2.73k
      for (uint16_t i=0; i<n; ++i) {
1682
2.31k
        auto id=long(input->readULong(4));
1683
2.31k
        ids.insert(id);
1684
2.31k
        f << id << ",";
1685
2.31k
      }
1686
421
      f << "],";
1687
421
    }
1688
449
  }
1689
674
  if (ok && input->tell()+4==input->size())
1690
103
    f << "num[hidden]=" << input->readULong(4) << ",";
1691
674
  if (ok && !input->isEnd()) {
1692
287
    STOFF_DEBUG_MSG(("StarObjectText::readDrawingLayer: find extra data\n"));
1693
287
    f << "###extra";
1694
287
  }
1695
674
  model->updateObjectIds(ids);
1696
674
  ascFile.addPos(pos);
1697
674
  ascFile.addNote(f.str().c_str());
1698
674
  return true;
1699
674
}
1700
7.18k
catch (...)
1701
7.18k
{
1702
0
  return false;
1703
0
}
1704
1705
////////////////////////////////////////////////////////////
1706
// main zone
1707
////////////////////////////////////////////////////////////
1708
bool StarObjectText::readWriterDocument(STOFFInputStreamPtr input, std::string const &name)
1709
22.7k
try
1710
22.7k
{
1711
22.7k
  StarZone zone(input, name, "SWWriterDocument", getPassword());
1712
22.7k
  if (!zone.readSWHeader()) {
1713
12.0k
    STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: can not read the header\n"));
1714
12.0k
    return false;
1715
12.0k
  }
1716
10.6k
  libstoff::DebugFile &ascFile=zone.ascii();
1717
  // sw_sw3doc.cxx Sw3IoImp::LoadDocContents
1718
10.6k
  SWFieldManager fieldManager;
1719
10.6k
  StarFileManager fileManager;
1720
127k
  while (!input->isEnd()) {
1721
126k
    long pos=input->tell();
1722
126k
    int rType=input->peek();
1723
126k
    bool done=false;
1724
126k
    switch (rType) {
1725
6.27k
    case '!':
1726
6.27k
      done=zone.readStringsPool();
1727
6.27k
      break;
1728
890
    case 'R':
1729
6.12k
    case '0': { // Outline
1730
6.12k
      std::shared_ptr<STOFFList> list;
1731
6.12k
      done=StarObjectNumericRuler::readList(zone,list);
1732
6.12k
      break;
1733
890
    }
1734
7.38k
    case '1': {
1735
7.38k
      StarWriterStruct::NoteInfo info(true);
1736
7.38k
      done=info.read(zone);
1737
7.38k
      break;
1738
890
    }
1739
1.94k
    case '4': {
1740
1.94k
      StarWriterStruct::NoteInfo info(false);
1741
1.94k
      done=info.read(zone);
1742
1.94k
      break;
1743
890
    }
1744
202
    case '8': {
1745
202
      StarWriterStruct::PrintData info;
1746
202
      done=info.read(zone);
1747
202
      break;
1748
890
    }
1749
6.29k
    case 'D': {
1750
6.29k
      StarWriterStruct::DatabaseName dbase;
1751
6.29k
      done=dbase.read(zone);
1752
6.29k
      break;
1753
890
    }
1754
1.79k
    case 'F':
1755
1.79k
      done=getFormatManager()->readSWFlyFrameList(zone, *this, m_textState->m_flyList);
1756
1.79k
      break;
1757
2.40k
    case 'J':
1758
2.40k
      done=readSWJobSetUp(zone);
1759
2.40k
      break;
1760
32
    case 'M': {
1761
32
      std::vector<StarWriterStruct::Macro> macroList;
1762
32
      done=StarWriterStruct::Macro::readList(zone, macroList);
1763
32
      break;
1764
890
    }
1765
39.7k
    case 'N':
1766
39.7k
      done=readSWContent(zone, m_textState->m_mainContent);
1767
39.7k
      break;
1768
1.25k
    case 'U': { // layout info, no code, ignored by LibreOffice
1769
1.25k
      StarLayout layout;
1770
1.25k
      done=layout.read(zone, *this);
1771
1.25k
      break;
1772
890
    }
1773
33
    case 'V': {
1774
33
      std::vector<std::vector<StarWriterStruct::Redline> > redlineListList;
1775
33
      done=StarWriterStruct::Redline::readListList(zone, redlineListList);
1776
33
      break;
1777
890
    }
1778
9.22k
    case 'Y':
1779
9.22k
      done=bool(fieldManager.readField(zone,'Y'));
1780
9.22k
      break;
1781
505
    case 'a': {
1782
505
      std::vector<StarWriterStruct::Bookmark> markList;
1783
505
      done=StarWriterStruct::Bookmark::readList(zone, markList);
1784
505
      break;
1785
890
    }
1786
4.69k
    case 'd': {
1787
4.69k
      StarWriterStruct::DocStats stats;
1788
4.69k
      done=stats.read(zone);
1789
4.69k
      break;
1790
890
    }
1791
1.88k
    case 'j': {
1792
1.88k
      StarWriterStruct::Dictionary dico;
1793
1.88k
      done=dico.read(zone);
1794
1.88k
      break;
1795
890
    }
1796
353
    case 'q':
1797
353
      done=getFormatManager()->readSWNumberFormatterList(zone);
1798
353
      break;
1799
516
    case 'u': {
1800
516
      std::vector<StarWriterStruct::TOX> toxList;
1801
516
      done=StarWriterStruct::TOX::readList(zone, toxList, *this);
1802
516
      break;
1803
890
    }
1804
650
    case 'y': {
1805
650
      std::vector<StarWriterStruct::TOX51> toxList;
1806
650
      done=StarWriterStruct::TOX51::readList(zone, toxList, *this);
1807
650
      break;
1808
890
    }
1809
35.6k
    default:
1810
35.6k
      break;
1811
126k
    }
1812
126k
    if (done)
1813
87.8k
      continue;
1814
1815
39.1k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1816
39.1k
    unsigned char type;
1817
39.1k
    if (!zone.openSWRecord(type)) {
1818
9.47k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1819
9.47k
      break;
1820
9.47k
    }
1821
29.6k
    libstoff::DebugStream f;
1822
29.6k
    f << "SWWriterDocument[" << type << "]:";
1823
29.6k
    long lastPos=zone.getRecordLastPosition();
1824
29.6k
    bool endZone=false;
1825
29.6k
    std::vector<uint32_t> string;
1826
29.6k
    switch (type) {
1827
1.11k
    case '$': // unknown, seems to store an object name
1828
1.11k
      f << "dollarZone,";
1829
1.11k
      if (input->tell()+7>lastPos) {
1830
937
        STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: zone seems to short\n"));
1831
937
        break;
1832
937
      }
1833
1.09k
      for (int i=0; i<5; ++i) { // f0=f1=1
1834
910
        auto val=int(input->readULong(1));
1835
910
        if (val) f << "f" << i << "=" << val << ",";
1836
910
      }
1837
182
      if (!zone.readString(string)) {
1838
44
        STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: can not read main string\n"));
1839
44
        f << "###string";
1840
44
        break;
1841
44
      }
1842
138
      else if (!string.empty())
1843
123
        f << libstoff::getString(string).cstr();
1844
138
      break;
1845
2.98k
    case '5': {
1846
      // sw_sw3misc.cxx InLineNumberInfo
1847
2.98k
      int fl=zone.openFlagZone();
1848
2.98k
      if (fl&0xf0) f << "fl=" << (fl>>4) << ",";
1849
2.98k
      f << "linenumberInfo=" << input->readULong(1) << ",";
1850
2.98k
      f << "nPos=" << input->readULong(1) << ",";
1851
2.98k
      f << "nChrIdx=" << input->readULong(2) << ",";
1852
2.98k
      f << "nPosFromLeft=" << input->readULong(2) << ",";
1853
2.98k
      f << "nCountBy=" << input->readULong(2) << ",";
1854
2.98k
      f << "nDividerCountBy=" << input->readULong(2) << ",";
1855
2.98k
      zone.closeFlagZone();
1856
2.98k
      if (!zone.readString(string)) {
1857
493
        STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: can not read sDivider string\n"));
1858
493
        f << "###sDivider";
1859
493
        break;
1860
493
      }
1861
2.48k
      else if (!string.empty())
1862
203
        f << libstoff::getString(string).cstr();
1863
2.48k
      break;
1864
2.98k
    }
1865
2.48k
    case '6':
1866
      // sw_sw3misc.cxx InDocDummies
1867
1.84k
      f << "docDummies,";
1868
1.84k
      f << "n1=" << input->readULong(4) << ",";
1869
1.84k
      f << "n2=" << input->readULong(4) << ",";
1870
1.84k
      f << "n3=" << input->readULong(1) << ",";
1871
1.84k
      f << "n4=" << input->readULong(1) << ",";
1872
5.40k
      for (int i=0; i<2; ++i) {
1873
3.65k
        if (!zone.readString(string)) {
1874
88
          STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: can not read a string\n"));
1875
88
          f << "###string";
1876
88
          break;
1877
88
        }
1878
3.56k
        else if (!string.empty())
1879
213
          f << (i==0 ? "sAutoMarkURL" : "s2") << "=" << libstoff::getString(string).cstr() << ",";
1880
3.65k
      }
1881
1.84k
      break;
1882
728
    case '7': { // config, ignored by LibreOffice, and find no code
1883
728
      f << "config,";
1884
728
      auto fl=int(zone.openFlagZone());
1885
728
      if (fl&0xf0) f << "fl=" << (fl>>4) << ",";
1886
728
      f << "f0=" << input->readULong(1) << ","; // 1
1887
4.36k
      for (int i=0; i<5; ++i) // e,1,5,1,5
1888
3.64k
        f << "f" << i+1 << "=" << input->readULong(2) << ",";
1889
728
      zone.closeFlagZone();
1890
728
      break;
1891
2.98k
    }
1892
5.00k
    case 'C': { // ignored by LibreOffice
1893
5.00k
      std::string comment("");
1894
101k
      while (lastPos && input->tell()<lastPos) comment+=char(input->readULong(1));
1895
5.00k
      f << "comment=" << comment << ",";
1896
5.00k
      break;
1897
2.98k
    }
1898
90
    case 'P': // password
1899
      // sw_sw3misc.cxx: InPasswd
1900
90
      f << "passwd,";
1901
90
      if (zone.isCompatibleWith(0x6)) {
1902
86
        f << "cType=" << input->readULong(1) << ",";
1903
86
        if (!zone.readString(string)) {
1904
24
          STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: can not read passwd string\n"));
1905
24
          f << "###passwd";
1906
24
        }
1907
62
        else
1908
62
          f << "cryptedPasswd=" << libstoff::getString(string).cstr() << ",";
1909
86
      }
1910
90
      break;
1911
1.13k
    case 'Z':
1912
1.13k
      endZone=true;
1913
1.13k
      break;
1914
16.7k
    default:
1915
16.7k
      STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: find unexpected type\n"));
1916
16.7k
      f << "###type,";
1917
29.6k
    }
1918
29.6k
    ascFile.addPos(pos);
1919
29.6k
    ascFile.addNote(f.str().c_str());
1920
29.6k
    zone.closeSWRecord(type, "SWWriterDocument");
1921
29.6k
    if (endZone)
1922
1.13k
      break;
1923
29.6k
  }
1924
10.6k
  if (!input->isEnd()) {
1925
9.52k
    STOFF_DEBUG_MSG(("StarObjectText::readWriterDocument: find extra data\n"));
1926
9.52k
    ascFile.addPos(input->tell());
1927
9.52k
    ascFile.addNote("SWWriterDocument:##extra");
1928
9.52k
  }
1929
10.6k
  return true;
1930
10.6k
}
1931
22.7k
catch (...)
1932
22.7k
{
1933
46
  return false;
1934
46
}
1935
////////////////////////////////////////////////////////////
1936
//
1937
// Low level
1938
//
1939
////////////////////////////////////////////////////////////
1940
1941
1942
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: