Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libstaroffice/src/lib/StarZone.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 <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "StarEncryption.hxx"
43
44
#include "StarZone.hxx"
45
46
constexpr size_t MAX_RECORD_NESTING = 1 << 10;
47
48
////////////////////////////////////////////////////////////
49
// constructor/destructor, ...
50
////////////////////////////////////////////////////////////
51
StarZone::StarZone(STOFFInputStreamPtr const &inputStream, std::string const &ascName, std::string const &zoneName, char const *password)
52
206k
  : m_input(inputStream)
53
206k
  , m_ascii(inputStream)
54
206k
  , m_version(0)
55
206k
  , m_documentVersion(0)
56
206k
  , m_headerVersionStack()
57
206k
  , m_encoding(StarEncoding::E_DONTKNOW)
58
206k
  , m_guiType(0)
59
206k
  , m_encryption()
60
206k
  , m_asciiName(ascName)
61
206k
  , m_zoneName(zoneName)
62
206k
  , m_typeStack()
63
206k
  , m_positionStack()
64
206k
  , m_beginToEndMap()
65
  , m_flagEndZone()
66
206k
  , m_poolList()
67
206k
{
68
206k
  if (password)
69
0
    m_encryption.reset(new StarEncryption(password));
70
206k
}
71
72
StarZone::~StarZone()
73
206k
{
74
206k
  m_ascii.reset();
75
206k
}
76
77
void StarZone::setInput(STOFFInputStreamPtr ip)
78
56.8k
{
79
56.8k
  m_input=ip;
80
56.8k
  m_ascii.setStream(ip);
81
56.8k
}
82
83
bool StarZone::readString(std::vector<uint32_t> &string, std::vector<size_t> &srcPositions, int encoding, bool chckEncryption) const
84
4.35M
{
85
4.35M
  auto sSz=int(m_input->readULong(2));
86
4.35M
  string.clear();
87
4.35M
  srcPositions.clear();
88
4.35M
  if (!sSz) return true;
89
2.34M
  unsigned long numRead;
90
2.34M
  uint8_t const *data=m_input->read(size_t(sSz), numRead);
91
2.34M
  if (!data || numRead!=static_cast<unsigned long>(sSz)) {
92
343k
    STOFF_DEBUG_MSG(("StarZone::readString: the sSz seems bad\n"));
93
343k
    return false;
94
343k
  }
95
2.00M
  std::vector<uint8_t> buffer;
96
2.00M
  buffer.resize(size_t(sSz));
97
2.00M
  std::memcpy(&buffer[0], data, size_t(sSz));
98
2.00M
  if (chckEncryption && m_encryption)
99
0
    m_encryption->decode(buffer);
100
2.00M
  auto encod=m_encoding;
101
2.00M
  if (encoding>=1) encod=StarEncoding::getEncodingForId(encoding);
102
2.00M
  return StarEncoding::convert(buffer, encod, string, srcPositions);
103
2.34M
}
104
105
bool StarZone::readStringsPool()
106
1.61k
{
107
1.61k
  long pos=m_input->tell();
108
1.61k
  unsigned char type;
109
1.61k
  if (m_input->peek()!='!' || !openSWRecord(type)) {
110
36
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
111
36
    return false;
112
36
  }
113
1.58k
  libstoff::DebugStream f;
114
1.58k
  f << "Entries(SWPoolList)[" << getRecordLevel() << "]:";
115
  // sw_sw3misc.xx: InStringPool sw_sw3imp.cxx: LoadOld and Load
116
1.58k
  int encoding=m_encoding;
117
1.58k
  m_poolList.clear();
118
1.58k
  long lastPos=getRecordLastPosition();
119
1.58k
  if (!isCompatibleWith(3)) {
120
2
    auto n=int(m_input->readULong(2));
121
2
    if (n>=256) {
122
2
      m_input->seek(-1, librevenge::RVNG_SEEK_CUR);
123
2
      encoding=int(m_input->readULong(1));
124
2
      f << "encoding=" << encoding << ",";
125
2
      n=int(m_input->readULong(2));
126
2
    }
127
2
    f << "n=" << n << ",";
128
2
    m_ascii.addPos(pos);
129
2
    m_ascii.addNote(f.str().c_str());
130
2
    std::vector<uint32_t> string;
131
2
    for (int i=0; i<n; ++i) {
132
2
      pos=m_input->tell();
133
2
      f.str("");
134
2
      f << "SWPoolList-" << i << ":";
135
2
      if (!readString(string, encoding) || m_input->tell()>lastPos) {
136
2
        STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n"));
137
2
        m_input->seek(pos, librevenge::RVNG_SEEK_SET);
138
2
        break;
139
2
      }
140
0
      m_poolList.push_back(libstoff::getString(string));
141
0
      f << m_poolList.back().cstr() << ",";
142
0
      m_ascii.addPos(pos);
143
0
      m_ascii.addNote(f.str().c_str());
144
0
    }
145
2
  }
146
1.58k
  else {
147
1.58k
    encoding=int(m_input->readULong(1));
148
1.58k
    f << "encoding=" << encoding << ",";
149
1.58k
    auto n=int(m_input->readULong(2));
150
1.58k
    f << "n=" << n << ",";
151
1.58k
    m_ascii.addPos(pos);
152
1.58k
    m_ascii.addNote(f.str().c_str());
153
154
1.58k
    std::vector<uint32_t> string;
155
18.2k
    for (int i=0; i<n; ++i) { // checkme
156
16.8k
      pos=m_input->tell();
157
16.8k
      f.str("");
158
16.8k
      f << "SWPoolList-" << i << ":";
159
16.8k
      auto nId=int(m_input->readULong(2));
160
16.8k
      f << "nId=" << nId << ",";
161
16.8k
      if (!readString(string, encoding) || m_input->tell()>lastPos) {
162
163
        STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n"));
163
163
        m_input->seek(pos, librevenge::RVNG_SEEK_SET);
164
163
        break;
165
163
      }
166
16.6k
      m_poolList.push_back(libstoff::getString(string));
167
16.6k
      f << m_poolList.back().cstr() << ",";
168
16.6k
      m_ascii.addPos(pos);
169
16.6k
      m_ascii.addNote(f.str().c_str());
170
16.6k
    }
171
1.58k
  }
172
1.58k
  closeSWRecord(type, "SWPoolList");
173
1.58k
  return true;
174
1.61k
}
175
176
bool StarZone::checkEncryption(uint32_t date, uint32_t time, std::vector<uint8_t> const &passwd)
177
0
{
178
0
  if ((!date && !time) || passwd.empty())
179
0
    return true;
180
0
  if (m_encryption && m_encryption->checkPassword(date,time,passwd))
181
0
    return true;
182
0
  if (!m_encryption) m_encryption.reset(new StarEncryption);
183
184
0
  if (!m_encryption->guessPassword(date,time,passwd) || !m_encryption->checkPassword(date,time,passwd)) {
185
0
    STOFF_DEBUG_MSG(("StarZone::readZoneHeader: can not find the password\n"));
186
0
    throw libstoff::WrongPasswordException();
187
0
  }
188
0
  STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find a potential password, let continue\n"));
189
0
  return true;
190
0
}
191
192
bool StarZone::readSWHeader()
193
1.67k
{
194
1.67k
  m_ascii.open(m_asciiName);
195
196
1.67k
  libstoff::DebugStream f;
197
1.67k
  f << "Entries(" << m_zoneName << "):";
198
199
  // sw_sw3doc.cxx: Sw3IoImp::InHeader
200
1.67k
  if (m_input->size()<0x36) {
201
0
    STOFF_DEBUG_MSG(("StarZone::readSWHeader: the zone is too short\n"));
202
0
    f << "###";
203
0
    m_ascii.addPos(0);
204
0
    m_ascii.addNote(f.str().c_str());
205
206
0
    return false;
207
0
  }
208
1.67k
  m_input->seek(0, librevenge::RVNG_SEEK_SET);
209
210
1.67k
  auto val=int(m_input->readULong(2));
211
1.67k
  if (val==0x5357)
212
0
    m_input->setReadInverted(!m_input->readInverted());
213
1.67k
  else if (val!=0x5753) {
214
45
    STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not set the endian\n"));
215
45
    f << "###";
216
45
    m_ascii.addPos(0);
217
45
    m_ascii.addNote(f.str().c_str());
218
219
45
    return false;
220
45
  }
221
222
1.62k
  m_input->seek(0, librevenge::RVNG_SEEK_SET);
223
13.0k
  for (int i=0; i<7; ++i) {
224
11.4k
    auto c=char(m_input->readULong(1));
225
11.4k
    static char const expected[]= {'S','W',char(0),'H', 'D', 'R', char(0)};
226
11.4k
    if (c==expected[i]) continue;
227
1.63k
    if (i!=2) {
228
1
      STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not read the header\n"));
229
1
      f << "###";
230
1
      m_ascii.addPos(0);
231
1
      m_ascii.addNote(f.str().c_str());
232
233
1
      return false;
234
1
    }
235
1.62k
    if (c<'3' || c>'5') {
236
4
      STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find unexpected version number\n"));
237
4
      f << "##version=" << int(c) << ",";
238
4
    }
239
1.62k
    else {
240
1.62k
      m_version=int(c-'0');
241
1.62k
      f << "version=" << m_version << ",";
242
1.62k
    }
243
1.62k
  }
244
1.62k
  auto hSz=int(m_input->readULong(1));
245
1.62k
  if (hSz<0x2e || !m_input->checkPosition(8+hSz)) {
246
0
    STOFF_DEBUG_MSG(("StarZone::readSWHeader: the header seems bad\n"));
247
0
    f << "###hSz";
248
0
    m_ascii.addPos(0);
249
0
    m_ascii.addNote(f.str().c_str());
250
251
0
    return false;
252
0
  }
253
1.62k
  m_documentVersion=int(m_input->readULong(2));
254
1.62k
  f << "docVersion=" << std::hex << m_documentVersion << std::dec << ",";
255
1.62k
  auto fFlags=int(m_input->readULong(2));
256
1.62k
  bool hasPasswd=false;
257
1.62k
  if (fFlags&2) f << "hasBlockName,";
258
1.62k
  if (fFlags&8) {
259
2
    hasPasswd=true;
260
2
    f << "hasPasswd,";
261
2
  }
262
1.62k
  if (fFlags&0x100) f << "hasPGNums,";
263
1.62k
  if (fFlags&0x8000) {
264
2
    f << "#badFile,";
265
2
    STOFF_DEBUG_MSG(("StarZone::readSWHeader: bad file is set\n"));
266
267
2
    m_ascii.addPos(0);
268
2
    m_ascii.addNote(f.str().c_str());
269
270
2
    return false;
271
2
  }
272
1.62k
  fFlags&=0x7EF5;
273
1.62k
  if (fFlags) f << "flags=" << std::hex << fFlags << std::dec << ",";
274
1.62k
  auto dFlags=long(m_input->readULong(4));
275
1.62k
  if (dFlags&1) f << "browse[mode],";
276
1.62k
  if (dFlags&2) f << "browse[mode2],";
277
1.62k
  if (dFlags&4) f << "html[mode],";
278
1.62k
  if (dFlags&8) f << "show[header],";
279
1.62k
  if (dFlags&0x10) f << "show[footer],";
280
1.62k
  if (dFlags&0x20) f << "global[doc],";
281
1.62k
  if (dFlags&0x40) f << "hasSections,";
282
1.62k
  if (dFlags&0x80) f << "isLabel,";
283
1.62k
  dFlags&=0xffffff00;
284
1.62k
  if (dFlags) f << "dFlags=" << std::hex << dFlags << std::dec << ",";
285
1.62k
  long recPos=int(m_input->readULong(4));
286
1.62k
  if (recPos) f << "recPos=" << std::hex << val << std::dec << ",";
287
1.62k
  m_input->seek(6, librevenge::RVNG_SEEK_CUR); // dummy
288
1.62k
  val=int(m_input->readULong(1));
289
1.62k
  if (val&1)
290
0
    f << "redline[on],";
291
1.62k
  if (val&2)
292
0
    f << "redline[ignore],";
293
1.62k
  if (val&0x10)
294
1.61k
    f << "redline[showInsert],";
295
1.62k
  if (val&0x20)
296
1.61k
    f << "redline[showDelete],";
297
1.62k
  val&=0xCC;
298
1.62k
  if (val) f << "redline=" << std::hex << val << std::dec << ",";
299
1.62k
  val=int(m_input->readULong(1));
300
1.62k
  if (val) f << "compVers=" << val << ",";
301
1.62k
  std::vector<uint8_t> passwd;
302
27.6k
  for (int i=0; i<16; ++i) passwd.push_back(static_cast<uint8_t>(m_input->readULong(1)));
303
1.62k
  val=int(m_input->readULong(1));
304
1.62k
  if (val) f << "charSet[encoding]=" << val << ",";
305
1.62k
  m_encoding=StarEncoding::getEncodingForId(val);
306
1.62k
  val=int(m_input->readULong(1));
307
1.62k
  if (val) f << "f0=" << val << ",";
308
1.62k
  uint32_t date, time;
309
1.62k
  *m_input >> date >> time;
310
1.62k
  f << "date=" << date << ",";
311
1.62k
  f << "time=" << time << ",";
312
1.62k
  if (hasPasswd)
313
0
    checkEncryption(date,time,passwd);
314
1.62k
  else
315
1.62k
    m_encryption.reset();
316
1.62k
  if (hSz==0x2e +64 && (fFlags&2)) {
317
0
    std::string string("");
318
0
    for (int i=0; i<64; ++i) {
319
0
      auto c=char(m_input->readULong(1));
320
0
      if (!c) break;
321
0
      string+=c;
322
0
    }
323
0
    f << string;
324
0
    m_input->seek(8+0x2e +64, librevenge::RVNG_SEEK_SET);
325
0
  }
326
1.62k
  if (m_input->tell()!=8+hSz) {
327
0
    m_ascii.addDelimiter(m_input->tell(),'|');
328
0
    STOFF_DEBUG_MSG(("StarZone::readSWHeader: find extra data\n"));
329
0
    f << "###extra";
330
0
  }
331
1.62k
  m_ascii.addPos(0);
332
1.62k
  m_ascii.addNote(f.str().c_str());
333
1.62k
  m_input->seek(8+hSz, librevenge::RVNG_SEEK_SET);
334
1.62k
  if (recPos && isCompatibleWith(int('%')))
335
0
    return readRecordSizes(recPos);
336
337
1.62k
  return true;
338
1.62k
}
339
340
////////////////////////////////////////////////////////////
341
// sdrheader: open/close
342
////////////////////////////////////////////////////////////
343
bool StarZone::openSCHHeader()
344
25.2k
{
345
25.2k
  long pos=m_input->tell();
346
25.2k
  if (!m_input->checkPosition(pos+6)) return false;
347
  // schiocmp.cxx: SchIOHeader::SchIOHeader
348
25.1k
  auto len=long(m_input->readULong(4));
349
25.1k
  m_headerVersionStack.push(int(m_input->readULong(2)));
350
25.1k
  long endPos=pos+len;
351
25.1k
  if (len<6 || !m_input->checkPosition(endPos)) {
352
9.64k
    m_headerVersionStack.pop();
353
9.64k
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
354
9.64k
    return false;
355
9.64k
  }
356
  // check the position ends in the current group (if a group is open)
357
15.5k
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
358
250
    STOFF_DEBUG_MSG(("StarZone::openSCHHeader: argh endPosition is not in the current group\n"));
359
250
    m_headerVersionStack.pop();
360
250
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
361
250
    return false;
362
250
  }
363
15.2k
  m_typeStack.push('@');
364
15.2k
  m_positionStack.push(endPos);
365
15.2k
  return true;
366
15.5k
}
367
368
bool StarZone::closeSCHHeader(std::string const &debugName)
369
15.3k
{
370
15.3k
  if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
371
15.3k
  return closeRecord('@', debugName);
372
15.3k
}
373
374
bool StarZone::openVersionCompatHeader()
375
39.3k
{
376
39.3k
  long pos=m_input->tell();
377
39.3k
  if (!m_input->checkPosition(pos+6)) return false;
378
  // vcompat.cxx: VersionCompat::VersionCompat
379
39.2k
  m_headerVersionStack.push(int(m_input->readULong(2)));
380
39.2k
  auto len=long(m_input->readULong(4));
381
39.2k
  long endPos=pos+6+len;
382
39.2k
  if (len<0 || !m_input->checkPosition(endPos)) {
383
2.27k
    m_headerVersionStack.pop();
384
2.27k
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
385
2.27k
    return false;
386
2.27k
  }
387
  // check the position ends in the current group (if a group is open)
388
37.0k
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
389
198
    STOFF_DEBUG_MSG(("StarZone::openVersionCompatHeader: argh endPosition is not in the current group\n"));
390
198
    m_headerVersionStack.pop();
391
198
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
392
198
    return false;
393
198
  }
394
36.8k
  m_typeStack.push('*');
395
36.8k
  m_positionStack.push(endPos);
396
36.8k
  return true;
397
37.0k
}
398
399
bool StarZone::closeVersionCompatHeader(std::string const &debugName)
400
36.8k
{
401
36.8k
  if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
402
36.8k
  return closeRecord('*', debugName);
403
36.8k
}
404
405
bool StarZone::openSDRHeader(std::string &magic)
406
479k
{
407
479k
  long pos=m_input->tell();
408
479k
  if (!m_input->checkPosition(pos+4)) return false;
409
479k
  if (m_positionStack.size()>=MAX_RECORD_NESTING) {
410
0
    STOFF_DEBUG_MSG(("StarZone::openSDRHeader: the record is nested too deeply\n"));
411
0
    return false;
412
0
  }
413
  // svdio.cxx: SdrIOHeader::Read
414
479k
  magic="";
415
2.39M
  for (int i=0; i<4; ++i) magic+=char(m_input->readULong(1));
416
  // special case: ok to have only magic if ...
417
479k
  if (magic=="DrXX") {
418
43.2k
    m_typeStack.push('_');
419
43.2k
    m_positionStack.push(m_input->tell());
420
43.2k
    return true;
421
43.2k
  }
422
436k
  m_headerVersionStack.push(int(m_input->readULong(2)));
423
436k
  auto len=long(m_input->readULong(4));
424
436k
  long endPos=pos+len;
425
436k
  if (len<10 || magic.compare(0,2,"Dr")!=0 || !m_input->checkPosition(endPos)) {
426
14.7k
    m_headerVersionStack.pop();
427
14.7k
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
428
14.7k
    return false;
429
14.7k
  }
430
  // check the position ends in the current group (if a group is open)
431
421k
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
432
5.31k
    STOFF_DEBUG_MSG(("StarZone::openSDRHeader: argh endPosition is not in the current group\n"));
433
5.31k
    m_headerVersionStack.pop();
434
5.31k
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
435
5.31k
    return false;
436
5.31k
  }
437
416k
  m_typeStack.push('_');
438
416k
  m_positionStack.push(endPos);
439
416k
  return true;
440
421k
}
441
442
bool StarZone::closeSDRHeader(std::string const &debugName)
443
459k
{
444
459k
  if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
445
459k
  return closeRecord('_', debugName);
446
459k
}
447
448
////////////////////////////////////////////////////////////
449
// record: open/close, read size
450
////////////////////////////////////////////////////////////
451
bool StarZone::openDummyRecord()
452
3.53M
{
453
3.53M
  m_typeStack.push('@');
454
3.53M
  if (!m_positionStack.empty())
455
3.36M
    m_positionStack.push(m_positionStack.top());
456
162k
  else
457
162k
    m_positionStack.push(m_input->size());
458
3.53M
  return true;
459
3.53M
}
460
461
bool StarZone::openRecord()
462
1.23M
{
463
1.23M
  long pos=m_input->tell();
464
1.23M
  if (!m_input->checkPosition(pos+4)) return false;
465
1.23M
  unsigned long sz=m_input->readULong(4);
466
1.23M
  long endPos=0;
467
468
1.23M
  m_flagEndZone=0;
469
1.23M
  if (sz<4) {
470
12.3k
    STOFF_DEBUG_MSG(("StarZone::openRecord: size can be less than 4\n"));
471
12.3k
    return false;
472
12.3k
  }
473
1.22M
  endPos=pos+long(sz);
474
  // check the position is in the file
475
1.22M
  if (endPos && !m_input->checkPosition(endPos)) {
476
47.5k
    STOFF_DEBUG_MSG(("StarZone::openRecord: endPosition is bad\n"));
477
47.5k
    return false;
478
47.5k
  }
479
  // check the position ends in the current group (if a group is open)
480
1.17M
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
481
9.65k
    STOFF_DEBUG_MSG(("StarZone::openRecord: argh endPosition is not in the current group\n"));
482
9.65k
    return false;
483
9.65k
  }
484
1.16M
  m_typeStack.push(' ');
485
1.16M
  m_positionStack.push(endPos);
486
1.16M
  return true;
487
1.17M
}
488
489
bool StarZone::openSCRecord()
490
593k
{
491
593k
  long pos=m_input->tell();
492
593k
  if (!m_input->checkPosition(pos+4)) return false;
493
593k
  unsigned long sz=m_input->readULong(4);
494
593k
  long endPos=0;
495
496
593k
  m_flagEndZone=0;
497
593k
  endPos=pos+4+long(sz);
498
  // check the position is in the file
499
593k
  if (endPos && !m_input->checkPosition(endPos)) {
500
111k
    STOFF_DEBUG_MSG(("StarZone::openSCRecord: endPosition is bad\n"));
501
111k
    return false;
502
111k
  }
503
  // check the position ends in the current group (if a group is open)
504
482k
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
505
6.27k
    STOFF_DEBUG_MSG(("StarZone::openSCRecord: argh endPosition is not in the current group\n"));
506
6.27k
    return false;
507
6.27k
  }
508
475k
  m_typeStack.push('_');
509
475k
  m_positionStack.push(endPos);
510
475k
  return true;
511
482k
}
512
513
bool StarZone::openSWRecord(unsigned char &type)
514
58.7k
{
515
58.7k
  long pos=m_input->tell();
516
58.7k
  if (!m_input->checkPosition(pos+4)) return false;
517
58.7k
  if (m_positionStack.size()>=MAX_RECORD_NESTING) {
518
0
    STOFF_DEBUG_MSG(("StarZone::openSWRecord: the record is nested too deeply\n"));
519
0
    return false;
520
0
  }
521
58.7k
  unsigned long val=m_input->readULong(4);
522
58.7k
  type=static_cast<unsigned char>(val&0xff);
523
58.7k
  if (!type) {
524
1.17k
    STOFF_DEBUG_MSG(("StarZone::openSWRecord: type can not be null\n"));
525
1.17k
    return false;
526
1.17k
  }
527
57.5k
  unsigned long sz=(val>>8);
528
57.5k
  long endPos=0;
529
530
57.5k
  m_flagEndZone=0;
531
57.5k
  if (sz==0xffffff && isCompatibleWith(0x0209)) {
532
356
    if (m_beginToEndMap.find(pos)!=m_beginToEndMap.end())
533
0
      endPos=m_beginToEndMap.find(pos)->second;
534
356
    else {
535
356
      STOFF_DEBUG_MSG(("StarZone::openSWRecord: can not find size for a zone, we may have some problem\n"));
536
356
    }
537
356
  }
538
57.2k
  else {
539
57.2k
    if (sz<4) {
540
534
      STOFF_DEBUG_MSG(("StarZone::openSWRecord: size can be less than 4\n"));
541
534
      return false;
542
534
    }
543
56.6k
    endPos=pos+long(sz);
544
56.6k
  }
545
  // check the position is in the file
546
57.0k
  if (endPos && !m_input->checkPosition(endPos)) {
547
4.66k
    STOFF_DEBUG_MSG(("StarZone::openSWRecord: endPosition is bad\n"));
548
4.66k
    return false;
549
4.66k
  }
550
  // check the position ends in the current group (if a group is open)
551
52.3k
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
552
1.95k
    STOFF_DEBUG_MSG(("StarZone::openSWRecord: argh endPosition is not in the current group\n"));
553
1.95k
    return false;
554
1.95k
  }
555
50.4k
  m_typeStack.push(type);
556
50.4k
  m_positionStack.push(endPos);
557
50.4k
  return true;
558
52.3k
}
559
560
bool StarZone::openSfxRecord(unsigned char &type)
561
2.02M
{
562
2.02M
  long pos=m_input->tell();
563
2.02M
  if (!m_input->checkPosition(pos+4)) return false;
564
  // filerec.cxx SfxMiniRecordReader::SfxMiniRecordReader
565
2.02M
  unsigned long val=m_input->readULong(4);
566
2.02M
  type=static_cast<unsigned char>(val&0xff);
567
  // checkme: can type be null
568
2.02M
  unsigned long sz=(val>>8);
569
2.02M
  long endPos=0;
570
571
2.02M
  m_flagEndZone=0;
572
2.02M
  endPos=pos+4+long(sz);
573
  // check the position is in the file
574
2.02M
  if (endPos && !m_input->checkPosition(endPos)) {
575
118k
    STOFF_DEBUG_MSG(("StarZone::openSfxRecord: endPosition is bad\n"));
576
118k
    return false;
577
118k
  }
578
  // check the position ends in the current group (if a group is open)
579
1.90M
  if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
580
156k
    STOFF_DEBUG_MSG(("StarZone::openSfxRecord: argh endPosition is not in the current group\n"));
581
156k
    return false;
582
156k
  }
583
1.74M
  m_typeStack.push(type);
584
1.74M
  m_positionStack.push(endPos);
585
1.74M
  return true;
586
1.90M
}
587
588
bool StarZone::closeRecord(unsigned char type, std::string const &debugName)
589
6.76M
{
590
6.76M
  m_flagEndZone=0;
591
7.48M
  while (!m_typeStack.empty()) {
592
7.48M
    unsigned char typ=m_typeStack.top();
593
7.48M
    long pos=m_positionStack.top();
594
595
7.48M
    m_typeStack.pop();
596
7.48M
    m_positionStack.pop();
597
7.48M
    if (typ!=type) continue;
598
6.76M
    if (!pos || type=='@')
599
3.54M
      return true;
600
3.21M
    long actPos=m_input->tell();
601
3.21M
    if (actPos!=pos) {
602
305k
      if (actPos>pos) {
603
44.0k
        STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, we read to much data\n"));
604
44.0k
      }
605
261k
      else if (actPos<pos) {
606
261k
        STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, some data have been ignored\n"));
607
261k
      }
608
305k
      libstoff::DebugStream f;
609
305k
      f << debugName << ":###extra";
610
305k
      m_ascii.addPos(actPos);
611
305k
      m_ascii.addNote(f.str().c_str());
612
305k
    }
613
614
3.21M
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
615
3.21M
    return true;
616
6.76M
  }
617
1.81k
  STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, can not find type %d\n", int(type)));
618
1.81k
  return false;
619
6.76M
}
620
621
unsigned char StarZone::openFlagZone()
622
26.3k
{
623
26.3k
  auto cFlags=static_cast<unsigned char>(m_input->readULong(1));
624
26.3k
  m_flagEndZone=m_input->tell()+long(cFlags&0xf);
625
26.3k
  return cFlags;
626
26.3k
}
627
628
void StarZone::closeFlagZone()
629
26.3k
{
630
26.3k
  if (!m_flagEndZone) {
631
0
    STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, can not find end position\n"));
632
0
    return;
633
0
  }
634
26.3k
  if (m_flagEndZone<m_input->tell()) {
635
4.61k
    STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we have read too much data\n"));
636
4.61k
    m_ascii.addPos(m_input->tell());
637
4.61k
    m_ascii.addNote("Entries(BadFlagZone):###");
638
4.61k
  }
639
21.7k
  else if (m_flagEndZone>m_input->tell()) {
640
1.45k
    STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we do not have read all data\n"));
641
1.45k
    m_ascii.addPos(m_input->tell());
642
1.45k
    m_ascii.addNote("Entries(BadFlagZone):#");
643
1.45k
  }
644
26.3k
  m_input->seek(m_flagEndZone, librevenge::RVNG_SEEK_SET);
645
26.3k
}
646
647
bool StarZone::readRecordSizes(long pos)
648
0
{
649
0
  if (!pos || !isCompatibleWith('%'))
650
0
    return true;
651
  // read the position:  sw_sw3imp.cxx: Sw3IoImp::InRecSizes
652
0
  long oldPos=m_input->tell();
653
0
  if (oldPos!=pos)
654
0
    m_input->seek(pos, librevenge::RVNG_SEEK_SET);
655
0
  libstoff::DebugStream f;
656
0
  f << m_zoneName << "[RecSize]:";
657
0
  unsigned char type;
658
0
  bool ok=openSWRecord(type);
659
0
  if (!ok || type!='%') {
660
0
    STOFF_DEBUG_MSG(("StarZone::readRecordSizes: can not open the record(recsize)\n"));
661
0
    f << "###extra";
662
0
    m_ascii.addPos(pos);
663
0
    m_ascii.addNote(f.str().c_str());
664
665
0
    m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
666
0
    return ok || (oldPos!=pos);
667
0
  }
668
669
0
  openFlagZone();
670
0
  auto nCount=int(m_input->readULong(4));
671
0
  f << "N=" << nCount << ",";
672
0
  closeFlagZone();
673
674
0
  if (nCount<0 || (getRecordLastPosition()-m_input->tell())/8<nCount || !m_input->checkPosition(m_input->tell()+8*nCount)) {
675
0
    STOFF_DEBUG_MSG(("StarZone::readRecordSizes: endCPos seems bad\n"));
676
0
    f << "###badN,";
677
678
0
    m_ascii.addPos(pos);
679
0
    m_ascii.addNote(f.str().c_str());
680
0
    closeSWRecord('%',m_zoneName);
681
0
    if (oldPos!=pos)
682
0
      m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
683
0
    return true;
684
0
  }
685
0
  f << "pos:size=[";
686
0
  for (int i=0; i<nCount; ++i) {
687
0
    auto cPos=long(m_input->readULong(4));
688
0
    auto sz=long(m_input->readULong(4));
689
0
    m_beginToEndMap[cPos]=cPos+sz;
690
0
    f << std::hex << cPos << "<->" << cPos+sz << std::dec << ",";
691
0
  }
692
0
  f << "],";
693
694
0
  closeSWRecord('%',m_zoneName);
695
0
  if (oldPos!=pos)
696
0
    m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
697
698
0
  m_ascii.addPos(pos);
699
0
  m_ascii.addNote(f.str().c_str());
700
0
  return true;
701
0
}
702
703
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: