Coverage Report

Created: 2026-10-28 06:34

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