Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libstaroffice/src/lib/StarObjectModel.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 <set>
39
#include <sstream>
40
41
#include <librevenge/librevenge.h>
42
43
#include "STOFFFrameStyle.hxx"
44
#include "STOFFGraphicListener.hxx"
45
#include "STOFFListener.hxx"
46
#include "STOFFOLEParser.hxx"
47
#include "STOFFPageSpan.hxx"
48
49
#include "StarAttribute.hxx"
50
#include "StarItemPool.hxx"
51
#include "StarObject.hxx"
52
#include "StarObjectSmallGraphic.hxx"
53
#include "StarState.hxx"
54
#include "StarZone.hxx"
55
56
#include "StarObjectModel.hxx"
57
58
/** Internal: the structures of a StarObjectModel */
59
namespace StarObjectModelInternal
60
{
61
//! small function used to convert a list of uint8_t to a bool vector
62
static bool convertUint8ListToBoolList(std::vector<int> const &orig, std::vector<bool> &res)
63
16.9k
{
64
16.9k
  size_t n=orig.size();
65
16.9k
  res.resize(n*8);
66
558k
  for (size_t i=0, j=0; i<n; ++i) {
67
541k
    int val=orig[i];
68
4.87M
    for (int k=0, depl=0x80; k<8; depl>>=1, ++k)
69
4.33M
      res[j++]=(val&depl);
70
541k
  }
71
16.9k
  return true;
72
16.9k
}
73
////////////////////////////////////////
74
//! Internal: class used to store a layer and its data
75
class Layer
76
{
77
public:
78
  //! constructor
79
  Layer()
80
220k
    : m_name("")
81
220k
    , m_id(0)
82
220k
    , m_type(0)
83
220k
  {
84
220k
  }
85
  //! operator<<
86
  friend std::ostream &operator<<(std::ostream &o, Layer const &layer)
87
0
  {
88
0
    o << "id=" << layer.m_id << ",";
89
0
    if (!layer.m_name.empty()) o << layer.m_name.cstr() << ",";
90
0
    if (layer.m_type==0) o << "user,";
91
0
    return o;
92
0
  }
93
  //! the layer name
94
  librevenge::RVNGString m_name;
95
  //! the layer id
96
  int m_id;
97
  //! the layer type
98
  int m_type;
99
};
100
////////////////////////////////////////
101
//! Internal: class used to store a layer set and its data
102
class LayerSet
103
{
104
public:
105
  //! constructor
106
  LayerSet()
107
63.6k
    : m_name("")
108
63.6k
    , m_memberList()
109
63.6k
    , m_excludeList()
110
63.6k
  {
111
63.6k
  }
112
  //! operator<<
113
  friend std::ostream &operator<<(std::ostream &o, LayerSet const &layer)
114
0
  {
115
0
    if (!layer.m_name.empty()) o << layer.m_name.cstr() << ",";
116
0
    o << "members=[";
117
0
    for (size_t i=0; i<layer.m_memberList.size(); ++i) {
118
0
      if (layer.m_memberList[i]) o << i << ",";
119
0
    }
120
0
    o << "],";
121
0
    o << "excludes=[";
122
0
    for (size_t i=0; i<layer.m_excludeList.size(); ++i) {
123
0
      if (layer.m_excludeList[i]) o << i << ",";
124
0
    }
125
0
    o << "],";
126
0
    return o;
127
0
  }
128
  //! the layer name
129
  librevenge::RVNGString m_name;
130
  //! the list of member
131
  std::vector<bool> m_memberList;
132
  //! the list of exclude
133
  std::vector<bool> m_excludeList;
134
};
135
136
////////////////////////////////////////
137
//! Internal: class used to store a page and its data
138
class Page
139
{
140
public:
141
  ////////////////////////////////////////
142
  //! Internal: class used to store a page descriptor
143
  struct Descriptor {
144
    //! constructor
145
    Descriptor()
146
15.2k
      : m_masterId(1)
147
15.2k
      , m_layerList()
148
15.2k
    {
149
15.2k
    }
150
    //! operator<<
151
    friend std::ostream &operator<<(std::ostream &o, Descriptor const &desc)
152
0
    {
153
0
      o << "id[master]=" << desc.m_masterId << ",";
154
0
      o << "inVisLayer=[";
155
0
      for (size_t i=0; i<desc.m_layerList.size(); ++i) {
156
0
        if (!desc.m_layerList[i])
157
0
          o << i << ",";
158
0
      }
159
0
      o << "],";
160
0
      return o;
161
0
    }
162
    //! the page number
163
    int m_masterId;
164
    //! a list of layer
165
    std::vector<bool> m_layerList;
166
  };
167
  //! constructor
168
  Page()
169
61.3k
    : m_masterPage(false)
170
61.3k
    , m_name("")
171
61.3k
    , m_size(0,0)
172
61.3k
    , m_masterPageDescList()
173
61.3k
    , m_layer()
174
61.3k
    , m_layerSet()
175
61.3k
    , m_objectList()
176
61.3k
    , m_background()
177
61.3k
  {
178
245k
    for (int &border : m_borders) border=0;
179
61.3k
  }
180
  //! returns the master page id
181
  int getMasterPageId() const
182
18.2k
  {
183
18.2k
    if (m_masterPage || m_masterPageDescList.empty()) return -1;
184
15.0k
    return m_masterPageDescList[0].m_masterId;
185
18.2k
  }
186
  //! update pagespan properties
187
  void updatePageSpan(STOFFPageSpan &page, double relUnit) const
188
14.9k
  {
189
14.9k
    if (m_size[0]>0 && m_size[0]!=0x7fffffff)
190
14.2k
      page.m_propertiesList[0].insert("fo:page-width", relUnit*m_size[0], librevenge::RVNG_POINT);
191
14.9k
    if (m_size[1]>0 && m_size[1]!=0x7fffffff)
192
14.0k
      page.m_propertiesList[0].insert("fo:page-height", relUnit*m_size[1], librevenge::RVNG_POINT);
193
74.9k
    for (int i=0; i<4; ++i) {
194
59.9k
      if (m_borders[i]<0 || m_borders[i]==0x7fffffff) continue;
195
57.1k
      char const *wh[]= {"left", "top", "right", "bottom"};
196
57.1k
      page.m_propertiesList[0].insert((std::string("fo:margin-")+wh[i]).c_str(),
197
57.1k
                                      relUnit*m_borders[i], librevenge::RVNG_POINT);
198
57.1k
    }
199
14.9k
    if (m_background) {
200
1
      STOFF_DEBUG_MSG(("StarObjectModelInternal::Page::updatePageSpan: sorry sending background object is not implemented\n"));
201
1
    }
202
14.9k
  }
203
  //! operator<<
204
  friend std::ostream &operator<<(std::ostream &o, Page const &page)
205
0
  {
206
0
    if (page.m_masterPage) o << "master,";
207
0
    if (!page.m_name.empty()) o << "name=" << page.m_name.cstr() << ",";
208
0
    o << "sz=" << page.m_size << ",";
209
0
    o << "borders=[";
210
0
    for (int border : page.m_borders) o << border << ",";
211
0
    o << "],";
212
0
    if (!page.m_masterPageDescList.empty()) {
213
0
      o << "desc=[";
214
0
      for (auto const &desc : page.m_masterPageDescList)
215
0
        o << "[" << desc << "],";
216
0
      o << "],";
217
0
    }
218
0
    o << "layer=[" << page.m_layer << "],";
219
0
    o << "layerSet=[" << page.m_layerSet << "],";
220
0
    if (page.m_background) o << "hasBackground,";
221
0
#if 1
222
0
    for (auto &obj : page.m_objectList) {
223
0
      if (obj)
224
0
        o << "\n\t\t" << *obj;
225
0
    }
226
0
    o << "\n";
227
#else
228
    o << "num[object]=" << page.m_objectList.size() << ",";
229
#endif
230
0
    return o;
231
0
  }
232
  //! a flag to know if the page is a master page
233
  bool m_masterPage;
234
  //! the page name
235
  librevenge::RVNGString m_name;
236
  //! the page size
237
  STOFFVec2i m_size;
238
  //! the border size: left, up, right, bottom
239
  int m_borders[4];
240
  //! the list of master page descriptor
241
  std::vector<Descriptor> m_masterPageDescList;
242
  //! the layer
243
  Layer m_layer;
244
  //! the layer set
245
  LayerSet m_layerSet;
246
  //! the list of object
247
  std::vector<std::shared_ptr<StarObjectSmallGraphic> > m_objectList;
248
  //! the background object
249
  std::shared_ptr<StarObjectSmallGraphic> m_background;
250
};
251
252
////////////////////////////////////////
253
//! Internal: the state of a StarObjectModel
254
struct State {
255
  //! constructor
256
  State()
257
52.7k
    : m_previewMasterPage(-1)
258
52.7k
    , m_pageList()
259
52.7k
    , m_masterPageList()
260
52.7k
    , m_idToLayerMap()
261
52.7k
    , m_layerSetList()
262
52.7k
    , m_pageToSendList()
263
52.7k
    , m_masterPageToSendSet()
264
52.7k
    , m_idToObjectMap()
265
52.7k
  {
266
52.7k
  }
267
  //! small operator<< to print the content of the state
268
  friend std::ostream &operator<<(std::ostream &o, State const &state)
269
0
  {
270
0
    if (state.m_previewMasterPage>=0)
271
0
      o << "prev[masterPage]=" << state.m_previewMasterPage << ",";
272
0
    if (!state.m_pageList.empty()) {
273
0
      o << "pages=[\n";
274
0
      for (auto &page : state.m_pageList) {
275
0
        if (!page)
276
0
          continue;
277
0
        o << "\t" << *page << "\n";
278
0
      }
279
0
      o << "]\n";
280
0
    }
281
0
    if (!state.m_masterPageList.empty()) {
282
0
      o << "masterPages=[\n";
283
0
      for (auto &page : state.m_masterPageList) {
284
0
        if (!page)
285
0
          continue;
286
0
        o << "\t" << *page << "\n";
287
0
      }
288
0
      o << "]\n";
289
0
    }
290
0
    if (!state.m_idToLayerMap.empty()) {
291
0
      o << "layers=[";
292
0
      for (auto it : state.m_idToLayerMap)
293
0
        o << "[" << it.second << "],";
294
0
      o << "]\n";
295
0
    }
296
0
    if (!state.m_layerSetList.empty()) {
297
0
      o << "layerSets=[\n";
298
0
      for (auto const &layer : state.m_layerSetList)
299
0
        o << "\t" << layer << "\n";
300
0
      o << "]\n";
301
0
    }
302
0
    return o;
303
0
  }
304
305
  //! the default master page: -1 means not found, in general 1 in StarDrawDocument
306
  int m_previewMasterPage;
307
  /*
308
    in general: page0(master0), nothing
309
    after by pair:
310
       page 2*i+1(master 2*k+1): page content
311
       page 2*i+2(master 2*k+2): a page graphic+a text zone(double click to add note)
312
   */
313
  //! list of pages
314
  std::vector<std::shared_ptr<Page> > m_pageList;
315
  /*
316
    in general: master0 contains 4 small box associated with a page graphic 1,3,5,7
317
    after by pair:
318
        master 2*i+1: the content of the master page
319
        master 2*i+2: a title text+text: maybe default text
320
   */
321
  //! list of master pages
322
  std::vector<std::shared_ptr<Page> > m_masterPageList;
323
  //! a map layerId to layer
324
  std::map<int, Layer> m_idToLayerMap;
325
  //! the list of layer set
326
  std::vector<LayerSet> m_layerSetList;
327
  //! the list of page to send
328
  std::vector<int> m_pageToSendList;
329
  //! the list of master page to send
330
  std::set<int> m_masterPageToSendSet;
331
  //! a map objectId to object
332
  std::map<int, std::shared_ptr<StarObjectSmallGraphic> > m_idToObjectMap;
333
334
};
335
336
}
337
338
////////////////////////////////////////////////////////////
339
// constructor/destructor, ...
340
////////////////////////////////////////////////////////////
341
StarObjectModel::StarObjectModel(StarObject const &orig, bool duplicateState)
342
52.7k
  : StarObject(orig, duplicateState)
343
52.7k
  , m_modelState(new StarObjectModelInternal::State)
344
52.7k
{
345
52.7k
}
346
347
StarObjectModel::~StarObjectModel()
348
52.7k
{
349
52.7k
}
350
351
std::ostream &operator<<(std::ostream &o, StarObjectModel const &model)
352
0
{
353
0
  o << *model.m_modelState;
354
0
  return o;
355
0
}
356
357
////////////////////////////////////////////////////////////
358
// send data
359
////////////////////////////////////////////////////////////
360
bool StarObjectModel::updatePageSpans(std::vector<STOFFPageSpan> &pageSpan, int &number, bool usePage0) const
361
14.4k
{
362
14.4k
  m_modelState->m_pageToSendList.clear();
363
14.4k
  m_modelState->m_masterPageToSendSet.clear();
364
365
14.4k
  auto pool=const_cast<StarObjectModel *>(this)->findItemPool(StarItemPool::T_XOutdevPool, false);
366
14.4k
  double const relUnit=pool ? pool->getRelativeUnit() : 0.028346457;
367
14.4k
  pageSpan.clear();
368
14.4k
  if (usePage0) {
369
2.70k
    if (m_modelState->m_pageList.empty() || !m_modelState->m_pageList[0])
370
359
      return false;
371
2.34k
    STOFFPageSpan ps;
372
2.34k
    m_modelState->m_pageList[0]->updatePageSpan(ps, relUnit);
373
2.34k
    pageSpan.push_back(ps);
374
2.34k
    return true;
375
2.70k
  }
376
11.7k
  auto numMasterPage=int(m_modelState->m_masterPageList.size());
377
29.9k
  for (size_t i=0; i<m_modelState->m_pageList.size(); ++i) {
378
18.2k
    if (!m_modelState->m_pageList[i])
379
0
      continue;
380
18.2k
    auto const &page=*m_modelState->m_pageList[i];
381
18.2k
    int id=page.getMasterPageId();
382
18.2k
    if (id<=0 || (id&1)!=1) continue;
383
9.07k
    m_modelState->m_pageToSendList.push_back(int(i));
384
9.07k
    STOFFPageSpan ps;
385
9.07k
    page.updatePageSpan(ps, relUnit);
386
9.07k
    if (id<numMasterPage && m_modelState->m_masterPageList[size_t(id)]) {
387
4.65k
      m_modelState->m_masterPageToSendSet.insert(id);
388
4.65k
      librevenge::RVNGString masterName;
389
4.65k
      masterName.sprintf("Master%d", id);
390
4.65k
      ps.m_propertiesList[0].insert("librevenge:master-page-name", masterName);
391
4.65k
    }
392
9.07k
    pageSpan.push_back(ps);
393
9.07k
  }
394
11.7k
  number=int(m_modelState->m_pageToSendList.size());
395
11.7k
  return number!=0;
396
14.4k
}
397
398
void StarObjectModel::updateObjectIds(std::set<long> &unusedId)
399
3
{
400
3
  if (m_modelState->m_pageList.empty() || !m_modelState->m_pageList[0])
401
0
    return;
402
3
  int actId=0;
403
6
  for (auto &obj : m_modelState->m_pageList[0]->m_objectList) {
404
6
    while (unusedId.find(long(actId))!=unusedId.end())
405
0
      ++actId;
406
6
    if (obj)
407
6
      m_modelState->m_idToObjectMap[actId]=obj;
408
6
    ++actId;
409
6
  }
410
3
}
411
412
bool StarObjectModel::sendObject(int id, STOFFListenerPtr listener, StarState const &state)
413
6
{
414
6
  auto it=m_modelState->m_idToObjectMap.find(id);
415
6
  if (it==m_modelState->m_idToObjectMap.end() || !it->second) {
416
0
    STOFF_DEBUG_MSG(("StarObjectModel::sendObject: can not find object %d\n", id));
417
0
    return false;
418
0
  }
419
6
  return it->second->send(listener, state.m_frame, *this);
420
6
}
421
422
bool StarObjectModel::sendPages(STOFFListenerPtr listener)
423
11.6k
{
424
11.6k
  if (!listener) {
425
0
    STOFF_DEBUG_MSG(("StarObjectModel::sendPages: can not find the listener\n"));
426
0
    return false;
427
0
  }
428
11.6k
  bool first=true;
429
11.6k
  for (auto &page : m_modelState->m_pageToSendList) {
430
9.06k
    if (!first)
431
1.77k
      listener->insertBreak(STOFFListener::PageBreak);
432
7.28k
    else
433
7.28k
      first=false;
434
9.06k
    sendPage(page, listener, false);
435
9.06k
  }
436
11.6k
  return true;
437
11.6k
}
438
439
bool StarObjectModel::sendMasterPages(STOFFGraphicListenerPtr listener)
440
11.0k
{
441
11.0k
  if (!listener) {
442
0
    STOFF_DEBUG_MSG(("StarObjectModel::sendMasterPages: can not find the listener\n"));
443
0
    return false;
444
0
  }
445
11.0k
  auto pool=const_cast<StarObjectModel *>(this)->findItemPool(StarItemPool::T_XOutdevPool, false);
446
11.0k
  double const relUnit=pool ? pool->getRelativeUnit() : 0.028346457;
447
11.0k
  auto numMasters=int(m_modelState->m_masterPageList.size());
448
11.0k
  for (auto id : m_modelState->m_masterPageToSendSet) {
449
3.56k
    if (id<0 || id>=numMasters || !m_modelState->m_masterPageList[size_t(id)]) {
450
0
      STOFF_DEBUG_MSG(("StarObjectModel::sendMasterPages: can not find master page %d\n", id));
451
0
      continue;
452
0
    }
453
3.56k
    auto const &page=*m_modelState->m_masterPageList[size_t(id)];
454
3.56k
    STOFFPageSpan ps;
455
3.56k
    page.updatePageSpan(ps, relUnit);
456
3.56k
    librevenge::RVNGString masterName;
457
3.56k
    masterName.sprintf("Master%d", id);
458
3.56k
    ps.m_propertiesList[0].insert("librevenge:master-page-name", masterName);
459
3.56k
    listener->openMasterPage(ps);
460
3.56k
    sendPage(id, listener, true);
461
3.56k
    listener->closeMasterPage();
462
3.56k
  }
463
11.0k
  return true;
464
11.0k
}
465
466
bool StarObjectModel::sendPage(int pageId, STOFFListenerPtr listener, bool masterPage)
467
27.5k
{
468
27.5k
  if (!listener) {
469
0
    STOFF_DEBUG_MSG(("StarObjectModel::sendPage: can not find the listener\n"));
470
0
    return false;
471
0
  }
472
27.5k
  std::vector<std::shared_ptr<StarObjectModelInternal::Page> > const &pageList=
473
27.5k
    masterPage ? m_modelState->m_masterPageList : m_modelState->m_pageList;
474
27.5k
  if (pageId<0) {
475
0
    STOFF_DEBUG_MSG(("StarObjectModel::sendPage: can not find page %d\n", pageId));
476
0
    return false;
477
0
  }
478
27.5k
  if (pageId>=int(pageList.size()) || !pageList[size_t(pageId)])
479
1.37k
    return false;
480
26.1k
  StarObjectModelInternal::Page &page=*pageList[size_t(pageId)];
481
26.1k
  STOFFFrameStyle frame;
482
26.1k
  frame.m_position.m_anchorTo=STOFFPosition::Page;
483
26.1k
  if (!masterPage) frame.m_position.m_propertyList.insert("text:anchor-page-number", pageId+1);
484
80.6k
  for (auto pag : page.m_objectList) {
485
80.6k
    if (pag)
486
80.6k
      pag->send(listener, frame, *this, masterPage);
487
80.6k
  }
488
26.1k
  return true;
489
27.5k
}
490
491
////////////////////////////////////////////////////////////
492
// the parser
493
////////////////////////////////////////////////////////////
494
bool StarObjectModel::read(StarZone &zone)
495
52.7k
{
496
52.7k
  STOFFInputStreamPtr input=zone.input();
497
  // first check magic
498
52.7k
  std::string magic("");
499
52.7k
  long pos=input->tell();
500
263k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
501
52.7k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
502
52.7k
  if (magic!="DrMd") return false;
503
504
19.2k
  libstoff::DebugFile &ascFile=zone.ascii();
505
19.2k
  libstoff::DebugStream f;
506
19.2k
  f << "Entries(SdrModel)[" << zone.getRecordLevel() << "]:";
507
  // svdmodel.cxx operator>>(..., SdrModel &)
508
19.2k
  if (!zone.openSDRHeader(magic)) {
509
355
    input->seek(pos, librevenge::RVNG_SEEK_SET);
510
355
    STOFF_DEBUG_MSG(("StarObjectModel::read: can not open the SDR Header\n"));
511
355
    f << "###";
512
355
    ascFile.addPos(pos);
513
355
    ascFile.addNote(f.str().c_str());
514
355
    return false;
515
355
  }
516
18.9k
  int version=zone.getHeaderVersion();
517
18.9k
  f << magic << ",nVers=" << version << ",";
518
519
18.9k
  if (magic!="DrMd" || version>17) {
520
42
    STOFF_DEBUG_MSG(("StarObjectModel::read: unexpected magic data\n"));
521
42
    f << "###";
522
42
    ascFile.addPos(pos);
523
42
    ascFile.addNote(f.str().c_str());
524
42
    return false;
525
42
  }
526
18.8k
  ascFile.addPos(pos);
527
18.8k
  ascFile.addNote(f.str().c_str());
528
18.8k
  pos=input->tell();
529
530
18.8k
  f.str("");
531
18.8k
  f << "SdrModelA[" << zone.getRecordLevel() << "]:";
532
  // SdrModel::ReadData
533
18.8k
  if (!zone.openRecord()) { // SdrModelA1
534
280
    STOFF_DEBUG_MSG(("StarObjectModel::read: can not open downCompat\n"));
535
280
    f << "###";
536
280
    ascFile.addPos(pos);
537
280
    ascFile.addNote(f.str().c_str());
538
280
    zone.closeSDRHeader("SdrModel");
539
280
    return true;
540
280
  }
541
542
18.6k
  ascFile.addPos(pos);
543
18.6k
  ascFile.addNote(f.str().c_str());
544
18.6k
  pos=input->tell();
545
18.6k
  f.str("");
546
18.6k
  f << "SdrModelA[" << zone.getRecordLevel() << "]:";
547
18.6k
  bool ok=true;
548
18.6k
  if (version>=11) {
549
18.1k
    magic="";
550
90.8k
    for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
551
18.1k
    f << "joeM";
552
18.1k
    if (magic!="JoeM" || !zone.openRecord()) { // SdrModelA2
553
95
      STOFF_DEBUG_MSG(("StarObjectModel::read: unexpected magic2 data\n"));
554
95
      f << "###magic" << magic;
555
95
      ascFile.addPos(pos);
556
95
      ascFile.addNote(f.str().c_str());
557
95
      zone.closeRecord("SdrModelA1");
558
95
      zone.closeSDRHeader("SdrModel");
559
95
      return true;
560
95
    }
561
18.0k
    ascFile.addPos(pos);
562
18.0k
    ascFile.addNote(f.str().c_str());
563
564
18.0k
    pos=input->tell();
565
18.0k
    f.str("");
566
18.0k
    f << "SdrModelInfo[" << zone.getRecordLevel() << "]:";
567
18.0k
    if (!zone.openRecord()) { // SdrModelInfo
568
1.52k
      STOFF_DEBUG_MSG(("StarObjectModel::read: can not read model info\n"));
569
1.52k
      f << "###";
570
1.52k
      ok=false;
571
1.52k
    }
572
16.5k
    else {
573
      /* operator>>(..., SdrModelInfo&)
574
575
         normally, this document also contains a SfxDocumentInfo, so it is safe to ignore them
576
       */
577
16.5k
      uint32_t date, time;
578
16.5k
      uint8_t enc;
579
16.5k
      *input >> date >> time >> enc;
580
16.5k
      f << "date=" << date << ",time=" << time << ",encoding=" << int(enc) << ",";
581
16.5k
      input->seek(3, librevenge::RVNG_SEEK_CUR); // creationGUI, creationCPU, creationSys
582
16.5k
      *input >> date >> time >> enc;
583
16.5k
      f << "modDate=" << date << ", modTime=" << time << ",encoding[mod]=" << int(enc) << ",";
584
16.5k
      input->seek(3, librevenge::RVNG_SEEK_CUR); // writeGUI, writeCPU, writeSys
585
16.5k
      *input >> date >> time >> enc;
586
16.5k
      f << "lastReadDate=" << date << ", lastReadTime=" << time << ",encoding[lastRead]=" << int(enc) << ",";
587
16.5k
      input->seek(3, librevenge::RVNG_SEEK_CUR); // lastReadGUI, lastReadCPU, lastReadSys
588
16.5k
      *input >> date >> time;
589
16.5k
      f << "lastPrintDate=" << date << ", lastPrintTime=" << time << ",";
590
16.5k
      ascFile.addPos(pos);
591
16.5k
      ascFile.addNote(f.str().c_str());
592
593
16.5k
      zone.closeRecord("SdrModelInfo");
594
16.5k
      pos=input->tell();
595
16.5k
      f.str("");
596
16.5k
      f << "SdrModelStats[" << zone.getRecordLevel() << "]:";
597
16.5k
      if (!zone.openRecord()) {
598
4.68k
        STOFF_DEBUG_MSG(("StarObjectModel::read: can not read model statistic\n"));
599
4.68k
        f << "###";
600
4.68k
        ok=false;
601
4.68k
      }
602
11.8k
      else {
603
11.8k
        zone.closeRecord("SdrModelStat");
604
11.8k
        ascFile.addPos(pos);
605
11.8k
        ascFile.addNote(f.str().c_str());
606
607
11.8k
        pos=input->tell();
608
11.8k
        f.str("");
609
11.8k
        f << "SdrModelFormatCompat[" << zone.getRecordLevel() << "]:";
610
11.8k
      }
611
16.5k
    }
612
18.0k
    if (ok&&!zone.openRecord()) {
613
508
      STOFF_DEBUG_MSG(("StarObjectModel::read: can not read model format compat\n"));
614
508
      f << "###";
615
508
      ok=false;
616
508
    }
617
17.5k
    else if (ok) {
618
11.3k
      if (input->tell()+6<=zone.getRecordLastPosition()) {
619
1.62k
        int16_t nTmp; // find 0
620
1.62k
        *input >> nTmp;
621
1.62k
        if (nTmp) f << "unk=" << nTmp << ",";
622
1.62k
      }
623
11.3k
      if (input->tell()+4<=zone.getRecordLastPosition()) {
624
11.3k
        auto compressedMode=int(input->readULong(2));
625
11.3k
        if (compressedMode) // checkme: find 0 or 16-17, do not seems to cause problem
626
991
          f << "#streamCompressed=" << compressedMode << ",";
627
11.3k
        f << "nStreamNumberFormat=" << input->readULong(2) << ",";
628
11.3k
      }
629
11.3k
      zone.closeRecord("SdrModelFormatCompat");
630
11.3k
    }
631
632
18.0k
    ascFile.addPos(pos);
633
18.0k
    ascFile.addNote(f.str().c_str());
634
18.0k
    pos=input->tell();
635
18.0k
    f.str("");
636
18.0k
    f << "SdrModelA[" << zone.getRecordLevel() << "]-data:";
637
18.0k
  }
638
18.5k
  if (ok) {
639
11.8k
    int32_t nNum, nDen;
640
11.8k
    uint16_t nTmp;
641
11.8k
    uint8_t nTmp8;
642
11.8k
    *input>> nNum >> nDen >> nTmp;
643
11.8k
    f << "objectUnit=" << nNum << "/" << nDen << ",";
644
11.8k
    if (nTmp) f << "eObjUnit=" << nTmp << ",";
645
11.8k
    input->seek(2, librevenge::RVNG_SEEK_CUR); // collapsed?
646
11.8k
    *input>>nTmp8;
647
11.8k
    if (nTmp8==1) f << "pageNotValid,";
648
11.8k
    input->seek(1, librevenge::RVNG_SEEK_CUR); // dummy
649
650
11.8k
    if (version<1) {
651
14
      STOFF_DEBUG_MSG(("StarObjectModel::read: reading model format for version 0 is not implemented\n"));
652
14
      f << "###version0";
653
14
      ok=false;
654
14
    }
655
11.7k
    else {
656
11.7k
      if (version<11) {
657
426
        auto charSet=int(input->readLong(2));
658
426
        if (StarEncoding::getEncodingForId(charSet)!=StarEncoding::E_DONTKNOW)
659
426
          zone.setEncoding(StarEncoding::getEncodingForId(charSet));
660
0
        else
661
0
          f << "###nCharSet=" << charSet << ",";
662
426
      }
663
11.7k
      std::vector<uint32_t> string;
664
74.5k
      for (int i=0; i<6; ++i) {
665
64.9k
        if (!zone.readString(string)) {
666
2.13k
          STOFF_DEBUG_MSG(("StarObjectModel::read: can not read a string\n"));
667
2.13k
          f << "###string";
668
2.13k
          ok=false;
669
2.13k
          break;
670
2.13k
        }
671
62.8k
        if (string.empty()) continue;
672
2.35k
        static char const* const wh[]= {"cTableName", "dashName", "lineEndName", "hashName", "gradientName", "bitmapName"};
673
2.35k
        f << wh[i] << "=" << libstoff::getString(string).cstr() << ",";
674
2.35k
      }
675
11.7k
    }
676
11.8k
  }
677
18.5k
  if (ok && version>=12 && input->tell()<zone.getRecordLastPosition()) {
678
4.91k
    int32_t nNum, nDen;
679
4.91k
    uint16_t nTmp;
680
4.91k
    *input>> nNum >> nDen >> nTmp;
681
4.91k
    f << "UIUnit=" << nNum << "/" << nDen << ",";
682
4.91k
    if (nTmp) f << "eUIUnit=" << nTmp << ",";
683
4.91k
  }
684
18.5k
  if (ok && version>=13 && input->tell()<zone.getRecordLastPosition()) {
685
2.93k
    int32_t nNum1, nNum2;
686
2.93k
    *input>> nNum1 >> nNum2;
687
2.93k
    if (nNum1) f << "nDefTextHgt=" << nNum1 << ",";
688
2.93k
    if (nNum2) f << "nDefTab=" << nNum2 << ",";
689
2.93k
  }
690
18.5k
  if (ok && version>=14 && input->tell()<zone.getRecordLastPosition()) {
691
2.92k
    uint16_t pNum;
692
2.92k
    *input>> pNum;
693
2.92k
    if (pNum!=0xFFFF) {
694
2.26k
      m_modelState->m_previewMasterPage=int(pNum);
695
2.26k
      f << "nStartPageNum=" << pNum << ",";
696
2.26k
    }
697
2.92k
  }
698
18.5k
  ascFile.addPos(pos);
699
18.5k
  ascFile.addNote(f.str().c_str());
700
18.5k
  if (version>=11) {
701
18.0k
    zone.closeRecord("SdrModelA2");
702
18.0k
    ok=true;
703
18.0k
  }
704
146k
  while (ok) {
705
146k
    pos=input->tell();
706
146k
    if (pos+4>zone.getRecordLastPosition())
707
7.26k
      break;
708
138k
    magic="";
709
694k
    for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
710
138k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
711
138k
    if (magic=="DrLy") {
712
54.7k
      StarObjectModelInternal::Layer layer;
713
54.7k
      if (readSdrLayer(zone, layer)) {
714
54.6k
        if (m_modelState->m_idToLayerMap.find(layer.m_id)!=m_modelState->m_idToLayerMap.end()) {
715
6.46k
          STOFF_DEBUG_MSG(("StarObjectModel::read: layer %d already exists\n", layer.m_id));
716
6.46k
        }
717
48.1k
        else
718
48.1k
          m_modelState->m_idToLayerMap[layer.m_id]=layer;
719
54.6k
        continue;
720
54.6k
      }
721
54.7k
    }
722
84.2k
    if (magic=="DrLS") {
723
1.01k
      StarObjectModelInternal::LayerSet layers;
724
1.01k
      if (readSdrLayerSet(zone, layers)) {
725
972
        m_modelState->m_layerSetList.push_back(layers);
726
972
        continue;
727
972
      }
728
1.01k
    }
729
83.2k
    if ((magic=="DrPg" || magic=="DrMP")) {
730
62.9k
      auto page=readSdrPage(zone);
731
62.9k
      if (page) {
732
51.5k
        if (magic=="DrPg")
733
32.1k
          m_modelState->m_pageList.push_back(page);
734
19.4k
        else
735
19.4k
          m_modelState->m_masterPageList.push_back(page);
736
51.5k
        continue;
737
51.5k
      }
738
62.9k
    }
739
740
31.6k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
741
31.6k
    if (!zone.openSDRHeader(magic)) {
742
10.8k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
743
10.8k
      break;
744
10.8k
    }
745
20.8k
    f.str("");
746
20.8k
    f << "SdrModel[" << magic << "-" << zone.getRecordLevel() << "]:";
747
20.8k
    if (magic!="DrXX") {
748
13.9k
      STOFF_DEBUG_MSG(("StarObjectModel::read: find unexpected child\n"));
749
13.9k
      f << "###type";
750
13.9k
      input->seek(zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
751
13.9k
    }
752
20.8k
    ascFile.addPos(pos);
753
20.8k
    ascFile.addNote(f.str().c_str());
754
20.8k
    zone.closeSDRHeader("SdrModel");
755
20.8k
  }
756
757
18.5k
  zone.closeRecord("SdrModelA1");
758
  // in DrawingLayer, find also 0500000001 and 060000000[01]00
759
18.5k
  pos=input->tell();
760
18.5k
  if (pos+4<=zone.getRecordLastPosition()) {
761
4.45k
    auto sz=long(input->readULong(4));
762
4.45k
    if (pos+sz==zone.getRecordLastPosition()) {
763
1.71k
      ascFile.addPos(pos);
764
1.71k
      ascFile.addNote("SdrModel:#extra");
765
1.71k
      input->seek(zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
766
1.71k
    }
767
2.74k
    else
768
2.74k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
769
4.45k
  }
770
18.5k
  zone.closeSDRHeader("SdrModel");
771
18.5k
  return true;
772
18.6k
}
773
774
bool StarObjectModel::readSdrLayer(StarZone &zone, StarObjectModelInternal::Layer &layer)
775
55.8k
{
776
55.8k
  layer=StarObjectModelInternal::Layer();
777
55.8k
  STOFFInputStreamPtr input=zone.input();
778
  // first check magic
779
55.8k
  std::string magic("");
780
55.8k
  long pos=input->tell();
781
279k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
782
55.8k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
783
55.8k
  if (magic!="DrLy") return false;
784
785
55.8k
  libstoff::DebugFile &ascFile=zone.ascii();
786
55.8k
  libstoff::DebugStream f;
787
55.8k
  f << "Entries(SdrLayerDef)[" << zone.getRecordLevel() << "]:";
788
  // svdlayer.cxx operator>>(..., SdrLayer &)
789
55.8k
  if (!zone.openSDRHeader(magic)) {
790
245
    input->seek(pos, librevenge::RVNG_SEEK_SET);
791
245
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayer: can not open the SDR Header\n"));
792
245
    f << "###";
793
245
    ascFile.addPos(pos);
794
245
    ascFile.addNote(f.str().c_str());
795
245
    return false;
796
245
  }
797
55.5k
  int version=zone.getHeaderVersion();
798
55.5k
  f << magic << ",nVers=" << version << ",";
799
800
55.5k
  if (magic!="DrLy") {
801
0
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayer: unexpected magic data\n"));
802
0
    f << "###";
803
0
    ascFile.addPos(pos);
804
0
    ascFile.addNote(f.str().c_str());
805
0
    return false;
806
0
  }
807
55.5k
  layer.m_id=int(input->readULong(1));
808
55.5k
  std::vector<uint32_t> string;
809
55.5k
  if (!zone.readString(string)) {
810
2.41k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayer: can not read a string\n"));
811
2.41k
    f << "###string";
812
2.41k
    ascFile.addPos(pos);
813
2.41k
    ascFile.addNote(f.str().c_str());
814
2.41k
    zone.closeSDRHeader("SdrLayerDef");
815
2.41k
    return true;
816
2.41k
  }
817
53.1k
  layer.m_name=libstoff::getString(string);
818
53.1k
  if (version>=1) layer.m_type=int(input->readULong(2));
819
53.1k
  f << layer;
820
53.1k
  ascFile.addPos(pos);
821
53.1k
  ascFile.addNote(f.str().c_str());
822
53.1k
  zone.closeSDRHeader("SdrLayerDef");
823
53.1k
  return true;
824
55.5k
}
825
826
bool StarObjectModel::readSdrLayerSet(StarZone &zone, StarObjectModelInternal::LayerSet &layers)
827
1.27k
{
828
1.27k
  layers=StarObjectModelInternal::LayerSet();
829
1.27k
  STOFFInputStreamPtr input=zone.input();
830
  // first check magic
831
1.27k
  std::string magic("");
832
1.27k
  long pos=input->tell();
833
6.36k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
834
1.27k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
835
1.27k
  if (magic!="DrLS") return false;
836
837
1.27k
  libstoff::DebugFile &ascFile=zone.ascii();
838
1.27k
  libstoff::DebugStream f;
839
1.27k
  f << "Entries(SdrLayerSet)[" << zone.getRecordLevel() << "]:";
840
  // svdlayer.cxx operator>>(..., SdrLayerSet &)
841
1.27k
  if (!zone.openSDRHeader(magic)) {
842
164
    input->seek(pos, librevenge::RVNG_SEEK_SET);
843
164
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayerSet: can not open the SDR Header\n"));
844
164
    f << "###";
845
164
    ascFile.addPos(pos);
846
164
    ascFile.addNote(f.str().c_str());
847
164
    return false;
848
164
  }
849
1.10k
  int version=zone.getHeaderVersion();
850
1.10k
  f << magic << ",nVers=" << version << ",";
851
852
1.10k
  if (magic!="DrLS") {
853
0
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayerSet: unexpected magic data\n"));
854
0
    f << "###";
855
0
    ascFile.addPos(pos);
856
0
    ascFile.addNote(f.str().c_str());
857
0
    return false;
858
0
  }
859
3.32k
  for (int i=0; i<2; ++i) {
860
2.21k
    std::vector<int> layerList;
861
73.1k
    for (int j=0; j<32; ++j) layerList.push_back(int(input->readULong(1)));
862
2.21k
    StarObjectModelInternal::convertUint8ListToBoolList(layerList, i==0 ? layers.m_memberList : layers.m_excludeList);
863
2.21k
  }
864
1.10k
  std::vector<uint32_t> string;
865
1.10k
  if (!zone.readString(string)) {
866
391
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrLayerSet: can not read a string\n"));
867
391
    f << layers << "###string";
868
391
    ascFile.addPos(pos);
869
391
    ascFile.addNote(f.str().c_str());
870
391
    zone.closeSDRHeader("SdrLayerSet");
871
391
    return true;
872
391
  }
873
718
  layers.m_name=libstoff::getString(string).cstr();
874
718
  f << layers;
875
718
  ascFile.addPos(pos);
876
718
  ascFile.addNote(f.str().c_str());
877
718
  zone.closeSDRHeader("SdrLayerSet");
878
718
  return true;
879
1.10k
}
880
881
std::shared_ptr<StarObjectModelInternal::Page> StarObjectModel::readSdrPage(StarZone &zone)
882
62.9k
{
883
62.9k
  STOFFInputStreamPtr input=zone.input();
884
  // first check magic
885
62.9k
  std::string magic("");
886
62.9k
  long pos=input->tell();
887
314k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
888
62.9k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
889
62.9k
  if (magic!="DrPg" && magic!="DrMP") return std::shared_ptr<StarObjectModelInternal::Page>();
890
891
  // svdpage.cxx operator>>
892
62.9k
  libstoff::DebugFile &ascFile=zone.ascii();
893
62.9k
  libstoff::DebugStream f;
894
62.9k
  f << "Entries(SdrPageDef)[" << zone.getRecordLevel() << "]:";
895
62.9k
  if (magic=="DrMP") f << "master,";
896
62.9k
  if (!zone.openSDRHeader(magic)) {
897
1.58k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
898
1.58k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: can not open the SDR Header\n"));
899
1.58k
    f << "###";
900
1.58k
    ascFile.addPos(pos);
901
1.58k
    ascFile.addNote(f.str().c_str());
902
1.58k
    return std::shared_ptr<StarObjectModelInternal::Page>();
903
1.58k
  }
904
61.3k
  int version=zone.getHeaderVersion();
905
61.3k
  f << magic << ",nVers=" << version << ",";
906
907
61.3k
  if (magic!="DrPg" && magic!="DrMP") {
908
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
909
0
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: unexpected magic data\n"));
910
0
    f << "###";
911
0
    ascFile.addPos(pos);
912
0
    ascFile.addNote(f.str().c_str());
913
0
    return std::shared_ptr<StarObjectModelInternal::Page>();
914
0
  }
915
61.3k
  ascFile.addPos(pos);
916
61.3k
  ascFile.addNote(f.str().c_str());
917
61.3k
  pos=input->tell();
918
919
61.3k
  std::shared_ptr<StarObjectModelInternal::Page> page(new StarObjectModelInternal::Page);
920
61.3k
  page->m_masterPage=magic=="DrMP";
921
61.3k
  f.str("");
922
61.3k
  f << "SdrPageDefA[" << zone.getRecordLevel() << "]:";
923
  // svdpage.cxx SdrPage::ReadData
924
61.3k
  bool hasExtraData=false;
925
117k
  for (int tr=0; tr<2; ++tr) {
926
    /* sometimes there is one or two block which appears before the
927
       SdrPage::ReadData data, so try to find them*/
928
117k
    long lastPos=zone.getRecordLastPosition();
929
117k
    if (!zone.openRecord()) { // SdrPageDefA1
930
6.46k
      STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: can not open downCompat\n"));
931
6.46k
      f << "###";
932
6.46k
      ascFile.addPos(pos);
933
6.46k
      ascFile.addNote(f.str().c_str());
934
6.46k
      zone.closeSDRHeader("SdrPageDef");
935
6.46k
      return std::shared_ptr<StarObjectModelInternal::Page>();
936
6.46k
    }
937
110k
    if (tr==1 || zone.getRecordLastPosition()==lastPos)
938
54.8k
      break;
939
    // unsure, how we can have some dim and pool here but seems frequent in DrawingLayer
940
55.6k
    uint16_t n;
941
55.6k
    *input >> n;
942
55.6k
    bool ok=false;
943
55.6k
    if (n>1) {
944
2.29k
      STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: bad version\n"));
945
2.29k
      f << "###n=" << n << ",";
946
2.29k
      ok=false;
947
2.29k
    }
948
53.4k
    else
949
53.4k
      hasExtraData=true;
950
55.6k
    if (n==1 && input->tell()+8<=zone.getRecordLastPosition())  {
951
17.5k
      f << "dim=[";
952
87.9k
      for (int i=0; i<4; ++i) f << input->readLong(2) << ((i%2) ? "," : "x");
953
17.5k
      f << "],";
954
17.5k
      *input >> n;
955
17.5k
      ok=true;
956
17.5k
    }
957
55.6k
    if (ok && n>1 && input->tell()+2<=zone.getRecordLastPosition()) {
958
583
      STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: bad version2\n"));
959
583
      f << "###n2=" << n << ",";
960
583
      ok=false;
961
583
    }
962
55.6k
    if (ok && n==1) {
963
16.3k
      long actPos=input->tell();
964
16.3k
      auto pool=getNewItemPool(StarItemPool::T_VCControlPool);
965
16.3k
      if (!pool || !pool->read(zone))
966
3.13k
        input->seek(actPos, librevenge::RVNG_SEEK_SET);
967
16.3k
    }
968
55.6k
    ascFile.addPos(pos);
969
55.6k
    ascFile.addNote(f.str().c_str());
970
971
55.6k
    zone.closeRecord("SdrPageDef");
972
55.6k
    pos=input->tell();
973
55.6k
    f.str("");
974
55.6k
    f << "SdrPageDefA[" << zone.getRecordLevel() << "]:";
975
55.6k
  }
976
54.8k
  ascFile.addPos(pos);
977
54.8k
  ascFile.addNote(f.str().c_str());
978
54.8k
  pos=input->tell();
979
54.8k
  f.str("");
980
54.8k
  f << "SdrPageDefA[" << zone.getRecordLevel() << "]:";
981
54.8k
  if (version>=11) {
982
54.0k
    magic="";
983
270k
    for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
984
54.0k
    f << "joeM";
985
54.0k
    if (magic!="JoeM" || !zone.openRecord()) { // SdrPageDefA2
986
3.27k
      STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: unexpected magic2 data\n"));
987
3.27k
      f << "###magic" << magic;
988
3.27k
      ascFile.addPos(pos);
989
3.27k
      ascFile.addNote(f.str().c_str());
990
3.27k
      zone.closeRecord("SdrPageDefA1");
991
3.27k
      zone.closeSDRHeader("SdrPageDef");
992
3.27k
      return std::shared_ptr<StarObjectModelInternal::Page>();
993
3.27k
    }
994
50.8k
    ascFile.addPos(pos);
995
50.8k
    ascFile.addNote(f.str().c_str());
996
997
50.8k
    pos=input->tell();
998
50.8k
    f.str("");
999
50.8k
    f << "SdrPageDefData[" << zone.getRecordLevel() << "]:";
1000
50.8k
  }
1001
51.5k
  int32_t nWdt, nHgt;
1002
51.5k
  int32_t borders[4];
1003
51.5k
  uint16_t n;
1004
51.5k
  *input >> nWdt >> nHgt >> borders[0] >> borders[1] >> borders[2] >> borders[3] >> n;
1005
51.5k
  f << "dim=" << nWdt << "x" << nHgt << ",";
1006
51.5k
  f << "border=[" << borders[0] << "x" << borders[1] << "-" << borders[2] << "x" << borders[3] << "],";
1007
51.5k
  page->m_size=STOFFVec2i(int(nWdt), int(nHgt));
1008
257k
  for (int i=0; i<4; ++i) page->m_borders[i]=int(borders[i]);
1009
51.5k
  if (n) f << "n=" << n << ","; // link to page name?
1010
51.5k
  ascFile.addPos(pos);
1011
51.5k
  ascFile.addNote(f.str().c_str());
1012
51.5k
  if (version>=11)
1013
50.8k
    zone.closeRecord("SdrPageDefData");
1014
1015
51.5k
  long lastPos=zone.getRecordLastPosition();
1016
51.5k
  bool ok=true;
1017
99.1k
  while (ok) {
1018
99.1k
    pos=input->tell();
1019
99.1k
    if (pos+4>lastPos)
1020
283
      break;
1021
98.8k
    magic="";
1022
494k
    for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
1023
98.8k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1024
98.8k
    if (magic=="DrLy" && readSdrLayer(zone, page->m_layer)) continue;
1025
97.8k
    if (magic=="DrLS" && readSdrLayerSet(zone, page->m_layerSet)) continue;
1026
97.7k
    if (magic=="DrMP" && readSdrMPageDesc(zone, *page)) continue;
1027
97.7k
    if (magic=="DrML" && readSdrMPageDescList(zone, *page)) continue;
1028
51.3k
    break;
1029
97.7k
  }
1030
51.5k
  if (ok && version==0) {
1031
739
    pos=input->tell();
1032
739
    f.str("");
1033
739
    f << "SdrPageDef[masterPage]:";
1034
739
    *input >> n;
1035
739
    if (pos+2+2*n>lastPos) {
1036
197
      STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: n is bad\n"));
1037
197
      f << "###n=" << n << ",";
1038
197
      ok=false;
1039
197
    }
1040
542
    else {
1041
542
      f << "pages=[";
1042
542
      StarObjectModelInternal::Page::Descriptor desc;
1043
31.6k
      for (int i=0; i<int(n); ++i) {
1044
31.1k
        auto id=int(input->readULong(2));
1045
31.1k
        f << id << ",";
1046
31.1k
        desc.m_masterId=id;
1047
31.1k
        page->m_masterPageDescList.push_back(desc);
1048
31.1k
      }
1049
542
      f << "],";
1050
542
    }
1051
739
    ascFile.addPos(pos);
1052
739
    ascFile.addNote(f.str().c_str());
1053
739
  }
1054
  // SdrObjList::Load
1055
168k
  while (ok) {
1056
167k
    pos=input->tell();
1057
167k
    if (pos+4>lastPos)
1058
454
      break;
1059
167k
    std::shared_ptr<StarObjectSmallGraphic> smallGraphic(new StarObjectSmallGraphic(*this, true));
1060
167k
    if (smallGraphic->readSdrObject(zone)) {
1061
116k
      page->m_objectList.push_back(smallGraphic);
1062
116k
      continue;
1063
116k
    }
1064
1065
50.9k
    magic="";
1066
254k
    for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
1067
50.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1068
50.9k
    if (magic=="DrXX" && zone.openSDRHeader(magic)) {
1069
27.4k
      f.str("");
1070
27.4k
      f << "SdrPageDef[DrXX-" << zone.getRecordLevel() << "]:";
1071
27.4k
      ascFile.addPos(pos);
1072
27.4k
      ascFile.addNote(f.str().c_str());
1073
27.4k
      zone.closeSDRHeader("SdrPageDef");
1074
27.4k
      break;
1075
27.4k
    }
1076
23.4k
    ok=false;
1077
23.4k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: can not find end object zone\n"));
1078
23.4k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1079
23.4k
    break;
1080
50.9k
  }
1081
51.5k
  if (ok && version>=16) {
1082
10.3k
    pos=input->tell();
1083
10.3k
    f.str("");
1084
10.3k
    f << "SdrPageDef[background-" << zone.getRecordLevel() << "]:";
1085
10.3k
    bool background;
1086
10.3k
    *input>>background;
1087
10.3k
    ascFile.addPos(pos);
1088
10.3k
    ascFile.addNote(f.str().c_str());
1089
1090
10.3k
    if (background) {
1091
435
      std::shared_ptr<StarObjectSmallGraphic> smallGraphic(new StarObjectSmallGraphic(*this, true));
1092
435
      if (smallGraphic->readSdrObject(zone))
1093
25
        page->m_background=smallGraphic;
1094
410
      else {
1095
410
        STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: can not find backgroound object\n"));
1096
410
        input->seek(pos, librevenge::RVNG_SEEK_SET);
1097
410
        ok=false;
1098
410
      }
1099
435
    }
1100
10.3k
  }
1101
51.5k
  zone.closeRecord("SdrPageDefA1");
1102
51.5k
  if (ok && hasExtraData) {
1103
26.5k
    lastPos=zone.getRecordLastPosition();
1104
26.5k
    n=0;
1105
78.3k
    while (input->tell()<lastPos) {
1106
54.3k
      pos=input->tell();
1107
54.3k
      if (!zone.openRecord()) break;
1108
51.8k
      f.str("");
1109
51.8k
      f << "SdrPageDefB" << ++n << "[" << zone.getRecordLevel() << "]:";
1110
51.8k
      if (n==1) {
1111
25.8k
        std::vector<uint32_t> string;
1112
25.8k
        if (!zone.readString(string)) {
1113
216
          STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: can not find read a string\n"));
1114
216
          f << "###string";
1115
216
        }
1116
25.6k
        else {
1117
          // Controls or sheet name
1118
25.6k
          page->m_name=libstoff::getString(string);
1119
25.6k
          f << page->m_name.cstr() << ",";
1120
25.6k
        }
1121
        // then if vers>={13|14|15|16}  671905111105671901000800000000000000
1122
25.8k
      }
1123
25.9k
      else if (n==2 && pos+12==zone.getRecordLastPosition()) {
1124
9.09k
        f << "empty,";
1125
45.4k
        for (int i=0; i<4; ++i) { // always 0
1126
36.3k
          auto val=int(input->readLong(2));
1127
36.3k
          if (val) f << "f" << i << "=" << val << ",";
1128
36.3k
        }
1129
9.09k
      }
1130
16.8k
      else if (!readSdrPageUnknownZone1(zone, zone.getRecordLastPosition())) {
1131
6.26k
        input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1132
6.26k
        STOFF_DEBUG_MSG(("StarObjectModel::readSdrPage: find some unknown zone\n"));
1133
6.26k
        f << "###unknown";
1134
6.26k
      }
1135
      // for version>=16?, find another zone: either an empty zone or a zone which contains many string...
1136
51.8k
      if (zone.getRecordLastPosition()!=input->tell()) {
1137
16.3k
        ascFile.addDelimiter(input->tell(),'|');
1138
16.3k
        f << "#";
1139
16.3k
        input->seek(zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
1140
16.3k
      }
1141
51.8k
      ascFile.addPos(pos);
1142
51.8k
      ascFile.addNote(f.str().c_str());
1143
51.8k
      zone.closeRecord("SdrPageDefB");
1144
51.8k
    }
1145
26.5k
  }
1146
1147
51.5k
  zone.closeSDRHeader("SdrPageDef");
1148
51.5k
  return page;
1149
54.8k
}
1150
1151
bool StarObjectModel::readSdrPageUnknownZone1(StarZone &zone, long lastPos)
1152
16.8k
{
1153
  // checkme: probably as draw pres: schheader: first a schheader, then 3 bool
1154
16.8k
  STOFFInputStreamPtr input=zone.input();
1155
16.8k
  long pos=input->tell()-4;
1156
16.8k
  libstoff::DebugFile &ascFile=zone.ascii();
1157
16.8k
  libstoff::DebugStream f;
1158
16.8k
  f << "Entries(SdrPageUnkn1)[" << zone.getRecordLevel() << "]:";
1159
16.8k
  if (pos+28>lastPos) return false;
1160
15.8k
  auto val=int(input->readULong(2));
1161
15.8k
  if (val!=3 && val!=7)
1162
4.28k
    return false;
1163
11.6k
  f << "f0=" << val << ",";
1164
46.4k
  for (int i=0; i<3; ++i) { // 1
1165
34.8k
    val=int(input->readULong(1));
1166
34.8k
    if (val!=1) f << "f" << i+1 << "=" << val << ",";
1167
34.8k
  }
1168
69.6k
  for (int i=0; i<5; ++i) { // g0=14|15|19, g1=1, g3=0-10,
1169
58.0k
    val=int(input->readLong(2));
1170
58.0k
    if (val) f << "g" << i << "=" << val << ",";
1171
58.0k
  }
1172
11.6k
  val=int(input->readLong(1)); // always 1
1173
11.6k
  if (val!=1) f << "f6=" << val << ",";
1174
46.4k
  for (int i=0; i<3; ++i) { // g5=1|1e
1175
34.8k
    val=int(input->readLong(2));
1176
34.8k
    if (val) f << "g" << i+5 << "=" << val << ",";
1177
34.8k
  }
1178
11.6k
  std::vector<uint32_t> string;
1179
11.6k
  if (!zone.readString(string) || input->tell()>lastPos)
1180
404
    return false;
1181
11.2k
  f << libstoff::getString(string).cstr() << ",";
1182
11.2k
  auto n=int(input->readULong(4));
1183
11.2k
  if (n<0 || (lastPos-input->tell())/8<n || input->tell()+8*n>lastPos)
1184
627
    return false;
1185
10.5k
  f << "unk=[";
1186
28.2k
  for (int i=0; i<n; ++i) {
1187
17.7k
    f << "[";
1188
88.5k
    for (int j=0; j<4; ++j) {
1189
70.8k
      val=int(input->readLong(2));
1190
70.8k
      if (val)
1191
28.2k
        f << val << ",";
1192
42.5k
      else
1193
42.5k
        f << "_,";
1194
70.8k
    }
1195
17.7k
    f << "],";
1196
17.7k
  }
1197
10.5k
  f << "],";
1198
10.5k
  int n1=int(lastPos-input->tell())/2;
1199
10.5k
  f << "unkn1=[";
1200
105k
  for (int i=0; i<n1; ++i) {
1201
95.2k
    val=int(input->readLong(2));
1202
95.2k
    if (val)
1203
31.5k
      f << val << ",";
1204
63.6k
    else
1205
63.6k
      f << "_,";
1206
95.2k
  }
1207
10.5k
  f << "],";
1208
10.5k
  if (lastPos>input->tell()) {
1209
114
    ascFile.addDelimiter(input->tell(),'|');
1210
114
    input->seek(lastPos, librevenge::RVNG_SEEK_SET);
1211
114
  }
1212
10.5k
  ascFile.addPos(pos);
1213
10.5k
  ascFile.addNote(f.str().c_str());
1214
10.5k
  return true;
1215
11.2k
}
1216
1217
bool StarObjectModel::readSdrMPageDesc(StarZone &zone, StarObjectModelInternal::Page &page)
1218
17.4k
{
1219
17.4k
  STOFFInputStreamPtr input=zone.input();
1220
  // first check magic
1221
17.4k
  std::string magic("");
1222
17.4k
  long pos=input->tell();
1223
87.4k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
1224
17.4k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1225
17.4k
  if (magic!="DrMD") return false;
1226
1227
16.7k
  libstoff::DebugFile &ascFile=zone.ascii();
1228
16.7k
  libstoff::DebugStream f;
1229
16.7k
  f << "Entries(SdrMPageDesc)[" << zone.getRecordLevel() << "]:";
1230
  // svdpage.cxx operator>>(..., SdrMaterPageDescriptor &)
1231
16.7k
  if (!zone.openSDRHeader(magic)) {
1232
2.01k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1233
2.01k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrMPageDesc: can not open the SDR Header\n"));
1234
2.01k
    f << "###";
1235
2.01k
    ascFile.addPos(pos);
1236
2.01k
    ascFile.addNote(f.str().c_str());
1237
2.01k
    return false;
1238
2.01k
  }
1239
14.7k
  int version=zone.getHeaderVersion();
1240
14.7k
  f << magic << ",nVers=" << version << ",";
1241
14.7k
  StarObjectModelInternal::Page::Descriptor desc;
1242
14.7k
  desc.m_masterId=int(input->readULong(2));
1243
14.7k
  std::vector<int> layers;
1244
485k
  for (int i=0; i<32; ++i)
1245
470k
    layers.push_back(int(input->readULong(1)));
1246
14.7k
  StarObjectModelInternal::convertUint8ListToBoolList(layers, desc.m_layerList);
1247
14.7k
  f << desc;
1248
14.7k
  page.m_masterPageDescList.push_back(desc);
1249
14.7k
  ascFile.addPos(pos);
1250
14.7k
  ascFile.addNote(f.str().c_str());
1251
14.7k
  zone.closeSDRHeader("SdrMPageDesc");
1252
14.7k
  return true;
1253
16.7k
}
1254
1255
bool StarObjectModel::readSdrMPageDescList(StarZone &zone, StarObjectModelInternal::Page &page)
1256
47.4k
{
1257
47.4k
  STOFFInputStreamPtr input=zone.input();
1258
  // first check magic
1259
47.4k
  std::string magic("");
1260
47.4k
  long pos=input->tell();
1261
237k
  for (int i=0; i<4; ++i) magic+=char(input->readULong(1));
1262
47.4k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1263
47.4k
  if (magic!="DrML") return false;
1264
1265
47.4k
  libstoff::DebugFile &ascFile=zone.ascii();
1266
47.4k
  libstoff::DebugStream f;
1267
47.4k
  f << "Entries(SdrMPageList)[" << zone.getRecordLevel() << "]:";
1268
  // svdpage.cxx operator>>(..., SdrMaterPageDescListriptor &)
1269
47.4k
  if (!zone.openSDRHeader(magic)) {
1270
1.01k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1271
1.01k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrMPageDescList: can not open the SDR Header\n"));
1272
1.01k
    f << "###";
1273
1.01k
    ascFile.addPos(pos);
1274
1.01k
    ascFile.addNote(f.str().c_str());
1275
1.01k
    return false;
1276
1.01k
  }
1277
46.4k
  int version=zone.getHeaderVersion();
1278
46.4k
  uint16_t n;
1279
46.4k
  *input>>n;
1280
46.4k
  f << magic << ",nVers=" << version << ",N=" << n << ",";
1281
46.4k
  ascFile.addPos(pos);
1282
46.4k
  ascFile.addNote(f.str().c_str());
1283
1284
46.4k
  long lastPos=zone.getRecordLastPosition();
1285
61.1k
  for (int i=0; i<n; ++i) {
1286
18.3k
    pos=input->tell();
1287
18.3k
    if (pos<lastPos && readSdrMPageDesc(zone, page)) continue;
1288
3.67k
    STOFF_DEBUG_MSG(("StarObjectModel::readSdrMPageDescList: can not find a page desc\n"));
1289
3.67k
    ascFile.addPos(pos);
1290
3.67k
    ascFile.addNote("SdrMPageList:###pageDesc");
1291
3.67k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1292
3.67k
    break;
1293
18.3k
  }
1294
1295
46.4k
  zone.closeSDRHeader("SdrMPageList");
1296
46.4k
  return true;
1297
47.4k
}
1298
1299
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: