Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/Lotus.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwps
3
 * Version: MPL 2.0 / LGPLv2.1+
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * Major Contributor(s):
10
 * Copyright (C) 2006, 2007 Andrew Ziem
11
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
12
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 *
14
 * For minor contributions see the git repository.
15
 *
16
 * Alternatively, the contents of this file may be used under the terms
17
 * of the GNU Lesser General Public License Version 2.1 or later
18
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
19
 * applicable instead of those above.
20
 */
21
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include <algorithm>
26
#include <cmath>
27
#include <iterator>
28
#include <map>
29
#include <sstream>
30
#include <stack>
31
#include <utility>
32
33
#include <librevenge-stream/librevenge-stream.h>
34
35
#include "libwps_internal.h"
36
#include "libwps_tools_win.h"
37
38
#include "WKSContentListener.h"
39
40
#include "WPSCell.h"
41
#include "WPSEntry.h"
42
#include "WPSFont.h"
43
#include "WPSHeader.h"
44
#include "WPSOLE1Parser.h"
45
#include "WPSPageSpan.h"
46
#include "WPSStream.h"
47
#include "WPSStringStream.h"
48
#include "WPSTable.h"
49
50
#include "LotusChart.h"
51
#include "LotusGraph.h"
52
#include "LotusSpreadsheet.h"
53
#include "LotusStyleManager.h"
54
55
#include "Lotus.h"
56
57
using namespace libwps;
58
59
//! Internal: namespace to define internal class of LotusParser
60
namespace LotusParserInternal
61
{
62
//! the font of a LotusParser
63
struct Font final : public WPSFont
64
{
65
  //! constructor
66
  explicit Font(libwps_tools_win::Font::Type type)
67
3.59k
    : WPSFont()
68
3.59k
    , m_type(type)
69
3.59k
  {
70
3.59k
  }
71
7.18k
  Font(Font const &)=default;
72
  ~Font() final;
73
  //! font encoding type
74
  libwps_tools_win::Font::Type m_type;
75
};
76
Font::~Font()
77
10.7k
{
78
10.7k
}
79
//! the state of LotusParser
80
struct State
81
{
82
  //! constructor
83
  State(libwps_tools_win::Font::Type fontType, char const *password)
84
182k
    : m_fontType(fontType)
85
182k
    , m_version(-1)
86
182k
    , m_isMacFile(false)
87
182k
    , m_inMainContentBlock(false)
88
182k
    , m_fontsMap()
89
182k
    , m_pageSpan()
90
182k
    , m_maxSheet(0)
91
182k
    , m_actualZoneId(0)
92
182k
    , m_actualZoneParentId(0)
93
182k
    , m_sheetZoneIdList()
94
182k
    , m_dataZoneIdToSheetZoneIdMap()
95
182k
    , m_linkIdToLinkMap()
96
182k
    , m_actualLevels()
97
182k
    , m_zone1Stack()
98
182k
    , m_sheetSubZoneOpened(0x20, false)
99
182k
    , m_actPage(0)
100
182k
    , m_numPages(0)
101
182k
    , m_metaData()
102
182k
    , m_password(password)
103
182k
    , m_isEncrypted(false)
104
182k
    , m_isDecoded(false)
105
182k
  {
106
182k
  }
107
  //! return the default font style
108
  libwps_tools_win::Font::Type getDefaultFontType() const
109
2.03M
  {
110
2.03M
    if (m_fontType != libwps_tools_win::Font::UNKNOWN)
111
140k
      return m_fontType;
112
1.89M
    return libwps_tools_win::Font::WIN3_WEUROPE;
113
2.03M
  }
114
115
  //! returns a default font (Courier12) with file's version to define the default encoding */
116
  WPSFont getDefaultFont() const
117
0
  {
118
0
    WPSFont res;
119
0
    if (m_version <= 2)
120
0
      res.m_name="Courier";
121
0
    else
122
0
      res.m_name="Times New Roman";
123
0
    res.m_size=12;
124
0
    return res;
125
0
  }
126
  //! returns the min and max cell
127
  void getLevels(WPSVec3i &minC, WPSVec3i &maxC) const
128
674k
  {
129
674k
    size_t numLevels=m_actualLevels.size();
130
2.69M
    for (size_t i=0; i<3; ++i)
131
2.02M
    {
132
2.02M
      if (i+1<numLevels)
133
1.29M
      {
134
1.29M
        minC[int(i)]=m_actualLevels[i+1][0];
135
1.29M
        maxC[int(i)]=m_actualLevels[i+1][1]-1;
136
1.29M
      }
137
726k
      else
138
726k
        minC[int(i)]=maxC[int(i)]=-1;
139
2.02M
    }
140
674k
  }
141
  //! returns a map dataZoneId to sheet final id
142
  std::map<int,int> getDataZoneIdToSheetIdMap() const
143
28.1k
  {
144
28.1k
    std::map<int,int> zoneIdToSheetMap;
145
72.2k
    for (size_t i=0; i<m_sheetZoneIdList.size(); ++i)
146
44.1k
      zoneIdToSheetMap[m_sheetZoneIdList[i]]=int(i);
147
28.1k
    std::map<int,int> res;
148
28.1k
    for (auto const &it : m_dataZoneIdToSheetZoneIdMap)
149
3.03k
    {
150
3.03k
      if (zoneIdToSheetMap.find(it.second)==zoneIdToSheetMap.end())
151
1.01k
      {
152
1.01k
        WPS_DEBUG_MSG(("LotusParserInternal::State::getDataZoneIdToSheetIdMap: can not find the sheet corresponding to %d\n", it.second));
153
1.01k
        continue;
154
1.01k
      }
155
2.01k
      res[zoneIdToSheetMap.find(it.second)->second]=it.first;
156
2.01k
    }
157
28.1k
    return res;
158
28.1k
  }
159
  //! returns a name corresponding to the actual level(for debugging)
160
  std::string getLevelsDebugName() const
161
907k
  {
162
907k
    std::stringstream s;
163
30.1M
    for (size_t i=0; i<m_actualLevels.size(); ++i)
164
29.2M
    {
165
29.2M
      auto const &level=m_actualLevels[i];
166
29.2M
      if (i==0 && level==Vec2i(0,0)) continue;
167
28.9M
      if (i<4)
168
2.41M
      {
169
2.41M
        char const *wh[]= {"Z", "T", "C", "R"};
170
2.41M
        s << wh[i];
171
2.41M
      }
172
26.5M
      else
173
26.5M
        s << "[F" << i << "]";
174
28.9M
      if (level[0]==level[1])
175
3.80M
        s << "_";
176
25.1M
      else if (level[0]==level[1]-1)
177
16.4M
        s << level[0];
178
8.71M
      else
179
8.71M
        s << level[0] << "x" << level[1]-1;
180
28.9M
    }
181
907k
    return s.str();
182
907k
  }
183
  //! returns a name corresponding to the zone1 stack(for debugging)
184
  std::string getZone1StackDebugName() const
185
111k
  {
186
111k
    if (m_zone1Stack.empty())
187
18.5k
      return "";
188
92.4k
    std::stringstream s;
189
92.4k
    s << "ids=[";
190
92.4k
    for (auto const &id : m_zone1Stack)
191
3.09M
      s << std::hex << id << std::dec << ",";
192
92.4k
    s << "],";
193
92.4k
    return s.str();
194
111k
  }
195
  //! the user font type
196
  libwps_tools_win::Font::Type m_fontType;
197
  //! the file version
198
  int m_version;
199
  //! flag to know if this is a mac file
200
  bool m_isMacFile;
201
  //! a flag used to know if we are in the main block or no
202
  bool m_inMainContentBlock;
203
  //! the fonts map
204
  std::map<int, Font> m_fontsMap;
205
  //! the actual document size
206
  WPSPageSpan m_pageSpan;
207
  //! the last sheet number
208
  int m_maxSheet;
209
  //! the actual zone id
210
  int m_actualZoneId;
211
  //! the actual zone parent id
212
  int m_actualZoneParentId;
213
  //! the list of sheet main zone id
214
  std::vector<int> m_sheetZoneIdList;
215
  //! a map to retrieve the sheet zone id from the data sheet zone id
216
  std::map<int,int> m_dataZoneIdToSheetZoneIdMap;
217
  //! a multimap link id to link zone
218
  std::multimap<int, LotusParser::Link> m_linkIdToLinkMap;
219
  //! the actual zone: (0,0), table list, col list, row list
220
  std::vector<Vec2i> m_actualLevels;
221
  //! a unknown Zone1 stack of increasing(?) numbers
222
  std::vector<unsigned long> m_zone1Stack;
223
  //! some sheet sub zones (SheetZone)
224
  std::vector<bool> m_sheetSubZoneOpened;
225
  int m_actPage /** the actual page*/, m_numPages /* the number of pages */;
226
  //! the metadata
227
  librevenge::RVNGPropertyList m_metaData;
228
229
  //! the password (if known)
230
  char const *m_password;
231
  //! true if the file is encrypted
232
  bool m_isEncrypted;
233
  //! true if the main stream has been decoded
234
  bool m_isDecoded;
235
private:
236
  State(State const &) = delete;
237
  State operator=(State const &) = delete;
238
};
239
240
}
241
242
// constructor, destructor
243
LotusParser::LotusParser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
244
                         libwps_tools_win::Font::Type encoding,
245
                         char const *password)
246
60.7k
  : WKSParser(input, header)
247
60.7k
  , m_listener()
248
60.7k
  , m_state(new LotusParserInternal::State(encoding, password))
249
60.7k
  , m_styleManager()
250
60.7k
  , m_chartParser()
251
60.7k
  , m_graphParser()
252
60.7k
  , m_spreadsheetParser()
253
60.7k
  , m_ole1Parser()
254
60.7k
{
255
60.7k
  m_styleManager.reset(new LotusStyleManager(*this));
256
60.7k
  m_chartParser.reset(new LotusChart(*this));
257
60.7k
  m_graphParser.reset(new LotusGraph(*this));
258
60.7k
  m_spreadsheetParser.reset(new LotusSpreadsheet(*this));
259
60.7k
}
260
261
LotusParser::~LotusParser()
262
60.7k
{
263
60.7k
}
264
265
int LotusParser::version() const
266
7.64M
{
267
7.64M
  return m_state->m_version;
268
7.64M
}
269
270
//////////////////////////////////////////////////////////////////////
271
// interface
272
//////////////////////////////////////////////////////////////////////
273
libwps_tools_win::Font::Type LotusParser::getDefaultFontType() const
274
2.03M
{
275
2.03M
  return m_state->getDefaultFontType();
276
2.03M
}
277
278
bool LotusParser::getFont(int id, WPSFont &font, libwps_tools_win::Font::Type &type) const
279
12.3k
{
280
12.3k
  if (m_state->m_fontsMap.find(id)==m_state->m_fontsMap.end())
281
9.32k
  {
282
9.32k
    WPS_DEBUG_MSG(("LotusParser::getFont: can not find font %d\n", id));
283
9.32k
    return false;
284
9.32k
  }
285
3.07k
  auto const &ft=m_state->m_fontsMap.find(id)->second;
286
3.07k
  font=ft;
287
3.07k
  type=ft.m_type;
288
3.07k
  return true;
289
12.3k
}
290
291
std::vector<LotusParser::Link> LotusParser::getLinksList(int lId) const
292
15.3k
{
293
15.3k
  std::vector<LotusParser::Link> res;
294
15.3k
  auto range = m_state->m_linkIdToLinkMap.equal_range(lId);
295
15.3k
  std::transform(range.first, range.second, std::back_inserter(res), [](std::pair<int,Link> const &element)
296
39.9k
  {
297
39.9k
    return element.second;
298
39.9k
  });
299
15.3k
  return res;
300
301
15.3k
}
302
303
bool LotusParser::hasGraphics(int sheetId) const
304
0
{
305
0
  return m_graphParser->hasGraphics(sheetId);
306
0
}
307
308
void LotusParser::sendGraphics(int sheetId)
309
2.27M
{
310
2.27M
  m_graphParser->sendGraphics(sheetId);
311
2.27M
}
312
313
bool LotusParser::getLeftTopPosition(Vec2i const &cell, int spreadsheet, Vec2f &pos) const
314
22.4k
{
315
22.4k
  return m_spreadsheetParser->getLeftTopPosition(cell, spreadsheet, pos);
316
22.4k
}
317
318
librevenge::RVNGString LotusParser::getSheetName(int id) const
319
42.8k
{
320
42.8k
  return m_spreadsheetParser->getSheetName(id);
321
42.8k
}
322
323
bool LotusParser::sendChart(int cId, WPSPosition const &pos, WPSGraphicStyle const &style)
324
4.52k
{
325
4.52k
  return m_chartParser->sendChart(cId, pos, style);
326
4.52k
}
327
328
bool LotusParser::updateEmbeddedObject(int id, WPSEmbeddedObject &object) const
329
212
{
330
212
  if (!m_ole1Parser)
331
0
  {
332
0
    WPS_DEBUG_MSG(("LotusParser::updateEmbeddedObject: can not find the ole1 parser\n"));
333
0
    return false;
334
0
  }
335
212
  return m_ole1Parser->updateEmbeddedObject(id, object);
336
212
}
337
338
//////////////////////////////////////////////////////////////////////
339
// parsing
340
//////////////////////////////////////////////////////////////////////
341
342
// main function to parse the document
343
void LotusParser::parse(librevenge::RVNGSpreadsheetInterface *documentInterface)
344
60.7k
{
345
60.7k
  RVNGInputStreamPtr input=getInput();
346
60.7k
  if (!input)
347
0
  {
348
0
    WPS_DEBUG_MSG(("LotusParser::parse: does not find main ole\n"));
349
0
    throw (libwps::ParseException());
350
0
  }
351
352
60.7k
  if (!checkHeader(nullptr)) throw(libwps::ParseException());
353
354
60.6k
  bool ok=false;
355
60.6k
  try
356
60.6k
  {
357
60.6k
    ascii().setStream(input);
358
60.6k
    ascii().open("MN0");
359
60.6k
    if (checkHeader(nullptr) && createZones())
360
28.1k
      createListener(documentInterface);
361
60.6k
    if (m_listener)
362
28.1k
    {
363
28.1k
      m_styleManager->updateState();
364
28.1k
      m_chartParser->updateState();
365
28.1k
      m_spreadsheetParser->updateState();
366
28.1k
      m_graphParser->updateState(m_state->getDataZoneIdToSheetIdMap(),
367
28.1k
                                 m_chartParser->getNameToChartIdMap());
368
369
28.1k
      m_chartParser->setListener(m_listener);
370
28.1k
      m_graphParser->setListener(m_listener);
371
28.1k
      m_spreadsheetParser->setListener(m_listener);
372
373
28.1k
      m_listener->startDocument();
374
2.30M
      for (int i=0; i<=m_state->m_maxSheet; ++i)
375
2.27M
        m_spreadsheetParser->sendSpreadsheet(i);
376
28.1k
      if (version()<=1 && !m_state->m_isMacFile && m_chartParser->getNumCharts())
377
516
      {
378
516
        std::vector<WPSColumnFormat> widths;
379
516
        WPSColumnFormat width(72.);
380
516
        width.m_numRepeat=20;
381
516
        widths.push_back(width);
382
516
        m_listener->openSheet(widths, "Charts");
383
516
        m_chartParser->sendCharts();
384
516
        m_listener->closeSheet();
385
516
      }
386
28.1k
      m_listener->endDocument();
387
28.1k
      m_listener.reset();
388
28.1k
      ok = true;
389
28.1k
    }
390
60.6k
  }
391
60.6k
  catch (libwps::PasswordException())
392
60.6k
  {
393
0
    ascii().reset();
394
0
    WPS_DEBUG_MSG(("LotusParser::parse: password exception catched when parsing MN0\n"));
395
0
    throw (libwps::PasswordException());
396
0
  }
397
60.6k
  catch (...)
398
60.6k
  {
399
247
    WPS_DEBUG_MSG(("LotusParser::parse: exception catched when parsing MN0\n"));
400
247
    throw (libwps::ParseException());
401
247
  }
402
403
60.4k
  ascii().reset();
404
60.4k
  if (!ok)
405
32.2k
    throw(libwps::ParseException());
406
60.4k
}
407
408
bool LotusParser::createListener(librevenge::RVNGSpreadsheetInterface *interface)
409
28.1k
{
410
28.1k
  std::vector<WPSPageSpan> pageList;
411
28.1k
  WPSPageSpan ps(m_state->m_pageSpan);
412
28.1k
  int numPages=m_state->m_maxSheet+1;
413
28.1k
  if (numPages<=0) numPages=1;
414
2.30M
  for (int i=0; i<numPages; ++i) pageList.push_back(ps);
415
28.1k
  m_listener.reset(new WKSContentListener(pageList, interface));
416
28.1k
  m_listener->setMetaData(m_state->m_metaData);
417
28.1k
  return true;
418
28.1k
}
419
420
////////////////////////////////////////////////////////////
421
// low level
422
////////////////////////////////////////////////////////////
423
424
////////////////////////////////////////////////////////////
425
// read the header
426
////////////////////////////////////////////////////////////
427
bool LotusParser::checkHeader(WPSHeader *header, bool strict)
428
121k
{
429
121k
  m_state.reset(new LotusParserInternal::State(m_state->m_fontType, m_state->m_password));
430
121k
  std::shared_ptr<WPSStream> mainStream(new WPSStream(getInput(), ascii()));
431
121k
  if (!checkHeader(mainStream, true, strict))
432
143
    return false;
433
121k
  if (header)
434
0
  {
435
0
    header->setMajorVersion(uint8_t(100+m_state->m_version));
436
0
    header->setCreator(libwps::WPS_LOTUS);
437
0
    header->setKind(libwps::WPS_SPREADSHEET);
438
0
    header->setNeedEncoding(true);
439
0
    header->setIsEncrypted(m_state->m_isEncrypted);
440
0
  }
441
121k
  return true;
442
121k
}
443
444
bool LotusParser::checkHeader(std::shared_ptr<WPSStream> stream, bool mainStream, bool strict)
445
121k
{
446
121k
  RVNGInputStreamPtr input = stream->m_input;
447
121k
  libwps::DebugFile &ascFile=stream->m_ascii;
448
121k
  libwps::DebugStream f;
449
450
121k
  if (!stream->checkFilePosition(12))
451
22
  {
452
22
    WPS_DEBUG_MSG(("LotusParser::checkHeader: file is too short\n"));
453
22
    return false;
454
22
  }
455
456
121k
  input->seek(0,librevenge::RVNG_SEEK_SET);
457
121k
  auto firstOffset = int(libwps::readU8(input));
458
121k
  auto type = int(libwps::read8(input));
459
121k
  auto val=int(libwps::read16(input));
460
121k
  f << "FileHeader:";
461
121k
  if (firstOffset == 0 && type == 0 && val==0x1a)
462
121k
  {
463
121k
    m_state->m_version=1;
464
121k
    f << "DOS,";
465
121k
  }
466
34
  else
467
34
  {
468
34
    WPS_DEBUG_MSG(("LotusParser::checkHeader: find unexpected first data\n"));
469
34
    return false;
470
34
  }
471
121k
  val=int(libwps::readU16(input));
472
121k
  if (!mainStream)
473
51
  {
474
51
    if (val!=0x8007)
475
3
    {
476
3
      WPS_DEBUG_MSG(("LotusParser::checkHeader: find unknown lotus file format\n"));
477
3
      return false;
478
3
    }
479
48
    f << "lotus123[FMT],";
480
48
  }
481
121k
  else if (val>=0x1000 && val<=0x1005)
482
121k
  {
483
121k
    WPS_DEBUG_MSG(("LotusParser::checkHeader: find lotus123 file\n"));
484
121k
    m_state->m_version=(val-0x1000)+1;
485
121k
    f << "lotus123[" << m_state->m_version << "],";
486
121k
  }
487
#ifdef DEBUG
488
  else if (val==0x8007)
489
  {
490
    WPS_DEBUG_MSG(("LotusParser::checkHeader: find lotus file format, sorry parsing this file is only implemented for debugging, not output will be created\n"));
491
    f << "lotus123[FMT],";
492
  }
493
#endif
494
92
  else
495
92
  {
496
92
    WPS_DEBUG_MSG(("LotusParser::checkHeader: unknown lotus 123 header\n"));
497
92
    return false;
498
92
  }
499
500
121k
  input->seek(0, librevenge::RVNG_SEEK_SET);
501
121k
  if (strict)
502
0
  {
503
0
    for (int i=0; i < 4; ++i)
504
0
    {
505
0
      if (!readZone(stream)) return false;
506
0
      if (m_state->m_isEncrypted) break;
507
0
    }
508
0
  }
509
121k
  ascFile.addPos(0);
510
121k
  ascFile.addNote(f.str().c_str());
511
121k
  return true;
512
121k
}
513
514
bool LotusParser::createZones()
515
60.6k
{
516
60.6k
  RVNGInputStreamPtr input=getInput();
517
60.6k
  if (!input)
518
0
  {
519
0
    WPS_DEBUG_MSG(("LotusParser::createZones: can not find the main input\n"));
520
0
    return false;
521
0
  }
522
60.6k
  m_styleManager->cleanState();
523
60.6k
  m_chartParser->cleanState();
524
60.6k
  m_graphParser->cleanState();
525
60.6k
  m_spreadsheetParser->cleanState();
526
527
60.6k
  int const vers=version();
528
529
60.6k
  std::shared_ptr<WPSStream> mainStream(new WPSStream(input, ascii()));
530
60.6k
  if (vers>=3)
531
49.4k
  {
532
49.4k
    m_ole1Parser.reset(new WPSOLE1Parser(mainStream));
533
49.4k
    m_ole1Parser->createZones();
534
49.4k
    std::shared_ptr<WPSStream> wkStream=m_ole1Parser->getStreamForName(vers==3 ? "WK3" : "123");
535
49.4k
    if (wkStream)
536
317
    {
537
317
      if (!readZones(wkStream)) return false;
538
301
      m_ole1Parser->updateMetaData(m_state->m_metaData, getDefaultFontType());
539
301
      if (vers==3)
540
271
      {
541
271
        std::shared_ptr<WPSStream> fmStream=m_ole1Parser->getStreamForName("FM3");
542
271
        if (fmStream) readZones(fmStream);
543
271
      }
544
301
      return true;
545
317
    }
546
49.4k
  }
547
60.3k
  input->seek(0, librevenge::RVNG_SEEK_SET);
548
60.3k
  if (!readZones(mainStream)) return false;
549
28.1k
  if (vers<=2) parseFormatStream();
550
28.1k
  return true;
551
60.3k
}
552
553
bool LotusParser::parseFormatStream()
554
6.03k
{
555
6.03k
  RVNGInputStreamPtr file=getFileInput();
556
6.03k
  if (!file || !file->isStructured()) return false;
557
558
160
  RVNGInputStreamPtr formatInput(file->getSubStreamByName("FM3"));
559
160
  if (!formatInput)
560
104
  {
561
104
    WPS_DEBUG_MSG(("LotusParser::parseFormatStream: can not find the format stream\n"));
562
104
    return false;
563
104
  }
564
565
56
  std::shared_ptr<WPSStream> formatStream(new WPSStream(formatInput));
566
56
  formatInput->seek(0, librevenge::RVNG_SEEK_SET);
567
56
  formatStream->m_ascii.open("FM3");
568
56
  formatStream->m_ascii.setStream(formatInput);
569
56
  if (!checkHeader(formatStream, false, false))
570
8
  {
571
8
    WPS_DEBUG_MSG(("LotusParser::parseFormatStream: can not read format stream\n"));
572
8
    return false;
573
8
  }
574
48
  return readZones(formatStream);
575
56
}
576
577
bool LotusParser::readZones(std::shared_ptr<WPSStream> stream)
578
60.7k
{
579
60.7k
  if (!stream)
580
0
  {
581
0
    WPS_DEBUG_MSG(("LotusParser::readZones: can not find the stream\n"));
582
0
    return false;
583
0
  }
584
60.7k
  RVNGInputStreamPtr &input = stream->m_input;
585
60.7k
  libwps::DebugFile &ascFile=stream->m_ascii;
586
587
60.7k
  bool mainDataRead=false;
588
  // data, format and ?
589
76.2k
  for (int wh=0; wh<2; ++wh)
590
75.9k
  {
591
75.9k
    if (input->isEnd())
592
185
      break;
593
594
6.66M
    while (readZone(stream))
595
6.58M
    {
596
6.58M
      if (m_state->m_isEncrypted && !m_state->m_isDecoded)
597
94
        throw(libwps::PasswordException());
598
6.58M
    }
599
600
    //
601
    // look for ending
602
    //
603
75.6k
    long pos = input->tell();
604
75.6k
    if (!stream->checkFilePosition(pos+4))
605
17.3k
      break;
606
58.3k
    auto type = int(libwps::readU16(input)); // 1
607
58.3k
    auto length = int(libwps::readU16(input));
608
58.3k
    if (type==1 && length==0)
609
15.4k
    {
610
15.4k
      ascFile.addPos(pos);
611
15.4k
      ascFile.addNote("Entries(EOF)");
612
15.4k
      if (!mainDataRead)
613
15.1k
        mainDataRead=m_state->m_inMainContentBlock;
614
      // end of block, look for other blocks
615
15.4k
      continue;
616
15.4k
    }
617
42.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
618
42.9k
    break;
619
58.3k
  }
620
621
607k
  while (!input->isEnd())
622
601k
  {
623
601k
    long pos=input->tell();
624
601k
    if (pos>=stream->m_eof) break;
625
601k
    auto id = int(libwps::readU8(input));
626
601k
    auto type = int(libwps::readU8(input));
627
601k
    auto sz = long(libwps::readU16(input));
628
601k
    if ((type>0x2a) || sz<0 || !stream->checkFilePosition(pos+4+sz))
629
53.8k
    {
630
53.8k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
631
53.8k
      break;
632
53.8k
    }
633
547k
    libwps::DebugStream f;
634
547k
    f << "Entries(UnknZon" << std::hex << id << "):";
635
547k
    ascFile.addPos(pos);
636
547k
    ascFile.addNote(f.str().c_str());
637
547k
    input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
638
547k
  }
639
640
60.6k
  if (!input->isEnd() && input->tell()<stream->m_eof)
641
53.8k
  {
642
53.8k
    ascFile.addPos(input->tell());
643
53.8k
    ascFile.addNote("Entries(Unknown)");
644
53.8k
  }
645
646
60.6k
  return mainDataRead || m_spreadsheetParser->hasSomeSpreadsheetData();
647
60.7k
}
648
649
bool LotusParser::readZone(std::shared_ptr<WPSStream> &stream)
650
6.66M
{
651
6.66M
  if (!stream)
652
0
    return false;
653
6.66M
  RVNGInputStreamPtr &input = stream->m_input;
654
6.66M
  libwps::DebugFile &ascFile=stream->m_ascii;
655
6.66M
  libwps::DebugStream f;
656
6.66M
  long pos = input->tell();
657
6.66M
  auto id = int(libwps::readU8(input));
658
6.66M
  auto type = int(libwps::readU8(input));
659
6.66M
  auto sz = long(libwps::readU16(input));
660
6.66M
  long endPos=pos+4+sz;
661
6.66M
  if ((type>0x2a) || sz<0 || !stream->checkFilePosition(endPos))
662
54.1k
  {
663
54.1k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
664
54.1k
    return false;
665
54.1k
  }
666
6.60M
  f << "Entries(Lotus";
667
6.60M
  if (type) f << std::hex << type << std::dec << "A";
668
6.60M
  f << std::hex << id << std::dec << "E):";
669
6.60M
  bool ok = true, isParsed = false, needWriteInAscii = false;
670
6.60M
  int val;
671
6.60M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
672
6.60M
  int const vers=version();
673
6.60M
  switch (type)
674
6.60M
  {
675
1.88M
  case 0:
676
1.88M
    switch (id)
677
1.88M
    {
678
115k
    case 0:
679
115k
    {
680
115k
      if (sz!=26)
681
4.36k
      {
682
4.36k
        ok=false;
683
4.36k
        break;
684
4.36k
      }
685
111k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
686
111k
      f.str("");
687
111k
      f << "Entries(BOF):";
688
111k
      val=int(libwps::readU16(input));
689
111k
      m_state->m_inMainContentBlock=false;
690
111k
      if (val==0x8007)
691
6.85k
        f << "FMT,";
692
104k
      else if (val>=0x1000 && val <= 0x1005)
693
75.7k
      {
694
75.7k
        m_state->m_inMainContentBlock=true;
695
75.7k
        f << "version=" << (val-0x1000) << ",";
696
75.7k
      }
697
28.5k
      else
698
28.5k
        f << "#version=" << std::hex << val << std::dec << ",";
699
555k
      for (int i=0; i<4; ++i)   // f0=4, f3 a small number
700
444k
      {
701
444k
        val=int(libwps::read16(input));
702
444k
        if (val)
703
332k
          f << "f" << i << "=" << val << ",";
704
444k
      }
705
111k
      val=int(libwps::readU8(input));
706
111k
      if (m_state->m_inMainContentBlock)
707
75.7k
      {
708
75.7k
        m_spreadsheetParser->setLastSpreadsheetId(val);
709
75.7k
        m_state->m_maxSheet=val;
710
75.7k
      }
711
111k
      if (val && m_state->m_inMainContentBlock)
712
57.3k
        f << "max[sheet]=" << val << ",";
713
53.8k
      else if (val)
714
27.0k
        f << "max[fmt]=" << val << ",";
715
716
888k
      for (int i=0; i<7; ++i)   // g0/g1=0..fd, g2=0|4, g3=0|5|7|1e|20|30, g4=0|8c|3d, g5=1|10, g6=2|a
717
777k
      {
718
777k
        val=int(libwps::readU8(input));
719
777k
        if (val)
720
499k
          f << "g" << i << "=" << std::hex << val << std::dec << ",";
721
777k
      }
722
111k
      isParsed=needWriteInAscii=true;
723
111k
      break;
724
115k
    }
725
15.5k
    case 0x1: // EOF
726
15.5k
      ok = false;
727
15.5k
      break;
728
4.97k
    case 0x2:
729
4.97k
      m_state->m_isEncrypted=true;
730
4.97k
      if (sz==16)
731
4.82k
      {
732
4.82k
        input->seek(pos+4, librevenge::RVNG_SEEK_SET);
733
4.82k
        std::vector<uint8_t> fileKeys;
734
82.0k
        for (int i=0; i<16; ++i)
735
77.1k
        {
736
77.1k
          unsigned char c(libwps::readU8(input));
737
77.1k
          fileKeys.push_back(uint8_t(c));
738
77.1k
        }
739
4.82k
        isParsed=needWriteInAscii=true;
740
4.82k
        if (!m_state->m_isDecoded)
741
1.28k
        {
742
1.28k
          static uint8_t const defValues[]=
743
1.28k
          {
744
1.28k
            0xb9,0x5f, 0xd7,0x31, 0xdb,0x75, 9,0x72,
745
1.28k
            0x5d,0x85, 0x32,0x11, 0x5,0x11, 0x58,0
746
1.28k
          };
747
1.28k
          uint16_t key;
748
1.28k
          std::vector<uint8_t> keys;
749
1.28k
          if (m_state->m_password && libwps::encodeLotusPassword(m_state->m_password, key, keys, defValues))
750
1.28k
          {
751
1.28k
            bool passwordOk=fileKeys.size()==keys.size();
752
1.28k
            if (passwordOk)
753
1.28k
            {
754
              /* check that the password is ok, normally,
755
                 all keys must be equal excepted:
756
                 - fileKey7=key7^(key>>8),
757
                 - and fileKey13=key13^key.
758
759
                 This also means that knowing fileKeys,
760
                 it is possible to retrieve the password
761
                 if it is short enough.
762
              */
763
1.28k
              int numSame=0;
764
21.7k
              for (size_t c=0; c < fileKeys.size(); ++c)
765
20.5k
              {
766
20.5k
                if (keys[c]==fileKeys[c])
767
43
                  ++numSame;
768
20.5k
              }
769
1.28k
              passwordOk=numSame>=14;
770
1.28k
              if (!passwordOk)
771
1.28k
              {
772
1.28k
                WPS_DEBUG_MSG(("LotusParser::parse: the password seems bad\n"));
773
1.28k
              }
774
1.28k
            }
775
1.28k
            if (!passwordOk)
776
1.28k
            {
777
1.28k
              keys=retrievePasswordKeys(fileKeys);
778
1.28k
              passwordOk=keys.size()==16;
779
1.28k
            }
780
1.28k
            RVNGInputStreamPtr newInput;
781
1.28k
            if (passwordOk) newInput=decodeStream(input, stream->m_eof, keys);
782
1.28k
            if (newInput)
783
1.18k
            {
784
              // let's replace the current input by the decoded input
785
1.18k
              m_state->m_isDecoded=true;
786
1.18k
              stream->m_input=newInput;
787
1.18k
              stream->m_ascii.setStream(newInput);
788
1.18k
            }
789
1.28k
          }
790
1.28k
        }
791
4.82k
      }
792
153
      else
793
153
      {
794
153
        WPS_DEBUG_MSG(("LotusParser::parse: find unexpected password field\n"));
795
153
        throw (libwps::PasswordException());
796
153
      }
797
4.82k
      f.str("");
798
4.82k
      f << "Entries(Password):";
799
4.82k
      break;
800
3.98k
    case 0x3:
801
3.98k
      if (sz!=6)
802
118
      {
803
118
        ok=false;
804
118
        break;
805
118
      }
806
3.87k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
807
15.4k
      for (int i=0; i<3; ++i)   // f0=1, f2=1|32
808
11.6k
      {
809
11.6k
        val=int(libwps::read16(input));
810
11.6k
        if (val)
811
7.84k
          f << "f" << i << "=" << val << ",";
812
11.6k
      }
813
3.87k
      isParsed=needWriteInAscii=true;
814
3.87k
      break;
815
2.88k
    case 0x4:
816
2.88k
      if (sz!=28)
817
318
      {
818
318
        ok=false;
819
318
        break;
820
318
      }
821
2.56k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
822
7.69k
      for (int i=0; i<2; ++i)   // f0=1|3
823
5.12k
      {
824
5.12k
        val=int(libwps::read8(input));
825
5.12k
        if (val!=1)
826
838
          f << "f" << i << "=" << val << ",";
827
5.12k
      }
828
7.69k
      for (int i=0; i<2; ++i)   // f2=1-3, f1=0|1
829
5.12k
      {
830
5.12k
        val=int(libwps::read16(input));
831
5.12k
        if (val)
832
2.94k
          f << "f" << i+1 << "=" << val << ",";
833
5.12k
      }
834
2.56k
      isParsed=needWriteInAscii=true;
835
2.56k
      break;
836
5.77k
    case 0x5:
837
5.77k
    {
838
5.77k
      f.str("");
839
5.77k
      f << "Entries(SheetUnknA):";
840
5.77k
      if (sz!=16)
841
58
      {
842
58
        ok=false;
843
58
        break;
844
58
      }
845
5.71k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
846
5.71k
      val=int(libwps::readU8(input));
847
5.71k
      if (val)
848
3.13k
        f << "sheet[id]=" << val << ",";
849
5.71k
      val=int(libwps::read8(input)); // always 0?
850
5.71k
      if (val)
851
279
        f << "f0=" << val << ",";
852
853
5.71k
      isParsed=needWriteInAscii=true;
854
5.71k
      break;
855
5.77k
    }
856
5.97k
    case 0x6: // one by sheet
857
5.97k
      f.str("");
858
5.97k
      f << "Entries(SheetUnknB):";
859
5.97k
      if (sz!=5)
860
72
      {
861
72
        ok=false;
862
72
        break;
863
72
      }
864
5.90k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
865
5.90k
      val=int(libwps::readU8(input));
866
5.90k
      if (val)
867
3.23k
        f << "sheet[id]=" << val << ",";
868
29.5k
      for (int i=0; i<4; ++i)   // f0=0, f2=0|1, f3=7-9
869
23.6k
      {
870
23.6k
        val=int(libwps::read8(input)); // always 0?
871
23.6k
        if (val)
872
12.7k
          f << "f" << i << "=" << val << ",";
873
23.6k
      }
874
5.90k
      isParsed=needWriteInAscii=true;
875
5.90k
      break;
876
3.19k
    case 0x7:
877
3.19k
      ok=isParsed=m_spreadsheetParser->readColumnSizes(stream);
878
3.19k
      break;
879
13.1k
    case 0x9:
880
13.1k
      ok=isParsed=m_spreadsheetParser->readCellName(stream);
881
13.1k
      break;
882
79.5k
    case 0xa:
883
79.5k
      ok=isParsed=readLinkZone(stream);
884
79.5k
      break;
885
4.82k
    case 0xb: // 0,1,-1
886
4.99k
    case 0x1e: // always with 0
887
9.04k
    case 0x21:
888
9.04k
      if (sz!=1)
889
65
      {
890
65
        ok=false;
891
65
        break;
892
65
      }
893
8.98k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
894
8.98k
      val=int(libwps::read8(input));
895
8.98k
      if (val==1)
896
5
        f << "true,";
897
8.97k
      else if (val)
898
1.14k
        f << "val=" << val << ",";
899
8.98k
      break;
900
2.65k
    case 0xc: // find 0 or 4 int with value 0|1|ff
901
2.65k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
902
16.2k
      for (long i=0; i<sz; ++i)
903
13.6k
      {
904
13.6k
        val=int(libwps::read8(input));
905
13.6k
        if (val==1) f << "f" << i << ",";
906
13.2k
        else if (val) f << "f" << i << "=" << val << ",";
907
13.6k
      }
908
2.65k
      isParsed=needWriteInAscii=true;
909
2.65k
      break;
910
4.48k
    case 0xe:
911
4.48k
      if (sz<30)
912
39
      {
913
39
        ok=false;
914
39
        break;
915
39
      }
916
4.44k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
917
137k
      for (int i=0; i<30; ++i)   // f7=0|f, f8=0|60, f9=0|54, f17=80, f18=0|ff, f19=3f|40, f26=0|f8, f27=80|ff, f28=b|c,f29=40
918
133k
      {
919
133k
        val=int(libwps::read8(input));
920
133k
        if (val) f << "f" << i << "=" << val << ",";
921
133k
      }
922
4.44k
      if (sz>=32)
923
4.33k
      {
924
4.33k
        val=int(libwps::read16(input)); // always 1?
925
4.33k
        if (val!=1) f << "f30=" << val << ",";
926
4.33k
      }
927
4.44k
      isParsed=needWriteInAscii=true;
928
4.44k
      break;
929
4.44k
    case 0xf:
930
4.44k
      if (sz<0x56)
931
29
      {
932
29
        ok=false;
933
29
        break;
934
29
      }
935
4.41k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
936
4.41k
      val=int(libwps::read8(input)); // 1|2
937
4.41k
      if (val!=1) f << "f0=" << val << ",";
938
17.6k
      for (int i=0; i<3; ++i)
939
13.2k
      {
940
13.2k
        long actPos=input->tell();
941
13.2k
        std::string name("");
942
24.5k
        for (int j=0; j<16; ++j)
943
24.4k
        {
944
24.4k
          auto c=char(libwps::readU8(input));
945
24.4k
          if (!c) break;
946
11.3k
          name += c;
947
11.3k
        }
948
13.2k
        if (!name.empty())
949
2.17k
          f << "str" << i << "=" << name << ",";
950
13.2k
        input->seek(actPos+16, librevenge::RVNG_SEEK_SET);
951
13.2k
      }
952
79.4k
      for (int i=0; i<17; ++i)   // f2=f11=1,f15=0|1, f16=0|2, f17=0|1|2
953
75.0k
      {
954
75.0k
        val=int(libwps::read8(input));
955
75.0k
        if (val) f << "f" << i+1 << "=" << val << ",";
956
75.0k
      }
957
48.5k
      for (int i=0; i<10; ++i)   // g0=0|1,g1=Ø|1, g2=4|a, g3=4c|50|80, g4=g5=0|2, g6=42, g7=41|4c, g8=3c|42|59
958
44.1k
      {
959
44.1k
        val=int(libwps::read16(input));
960
44.1k
        if (val) f << "g" << i << "=" << val << ",";
961
44.1k
      }
962
4.41k
      isParsed=needWriteInAscii=true;
963
4.41k
      break;
964
6.93k
    case 0x10: // CHECKME
965
6.93k
    {
966
6.93k
      if (sz<3)
967
27
      {
968
27
        ok=false;
969
27
        break;
970
27
      }
971
6.90k
      f.str("");
972
6.90k
      f << "Entries(Macro):";
973
6.90k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
974
20.7k
      for (int i=0; i<2; ++i)
975
13.8k
      {
976
13.8k
        val=int(libwps::readU8(input));
977
13.8k
        if (val) f << "f" << i << "=" << val << ",";
978
13.8k
      }
979
6.90k
      std::string data("");
980
14.3k
      for (long i=2; i<sz; ++i)
981
13.2k
      {
982
13.2k
        auto c=char(libwps::readU8(input));
983
13.2k
        if (!c) break;
984
7.46k
        data += c;
985
7.46k
      }
986
6.90k
      if (!data.empty())
987
2.30k
        f << "data=" << data << ",";
988
6.90k
      if (input->tell()!=endPos && input->tell()+1!=endPos)
989
1.42k
      {
990
1.42k
        WPS_DEBUG_MSG(("LotusParser::readZone: the string zone %d seems too short\n", id));
991
1.42k
        f << "###";
992
1.42k
      }
993
6.90k
      isParsed=needWriteInAscii=true;
994
6.90k
      break;
995
6.93k
    }
996
18.5k
    case 0x11:
997
18.5k
      ok=isParsed=m_chartParser->readChart(stream);
998
18.5k
      break;
999
118k
    case 0x12:
1000
118k
      ok=isParsed=m_chartParser->readChartName(stream);
1001
118k
      break;
1002
256k
    case 0x13:
1003
256k
      isParsed=m_spreadsheetParser->readRowFormats(stream);
1004
256k
      break;
1005
352
    case 0x15:
1006
3.55k
    case 0x1d:
1007
3.55k
      if (sz!=4)
1008
2.00k
      {
1009
2.00k
        WPS_DEBUG_MSG(("LotusParser::readZone: size of zone%d seems bad\n", id));
1010
2.00k
        f << "###";
1011
2.00k
        break;
1012
2.00k
      }
1013
1.54k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1014
1.54k
      val=int(libwps::read16(input)); // small number 6-c maybe a style
1015
1.54k
      if (val) f << "f0=" << val << ",";
1016
4.62k
      for (int i=0; i<2; ++i)   // zone15: f1=3, f2=2-5, zone 1d: always 0
1017
3.08k
      {
1018
3.08k
        val=int(libwps::readU8(input));
1019
3.08k
        if (val) f << "f" << i+1 << "=" << val << ",";
1020
3.08k
      }
1021
1.54k
      isParsed=needWriteInAscii=true;
1022
1.54k
      break;
1023
46.5k
    case 0x16: // the cell text
1024
55.7k
    case 0x17: // double10 cell
1025
68.8k
    case 0x18: // uint16 double cell
1026
83.6k
    case 0x19: // double10+formula
1027
102k
    case 0x1a: // text formula result cell
1028
162k
    case 0x25: // uint32 double cell
1029
167k
    case 0x26: // comment cell
1030
171k
    case 0x27: // double8 cell
1031
211k
    case 0x28: // double8+formula
1032
211k
      ok=isParsed=m_spreadsheetParser->readCell(stream);
1033
211k
      break;
1034
583k
    case 0x1b:
1035
583k
      isParsed=readDataZone(stream);
1036
583k
      break;
1037
2.45k
    case 0x1c: // always 00002d000000
1038
2.45k
      if (sz!=6)
1039
1.35k
      {
1040
1.35k
        WPS_DEBUG_MSG(("LotusParser::readZone: size of zone%d seems bad\n", id));
1041
1.35k
        f << "###";
1042
1.35k
        break;
1043
1.35k
      }
1044
1.10k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1045
7.72k
      for (int i=0; i<6; ++i)   // some int
1046
6.62k
      {
1047
6.62k
        val=int(libwps::readU8(input));
1048
6.62k
        if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1049
6.62k
      }
1050
1.10k
      isParsed=needWriteInAscii=true;
1051
1.10k
      break;
1052
46.8k
    case 0x1f:
1053
46.8k
      isParsed=ok=m_spreadsheetParser->readColumnDefinition(stream);
1054
46.8k
      break;
1055
8.23k
    case 0x23:
1056
8.23k
      isParsed=ok=m_spreadsheetParser->readSheetName(stream);
1057
8.23k
      break;
1058
    // case 13: big structure
1059
1060
    //
1061
    // format:
1062
    //
1063
2.38k
    case 0x93: // 4
1064
4.80k
    case 0x96: // 0 or FF
1065
6.85k
    case 0x97: // 5F
1066
8.23k
    case 0x98: // 0|2|3
1067
12.7k
    case 0x99: // 0|4 or FF
1068
15.4k
    case 0x9c: // 0
1069
19.7k
    case 0xa3: // 0 or FF
1070
21.7k
    case 0xce: // 1
1071
22.5k
    case 0xcf: // 1
1072
24.9k
    case 0xd0: // 1
1073
24.9k
      if (m_state->m_inMainContentBlock) break;
1074
14.0k
      f.str("");
1075
14.0k
      f << "Entries(FMTByte" << std::hex << id << std::dec << "Z):";
1076
14.0k
      if (sz!=1)
1077
1.73k
      {
1078
1.73k
        f << "###";
1079
1.73k
        break;
1080
1.73k
      }
1081
12.3k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1082
12.3k
      val=int(libwps::readU8(input));
1083
12.3k
      if (val==0xFF) f << "true,";
1084
9.79k
      else if (val) f << "val=" << val << ",";
1085
12.3k
      isParsed=needWriteInAscii=true;
1086
12.3k
      break;
1087
108
    case 0x87: // always with 0000
1088
563
    case 0x88: // always with 0000
1089
2.56k
    case 0x8e: // with 57|64
1090
8.49k
    case 0x9a: // with 800
1091
10.4k
    case 0x9b: // with 720
1092
13.5k
    case 0xcd: // with 57|64
1093
13.5k
      if (m_state->m_inMainContentBlock) break;
1094
8.09k
      f.str("");
1095
8.09k
      f << "Entries(FMTInt" << std::hex << id << std::dec << "Z):";
1096
8.09k
      if (sz!=2)
1097
760
      {
1098
760
        f << "###";
1099
760
        break;
1100
760
      }
1101
7.33k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1102
7.33k
      val=int(libwps::readU16(input));
1103
7.33k
      if (val) f << "val=" << val << ",";
1104
7.33k
      isParsed=needWriteInAscii=true;
1105
7.33k
      break;
1106
1.70k
    case 0x86:
1107
1.86k
    case 0x89:
1108
3.53k
    case 0xba: // header?
1109
33.6k
    case 0xbb: // footer?
1110
33.6k
    {
1111
33.6k
      if (m_state->m_inMainContentBlock) break;
1112
29.2k
      f.str("");
1113
29.2k
      if (id==0x86)
1114
10
        f << "Entries(FMTPrinter):";
1115
29.2k
      else if (id==0x89)
1116
19
        f << "Entries(FMTPrinter):shortName,";
1117
29.2k
      else if (id==0xba)
1118
1.42k
        f << "Entries(FMTHeader):";
1119
27.8k
      else
1120
27.8k
        f << "Entries(FMTFooter):";
1121
1122
29.2k
      if (sz<1)
1123
1.38k
      {
1124
1.38k
        f << "###";
1125
1.38k
        break;
1126
1.38k
      }
1127
27.9k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1128
27.9k
      std::string text;
1129
191k
      for (long i=0; i<sz; ++i) text+=char(libwps::readU8(input));
1130
27.9k
      f << text << ",";
1131
27.9k
      isParsed=needWriteInAscii=true;
1132
27.9k
      break;
1133
29.2k
    }
1134
22.6k
    case 0xae:
1135
22.6k
      if (m_state->m_inMainContentBlock) break;
1136
19.2k
      isParsed=m_styleManager->readFMTFontName(stream);
1137
19.2k
      break;
1138
2.60k
    case 0xaf:
1139
4.94k
    case 0xb1:
1140
4.94k
      if (m_state->m_inMainContentBlock) break;
1141
3.88k
      isParsed=m_styleManager->readFMTFontSize(stream);
1142
3.88k
      break;
1143
4.65k
    case 0xb0:
1144
4.65k
      if (m_state->m_inMainContentBlock) break;
1145
4.05k
      isParsed=m_styleManager->readFMTFontId(stream);
1146
4.05k
      break;
1147
2.04k
    case 0xb6:
1148
2.04k
      if (m_state->m_inMainContentBlock) break;
1149
1.72k
      isParsed=readFMTStyleName(stream);
1150
1.72k
      break;
1151
1.88k
    case 0xb8: // always 0101
1152
1.88k
      if (m_state->m_inMainContentBlock) break;
1153
1.32k
      f.str("");
1154
1.32k
      f << "Entries(FMTInts" << std::hex << id << std::dec << "Z):";
1155
1.32k
      if (sz!=2)
1156
414
      {
1157
414
        f << "###";
1158
414
        break;
1159
414
      }
1160
910
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1161
2.73k
      for (int i=0; i<2; ++i)
1162
1.82k
      {
1163
1.82k
        val=int(libwps::readU8(input));
1164
1.82k
        if (val!=1) f << "f" << i << "=" << val << ",";
1165
1.82k
      }
1166
910
      isParsed=needWriteInAscii=true;
1167
910
      break;
1168
7.64k
    case 0xc3:
1169
7.64k
      if (m_state->m_inMainContentBlock) break;
1170
6.90k
      isParsed=ok=m_spreadsheetParser->readSheetHeader(stream);
1171
6.90k
      break;
1172
470
    case 0xc4: // with 0-8, 5c-15c
1173
1.08k
    case 0xcb: // unsure, seems appeared together a group with 1,1
1174
1.08k
      if (m_state->m_inMainContentBlock) break;
1175
523
      f.str("");
1176
523
      if (id==0xcb)
1177
188
        f << "Entries(FMTGrpData):";
1178
335
      else
1179
335
        f << "Entries(FMTInt2" << std::hex << id << std::dec << "Z):";
1180
523
      if (sz!=4)
1181
428
      {
1182
428
        f << "###";
1183
428
        break;
1184
428
      }
1185
95
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1186
285
      for (int i=0; i<2; ++i)
1187
190
      {
1188
190
        val=int(libwps::readU16(input));
1189
190
        if (val) f << "f" << i << "=" << val << ",";
1190
190
      }
1191
95
      isParsed=needWriteInAscii=true;
1192
95
      break;
1193
26.1k
    case 0xc5:
1194
26.1k
      if (m_state->m_inMainContentBlock) break;
1195
24.1k
      isParsed=ok=m_spreadsheetParser->readExtraRowFormats(stream);
1196
24.1k
      break;
1197
14.4k
    case 0xc9:
1198
14.4k
      if (m_state->m_inMainContentBlock) break;
1199
13.2k
      isParsed=ok=m_graphParser->readZoneBeginC9(stream);
1200
13.2k
      break;
1201
46.2k
    case 0xca: // a graphic
1202
46.2k
      if (m_state->m_inMainContentBlock) break;
1203
44.8k
      isParsed=ok=m_graphParser->readGraphic(stream);
1204
44.8k
      break;
1205
31.0k
    case 0xcc: // frame of a graphic
1206
31.0k
      if (m_state->m_inMainContentBlock) break;
1207
29.2k
      isParsed=ok=m_graphParser->readFrame(stream);
1208
29.2k
      break;
1209
714
    case 0xd1: // the textbox data
1210
714
      if (m_state->m_inMainContentBlock) break;
1211
519
      isParsed=ok=m_graphParser->readTextBoxDataD1(stream);
1212
519
      break;
1213
3.19k
    case 0xb7:
1214
3.19k
      if (m_state->m_inMainContentBlock) break;
1215
2.90k
      isParsed=ok=m_graphParser->readFMTPictName(stream);
1216
2.90k
      break;
1217
1.29k
    case 0xbf: // variable size, can also contain a name, ...
1218
4.34k
    case 0xc0: // size 1a: dim + a list of id?
1219
5.83k
    case 0xc2: // size 22: a list of id?
1220
5.83k
      if (m_state->m_inMainContentBlock) break;
1221
4.02k
      f.str("");
1222
4.02k
      f << "Entries(FMTPict" << std::hex << id << std::dec << "):";
1223
4.02k
      break;
1224
115k
    default:
1225
115k
      input->seek(pos+4, librevenge::RVNG_SEEK_SET);
1226
115k
      if (!m_state->m_inMainContentBlock && id>=0x80)
1227
18.6k
      {
1228
18.6k
        f.str("");
1229
18.6k
        f << "Entries(FMT" << std::hex << id << std::dec << "E):";
1230
18.6k
      }
1231
115k
      break;
1232
1.88M
    }
1233
1.88M
    break;
1234
1.88M
  case 1:
1235
1.46M
    if (vers<=2)
1236
87
    {
1237
87
      ok=false;
1238
87
      break;
1239
87
    }
1240
1.46M
    ok = isParsed=readZone1(stream);
1241
1.46M
    break;
1242
129k
  case 2:
1243
129k
    if (vers<=2)
1244
54
    {
1245
54
      ok=false;
1246
54
      break;
1247
54
    }
1248
129k
    ok = isParsed=readSheetZone(stream);
1249
129k
    break;
1250
858k
  case 3:
1251
858k
    if (vers<=2)
1252
25
    {
1253
25
      ok=false;
1254
25
      break;
1255
25
    }
1256
858k
    ok = isParsed=m_graphParser->readGraphZone(stream, m_state->m_actualZoneParentId); // sheetZone.Data0
1257
858k
    break;
1258
341k
  case 4:
1259
341k
    if (vers<=2)
1260
35
    {
1261
35
      ok=false;
1262
35
      break;
1263
35
    }
1264
341k
    ok = isParsed=readZone4(stream);
1265
341k
    break;
1266
30.2k
  case 5:
1267
30.2k
    if (vers<=2)
1268
16
    {
1269
16
      ok=false;
1270
16
      break;
1271
16
    }
1272
30.2k
    ok = isParsed=readChartZone(stream);
1273
30.2k
    break;
1274
83.0k
  case 6:
1275
83.0k
    if (vers<=2)
1276
22
    {
1277
22
      ok=false;
1278
22
      break;
1279
22
    }
1280
83.0k
    ok = isParsed=readRefZone(stream);
1281
83.0k
    break;
1282
36.6k
  case 7:
1283
36.6k
    if (vers<=2)
1284
29
    {
1285
29
      ok=false;
1286
29
      break;
1287
29
    }
1288
36.6k
    ok = isParsed=readZone7(stream);
1289
36.6k
    break;
1290
1.52M
  case 8:
1291
1.52M
    if (vers<=2)
1292
57
    {
1293
57
      ok=false;
1294
57
      break;
1295
57
    }
1296
1.52M
    ok = isParsed=readZone8(stream);
1297
1.52M
    break;
1298
76.2k
  case 0xa:
1299
76.2k
    if (vers<=2)
1300
11
    {
1301
11
      ok=false;
1302
11
      break;
1303
11
    }
1304
76.2k
    ok = isParsed=readVersionZone(stream);
1305
76.2k
    break;
1306
179k
  default:
1307
    // checkme: maybe <5 is ok
1308
179k
    if (vers<=2)
1309
286
    {
1310
286
      ok=false;
1311
286
      break;
1312
286
    }
1313
179k
    ok = isParsed=readZoneV3(stream);
1314
179k
    break;
1315
6.60M
  }
1316
6.60M
  if (!ok)
1317
21.2k
  {
1318
21.2k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1319
21.2k
    return false;
1320
21.2k
  }
1321
6.58M
  if (sz && input->tell()!=pos && input->tell()!=endPos)
1322
300k
    ascFile.addDelimiter(input->tell(),'|');
1323
6.58M
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1324
6.58M
  if (!isParsed || needWriteInAscii)
1325
379k
  {
1326
379k
    ascFile.addPos(pos);
1327
379k
    ascFile.addNote(f.str().c_str());
1328
379k
  }
1329
6.58M
  return true;
1330
6.60M
}
1331
1332
bool LotusParser::readDataZone(std::shared_ptr<WPSStream> stream)
1333
583k
{
1334
583k
  if (!stream) return false;
1335
583k
  RVNGInputStreamPtr &input = stream->m_input;
1336
583k
  libwps::DebugFile &ascFile=stream->m_ascii;
1337
583k
  libwps::DebugStream f;
1338
583k
  long pos = input->tell();
1339
583k
  auto type = int(libwps::readU16(input));
1340
583k
  auto sz = long(libwps::readU16(input));
1341
583k
  long endPos=pos+4+sz;
1342
583k
  if (type!=0x1b || sz<2)
1343
2.52k
  {
1344
2.52k
    WPS_DEBUG_MSG(("LotusParser::readDataZone: the zone seems odd\n"));
1345
2.52k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1346
2.52k
    return false;
1347
2.52k
  }
1348
581k
  type = int(libwps::readU16(input));
1349
581k
  f << "Entries(Data" << std::hex << type << std::dec << "E):";
1350
581k
  bool isParsed=false, needWriteInAscii=false;
1351
581k
  sz-=2;
1352
581k
  int val;
1353
581k
  switch (type)
1354
581k
  {
1355
  //
1356
  // mac windows
1357
  //
1358
4.72k
  case 0x7d2:
1359
4.72k
  {
1360
4.72k
    f.str("");
1361
4.72k
    f << "Entries(WindowsMacDef):";
1362
4.72k
    if (sz<26)
1363
171
    {
1364
171
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the windows definition seems bad\n"));
1365
171
      f << "###";
1366
171
      break;
1367
171
    }
1368
4.55k
    val=int(libwps::readU8(input));
1369
4.55k
    if (val) f << "id=" << val << ",";
1370
4.55k
    val=int(libwps::read8(input)); // find 0|2
1371
4.55k
    if (val) f << "f0=" << val << ",";
1372
4.55k
    int dim[4];
1373
22.7k
    for (int i=0; i<4; ++i)
1374
18.2k
    {
1375
18.2k
      dim[i]=int(libwps::read16(input));
1376
18.2k
      val=int(libwps::read16(input));
1377
18.2k
      if (!val) continue;
1378
3.29k
      if (i)
1379
1.85k
        f << "num[split]=" << val << ",";
1380
1.44k
      else
1381
1.44k
        f << "dim" << i << "[h]=" << val << ",";
1382
3.29k
    }
1383
4.55k
    f << "dim=" << WPSBox2i(Vec2i(dim[0],dim[1]),Vec2i(dim[2],dim[3])) << ",";
1384
40.9k
    for (int i=0; i<8; ++i)   // small value or 100
1385
36.4k
    {
1386
36.4k
      val=int(libwps::read8(input));
1387
36.4k
      if (val) f << "f" << i+1 << "=" << val << ",";
1388
36.4k
    }
1389
4.55k
    isParsed=needWriteInAscii=true;
1390
4.55k
    auto remain=int(sz-26);
1391
4.55k
    if (remain<=1) break;
1392
617
    std::string name("");
1393
10.6k
    for (int i=0; i<remain; ++i)
1394
9.99k
      name+=char(libwps::readU8(input));
1395
617
    f << name << ",";
1396
617
    break;
1397
4.55k
  }
1398
4.47k
  case 0x7d3:
1399
4.47k
  {
1400
4.47k
    f.str("");
1401
4.47k
    f << "Entries(WindowsMacSplit):";
1402
4.47k
    if (sz<24)
1403
71
    {
1404
71
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the windows split seems bad\n"));
1405
71
      f << "###";
1406
71
      break;
1407
71
    }
1408
4.40k
    val=int(libwps::readU8(input));
1409
4.40k
    if (val) f << "id=" << val << ",";
1410
4.40k
    val=int(libwps::readU8(input));
1411
4.40k
    if (val) f << "split[id]=" << val << ",";
1412
17.6k
    for (int i=0; i<3; ++i)   // 0 or 1
1413
13.2k
    {
1414
13.2k
      val=int(libwps::read8(input));
1415
13.2k
      if (val) f << "f" << i+1 << "=" << val << ",";
1416
13.2k
    }
1417
4.40k
    int dim[4];
1418
22.0k
    for (int i=0; i<4; ++i)
1419
17.6k
    {
1420
17.6k
      val=int(libwps::read16(input));
1421
17.6k
      dim[i]=int(libwps::read16(input));
1422
17.6k
      if (val) f << "dim" << i <<"[h]=" << val << ",";
1423
17.6k
    }
1424
4.40k
    f << "dim=" << WPSBox2i(Vec2i(dim[0],dim[1]),Vec2i(dim[2],dim[3])) << ",";
1425
17.6k
    for (int i=0; i<3; ++i)
1426
13.2k
    {
1427
13.2k
      static int const expected[]= {0,-1,25};
1428
13.2k
      val=int(libwps::read8(input));
1429
13.2k
      if (val!=expected[i]) f << "g" << i << "=" << val << ",";
1430
13.2k
    }
1431
4.40k
    isParsed=needWriteInAscii=true;
1432
4.40k
    break;
1433
4.47k
  }
1434
1.75k
  case 0x7d4:
1435
1.75k
  {
1436
1.75k
    f.str("");
1437
1.75k
    f << "Entries(WindowsMacUnkn0)";
1438
1.75k
    if (sz<5)
1439
271
    {
1440
271
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the windows unkn0 seems bad\n"));
1441
271
      f << "###";
1442
271
      break;
1443
271
    }
1444
7.43k
    for (int i=0; i<4; ++i)   // always 2,1,1,2 ?
1445
5.94k
    {
1446
5.94k
      val=int(libwps::read8(input));
1447
5.94k
      if (val) f << "f" << i << "=" << val << ",";
1448
5.94k
    }
1449
1.48k
    isParsed=needWriteInAscii=true;
1450
1.48k
    auto remain=int(sz-4);
1451
1.48k
    if (remain<=1) break;
1452
1.41k
    std::string name("");
1453
14.0k
    for (int i=0; i<remain; ++i) // always LMBCS 1.2?
1454
12.6k
      name+=char(libwps::readU8(input));
1455
1.41k
    f << name << ",";
1456
1.41k
    break;
1457
1.48k
  }
1458
397
  case 0x7d5: // frequently followed by Lotus13 block and SheetRow, ...
1459
397
    f.str("");
1460
397
    f << "Entries(SheetBegin):";
1461
397
    if (sz!=11)
1462
54
    {
1463
54
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the sheet begin zone seems bad\n"));
1464
54
      f << "###";
1465
54
      break;
1466
54
    }
1467
    // time to update the style manager state
1468
343
    m_styleManager->updateState();
1469
1470
343
    val=int(libwps::readU8(input));
1471
343
    if (val) f << "sheet[id]=" << val << ",";
1472
    // then always 0a3fff00ffff508451ff ?
1473
343
    isParsed=needWriteInAscii=true;
1474
343
    break;
1475
1.24k
  case 0x7d7:
1476
1.24k
    isParsed=m_spreadsheetParser->readRowSizes(stream, endPos);
1477
1.24k
    break;
1478
1.92k
  case 0x7d8:
1479
3.89k
  case 0x7d9:
1480
3.89k
  {
1481
3.89k
    f.str("");
1482
3.89k
    int dataSz=type==0x7d8 ? 1 : 2;
1483
3.89k
    if (type==0x7d8)
1484
1.92k
      f << "Entries(ColMacBreak):";
1485
1.96k
    else
1486
1.96k
      f << "Entries(RowMacBreak):";
1487
1488
3.89k
    if (sz<4 || (sz%dataSz))
1489
84
    {
1490
84
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the page mac break seems bad\n"));
1491
84
      f << "###";
1492
84
      break;
1493
84
    }
1494
3.81k
    val=int(libwps::readU8(input));
1495
3.81k
    if (val) f << "sheet[id]=" << val << ",";
1496
3.81k
    val=int(libwps::readU8(input)); // always 0
1497
3.81k
    if (val) f << "f0=" << val << ",";
1498
3.81k
    f << "break=[";
1499
3.81k
    auto N=int((sz-2)/dataSz);
1500
17.7k
    for (int i=0; i<N; ++i)
1501
13.9k
    {
1502
13.9k
      if (dataSz==1)
1503
9.05k
        f << int(libwps::readU8(input)) << ",";
1504
4.89k
      else
1505
4.89k
        f << libwps::readU16(input) << ",";
1506
13.9k
    }
1507
3.81k
    f << "],";
1508
3.81k
    isParsed=needWriteInAscii=true;
1509
3.81k
    break;
1510
3.89k
  }
1511
1512
  //
1513
  // selection
1514
  //
1515
4.16k
  case 0xbb8:
1516
4.16k
    f.str("");
1517
4.16k
    f << "Entries(MacSelect):";
1518
1519
4.16k
    if (sz!=18)
1520
107
    {
1521
107
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the mac selection seems bad\n"));
1522
107
      f << "###";
1523
107
      break;
1524
107
    }
1525
16.2k
    for (int i=0; i<3; ++i)   // f0=0, f1=f2=1
1526
12.1k
    {
1527
12.1k
      val=int(libwps::read16(input));
1528
12.1k
      if (val) f << "f" << i << "=" << val << ",";
1529
12.1k
    }
1530
16.2k
    for (int i=0; i<3; ++i)
1531
12.1k
    {
1532
12.1k
      auto row=int(libwps::readU16(input));
1533
12.1k
      auto sheet=int(libwps::readU8(input));
1534
12.1k
      auto col=int(libwps::readU8(input));
1535
12.1k
      f << "C" << col << "-" << row;
1536
12.1k
      if (sheet) f << "[" << sheet << "],";
1537
2.84k
      else f << ",";
1538
12.1k
    }
1539
4.05k
    isParsed=needWriteInAscii=true;
1540
4.05k
    break;
1541
1542
  //
1543
  // style
1544
  //
1545
23.0k
  case 0xfa0: // wk3
1546
23.0k
    isParsed=m_styleManager->readFontStyleA0(stream, endPos);
1547
23.0k
    break;
1548
3.35k
  case 0xfa1: // wk6-wk9, with size 26
1549
3.35k
    f.str("");
1550
3.35k
    f << "Entries(FontStyle):";
1551
3.35k
    break;
1552
51.9k
  case 0xfaa: // 10Style
1553
58.9k
  case 0xfab:
1554
58.9k
    isParsed=m_styleManager->readLineStyle(stream, endPos, type==0xfaa ? 0 : 1);
1555
58.9k
    break;
1556
78.9k
  case 0xfb4: // 20 Style
1557
78.9k
    isParsed=m_styleManager->readColorStyle(stream, endPos);
1558
78.9k
    break;
1559
3.90k
  case 0xfbe: // 30Style
1560
3.90k
    isParsed=m_styleManager->readFormatStyle(stream, endPos);
1561
3.90k
    break;
1562
15.0k
  case 0xfc8: //
1563
15.0k
    isParsed=m_styleManager->readGraphicStyle(stream, endPos);
1564
15.0k
    break;
1565
8.56k
  case 0xfc9: // 40Style: lotus 123
1566
8.56k
    isParsed=m_styleManager->readGraphicStyleC9(stream, endPos);
1567
8.56k
    break;
1568
42.5k
  case 0xfd2: // 50Style
1569
42.5k
    isParsed=m_styleManager->readCellStyleD2(stream, endPos);
1570
42.5k
    break;
1571
17.2k
  case 0xfdc:
1572
17.2k
    isParsed=readMacFontName(stream, endPos);
1573
17.2k
    break;
1574
7.92k
  case 0xfe6: // wk5
1575
7.92k
    if (version()==3)
1576
3.53k
      isParsed=m_styleManager->readCellStyleE6(stream, endPos);
1577
4.38k
    else if (version()>3)
1578
4.12k
      isParsed=m_styleManager->readStyleE6(stream, endPos);
1579
7.92k
    break;
1580
9.38k
  case 0xff0: // wk5
1581
9.38k
    isParsed=m_styleManager->readFontStyleF0(stream, endPos);
1582
9.38k
    break;
1583
1584
  // 0xfe6: X X CeId : 60Style
1585
1586
  //
1587
  // graphic
1588
  //
1589
1590
5.91k
  case 0x2328: // begin(wk3mac)
1591
5.91k
    isParsed=m_graphParser->readZoneBegin(stream, endPos);
1592
5.91k
    break;
1593
5.24k
  case 0x2332: // line(wk3mac)
1594
7.97k
  case 0x2346: // rect, rectoval, rect(wk3mac)
1595
12.3k
  case 0x2350: // arc(wk3mac)
1596
12.5k
  case 0x2352: // rect shadow(wk3mac)
1597
22.2k
  case 0x23f0: // frame(wk3mac)
1598
22.2k
    isParsed=m_graphParser->readZoneData(stream, endPos, type);
1599
22.2k
    break;
1600
1.83k
  case 0x23fa: // textbox data(wk3mac)
1601
1.83k
    isParsed=m_graphParser->readTextBoxData(stream, endPos);
1602
1.83k
    break;
1603
1604
8.76k
  case 0x2710:   // chart data(wk3mac)
1605
8.76k
  {
1606
8.76k
    int chartId=-1;
1607
8.76k
    isParsed=m_chartParser->readMacHeader(stream, endPos, chartId);
1608
8.76k
    if (isParsed && chartId>=0)
1609
8.49k
      m_graphParser->setChartId(chartId);
1610
8.76k
    break;
1611
12.5k
  }
1612
18.8k
  case 0x2774:
1613
18.8k
    isParsed=m_chartParser->readMacPlacement(stream, endPos);
1614
18.8k
    break;
1615
9.72k
  case 0x277e:
1616
9.72k
    isParsed=m_chartParser->readMacLegend(stream, endPos);
1617
9.72k
    break;
1618
9.47k
  case 0x2788:
1619
9.47k
    isParsed=m_chartParser->readMacPlotArea(stream, endPos);
1620
9.47k
    break;
1621
21.5k
  case 0x27d8:
1622
21.5k
    isParsed=m_chartParser->readMacAxis(stream, endPos);
1623
21.5k
    break;
1624
26.4k
  case 0x27e2:
1625
26.4k
    isParsed=m_chartParser->readMacSerie(stream, endPos);
1626
26.4k
    break;
1627
  // case 0x27ec: always 030000
1628
3.43k
  case 0x2846: // only 3d
1629
3.43k
    isParsed=m_chartParser->readMacFloor(stream, endPos);
1630
3.43k
    break;
1631
6.66k
  case 0x2904: // only if manual
1632
6.66k
    isParsed=m_chartParser->readMacPosition(stream, endPos);
1633
6.66k
    break;
1634
1635
  //
1636
  // chart
1637
  //
1638
1639
8.74k
  case 0x2a30: // plot area style?
1640
8.74k
    isParsed=m_chartParser->readPlotArea(stream, endPos);
1641
8.74k
    break;
1642
52.2k
  case 0x2a31: // serie style
1643
52.2k
    isParsed=m_chartParser->readSerie(stream, endPos);
1644
52.2k
    break;
1645
2.92k
  case 0x2a32: // serie name
1646
2.92k
    isParsed=m_chartParser->readSerieName(stream, endPos);
1647
2.92k
    break;
1648
4.94k
  case 0x2a33: // serie width
1649
4.94k
    isParsed=m_chartParser->readSerieWidth(stream, endPos);
1650
4.94k
    break;
1651
2.06k
  case 0x2a34: // serie of font, before 2a35
1652
2.06k
    isParsed=m_chartParser->readFontsStyle(stream, endPos);
1653
2.06k
    break;
1654
2.50k
  case 0x2a35: // list of frames styles
1655
2.50k
    isParsed=m_chartParser->readFramesStyle(stream, endPos);
1656
2.50k
    break;
1657
  //
1658
  // mac pict
1659
  //
1660
52
  case 0x240e:
1661
52
    isParsed=m_graphParser->readPictureDefinition(stream, endPos);
1662
52
    break;
1663
248
  case 0x2410:
1664
248
    isParsed=m_graphParser->readPictureData(stream, endPos);
1665
248
    break;
1666
1667
  //
1668
  // mac printer
1669
  //
1670
1.73k
  case 0x2af8:
1671
1.73k
    isParsed=readDocumentInfoMac(stream, endPos);
1672
1.73k
    break;
1673
1.18k
  case 0x2afa:
1674
1.18k
    f.str("");
1675
1.18k
    f << "Entries(PrinterMacUnkn1):";
1676
1.18k
    if (sz!=3)
1677
203
    {
1678
203
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the printer unkn1 seems bad\n"));
1679
203
      f << "###";
1680
203
      break;
1681
203
    }
1682
3.90k
    for (int i=0; i<3; ++i)
1683
2.93k
    {
1684
2.93k
      val=int(libwps::readU8(input));
1685
2.93k
      static int const expected[]= {0x1f, 0xe0, 0/*or 1*/};
1686
2.93k
      if (val!=expected[i])
1687
263
        f << "f" << i << "=" << val << ",";
1688
2.93k
    }
1689
977
    isParsed=needWriteInAscii=true;
1690
977
    break;
1691
1.85k
  case 0x2afb:
1692
1.85k
  {
1693
1.85k
    f.str("");
1694
1.85k
    f << "Entries(PrinterMacName):";
1695
1.85k
    if (sz<3)
1696
20
    {
1697
20
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the printername seems bad\n"));
1698
20
      f << "###";
1699
20
      break;
1700
20
    }
1701
1.83k
    val=int(libwps::read16(input));
1702
1.83k
    if (val!=20) f << "f0=" << val << ",";
1703
1.83k
    std::string name("");
1704
32.7k
    for (long i=4; i<sz; ++i)
1705
31.2k
    {
1706
31.2k
      auto c=char(libwps::readU8(input));
1707
31.2k
      if (!c) break;
1708
30.8k
      name+=c;
1709
30.8k
    }
1710
1.83k
    f << name << ",";
1711
1.83k
    isParsed=needWriteInAscii=true;
1712
1.83k
    break;
1713
1.85k
  }
1714
1.25k
  case 0x2afc:
1715
1.25k
    f.str("");
1716
1.25k
    f << "Entries(PrintMacInfo):";
1717
1.25k
    if (sz<120)
1718
7
    {
1719
7
      WPS_DEBUG_MSG(("LotusParser::readDataZone: the printinfo seems bad\n"));
1720
7
      f << "###";
1721
7
      break;
1722
7
    }
1723
1.24k
    isParsed=needWriteInAscii=true;
1724
1.24k
    break;
1725
1726
6.77k
  case 0x32e7:
1727
6.77k
    isParsed=m_styleManager->readMenuStyleE7(stream, endPos);
1728
6.77k
    break;
1729
1730
  // 32e7: related to style ?
1731
543
  case 0x36b0:
1732
543
    isParsed=m_spreadsheetParser->readSheetName1B(stream, endPos);
1733
543
    break;
1734
1735
  //
1736
  // 4268, 4269
1737
  //
1738
1739
123
  case 0x4a38:
1740
123
    f.str("");
1741
123
    f << "Entries(LinkUnkA):";
1742
123
    break;
1743
122
  case 0x4a39:
1744
122
    f.str("");
1745
122
    f << "Entries(LinkUnkB):";
1746
122
    break;
1747
340
  case 0x6590:
1748
340
    isParsed=m_spreadsheetParser->readNote(stream, endPos);
1749
340
    break;
1750
1751
68.9k
  default:
1752
68.9k
    break;
1753
581k
  }
1754
581k
  if (!isParsed || needWriteInAscii)
1755
96.5k
  {
1756
96.5k
    ascFile.addPos(pos);
1757
96.5k
    ascFile.addNote(f.str().c_str());
1758
96.5k
  }
1759
581k
  if (input->tell()!=endPos)
1760
175k
    ascFile.addDelimiter(input->tell(),'|');
1761
581k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1762
581k
  return true;
1763
581k
}
1764
1765
bool LotusParser::readZoneV3(std::shared_ptr<WPSStream> stream)
1766
179k
{
1767
179k
  if (!stream) return false;
1768
179k
  RVNGInputStreamPtr &input = stream->m_input;
1769
179k
  libwps::DebugFile &ascFile=stream->m_ascii;
1770
179k
  libwps::DebugStream f;
1771
179k
  long pos = input->tell();
1772
179k
  auto type = int(libwps::readU16(input));
1773
179k
  auto sz = long(libwps::readU16(input));
1774
179k
  long endPos=pos+4+sz;
1775
179k
  if (sz<0 || !stream->checkFilePosition(endPos))
1776
0
  {
1777
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1778
0
    return false;
1779
0
  }
1780
179k
  f << "Entries(Data" << std::hex << type << std::dec << "N):";
1781
179k
  ascFile.addPos(pos);
1782
179k
  ascFile.addNote(f.str().c_str());
1783
179k
  if (input->tell()!=endPos && input->tell()!=pos)
1784
90.4k
    ascFile.addDelimiter(input->tell(),'|');
1785
179k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1786
179k
  return true;
1787
179k
}
1788
1789
bool LotusParser::readZone1(std::shared_ptr<WPSStream> stream)
1790
1.46M
{
1791
1.46M
  if (!stream) return false;
1792
1.46M
  RVNGInputStreamPtr &input = stream->m_input;
1793
1.46M
  libwps::DebugFile &ascFile=stream->m_ascii;
1794
1.46M
  libwps::DebugStream f;
1795
1.46M
  long pos = input->tell();
1796
1.46M
  auto id = int(libwps::readU8(input));
1797
1.46M
  if (libwps::readU8(input) != 1)
1798
0
  {
1799
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1800
0
    return false;
1801
0
  }
1802
1.46M
  auto sz = long(libwps::readU16(input));
1803
1.46M
  long endPos=pos+4+sz;
1804
1.46M
  if (sz<0 || !stream->checkFilePosition(endPos))
1805
0
  {
1806
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1807
0
    return false;
1808
0
  }
1809
1.46M
  f << "Entries(Zone1):";
1810
1.46M
  int val;
1811
1.46M
  bool isParsed=false;
1812
1.46M
  switch (id)
1813
1.46M
  {
1814
102k
  case 0: // list of ids all between 1-N
1815
176k
  case 3: // always follow an id zone, with some value between 0 and N
1816
211k
  case 0xb: // always follow a level[close] zone, with some value between 0 and N, meaning unsure...
1817
211k
    f << (id==0 ? "id=" : id==3 ? "parent[id]," : "parent2[id],");
1818
211k
    if (sz!=4)
1819
73.8k
    {
1820
73.8k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone %d\n", id));
1821
73.8k
      f << "###";
1822
73.8k
      break;
1823
73.8k
    }
1824
137k
    val=int(libwps::readU32(input));
1825
137k
    if (val)
1826
131k
    {
1827
131k
      if (id==3)
1828
49.3k
        m_state->m_actualZoneParentId=val;
1829
131k
      f << "Z" << val << ",";
1830
131k
    }
1831
137k
    if (id==0) m_state->m_actualZoneId=val;
1832
137k
    break;
1833
507k
  case 4:
1834
507k
    f << "stack1[open],";
1835
507k
    if (sz!=4)
1836
445k
    {
1837
445k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone 4\n"));
1838
445k
      f << "###";
1839
445k
      break;
1840
445k
    }
1841
    // 01[XX][YY]00 where Y is a small even number
1842
61.7k
    m_state->m_zone1Stack.push_back(libwps::readU32(input));
1843
61.7k
    f << m_state->getZone1StackDebugName();
1844
61.7k
    break;
1845
93.2k
  case 5:
1846
93.2k
    f << "stack1[close],";
1847
93.2k
    if (sz!=4)
1848
43.9k
    {
1849
43.9k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone 5\n"));
1850
43.9k
      f << "###";
1851
43.9k
      break;
1852
43.9k
    }
1853
49.2k
    else
1854
49.2k
    {
1855
49.2k
      unsigned long lVal=libwps::readU32(input);
1856
49.2k
      if (m_state->m_zone1Stack.empty() || m_state->m_zone1Stack.back()!=lVal)
1857
22.6k
      {
1858
22.6k
        WPS_DEBUG_MSG(("LotusParser::readZone1: the value seems bad for zone 5\n"));
1859
22.6k
        f << "###val=" << std::hex << lVal << ",";
1860
22.6k
      }
1861
49.2k
      if (!m_state->m_zone1Stack.empty()) m_state->m_zone1Stack.pop_back();
1862
49.2k
      f << m_state->getZone1StackDebugName();
1863
49.2k
    }
1864
49.2k
    break;
1865
  // level 1=table, 2=col, 3=row
1866
195k
  case 0x6: // no data
1867
195k
    f << "level[open],";
1868
195k
    m_state->m_actualLevels.push_back(Vec2i(0,0));
1869
195k
    f << "[" << m_state->getLevelsDebugName() << "],";
1870
195k
    break;
1871
189k
  case 0x7: // no data
1872
189k
    f << "level[close]";
1873
189k
    if (m_state->m_actualLevels.empty())
1874
81.6k
    {
1875
81.6k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the level seems bad\n"));
1876
81.6k
      f << "###";
1877
81.6k
      break;
1878
81.6k
    }
1879
108k
    else
1880
108k
      m_state->m_actualLevels.pop_back();
1881
108k
    f << "[" << m_state->getLevelsDebugName() << "],";
1882
108k
    break;
1883
3.24k
  case 0x9: // appear one time at the beginning of the file, pos~8
1884
3.24k
    f << "dimension,";
1885
3.24k
    if (sz!=20)
1886
674
    {
1887
674
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone 9\n"));
1888
674
      f << "###";
1889
674
      break;
1890
674
    }
1891
2.57k
    int dim[4];
1892
10.3k
    for (int &i : dim) i=int(libwps::read32(input));
1893
2.57k
    f << "dim=" << WPSBox2i(Vec2i(dim[0],dim[1]), Vec2i(dim[2],dim[3])) << ",";
1894
7.72k
    for (int i=0; i<2; ++i)   // always 1,0
1895
5.15k
    {
1896
5.15k
      val=int(libwps::readU16(input));
1897
5.15k
      if (val!=1-i) f << "f" << i << "=" << val << ",";
1898
5.15k
    }
1899
2.57k
    break;
1900
28.4k
  case 0xa:   // appear one time at the beginning of the file, pos=3
1901
28.4k
  {
1902
28.4k
    f << "typea,";
1903
28.4k
    if (sz<24 || (sz%8)!=0)
1904
24.4k
    {
1905
24.4k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone a\n"));
1906
24.4k
      f << "###";
1907
24.4k
      break;
1908
24.4k
    }
1909
48.8k
    for (int i=0; i<11; ++i)   // f0=cd92|cebd|1cc8, f1=e|f
1910
44.7k
    {
1911
44.7k
      val=int(libwps::readU16(input));
1912
44.7k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1913
44.7k
    }
1914
4.07k
    auto N=int(libwps::readU16(input));
1915
4.07k
    f << "N=" << N << ",";
1916
4.07k
    if (24+N*8!=sz)
1917
1.12k
    {
1918
1.12k
      WPS_DEBUG_MSG(("LotusParser::readZone1: the N value seems bad for zone a\n"));
1919
1.12k
      f << "###";
1920
1.12k
      break;
1921
1.12k
    }
1922
7.17k
    for (int i=0; i<N; ++i)
1923
4.23k
    {
1924
4.23k
      f << "unk" << i << "=[";
1925
21.1k
      for (int j=0; j<4; ++j)   // f0=12|18|24|800, f1=15e|2913, f2=4|37|41
1926
16.9k
      {
1927
16.9k
        val=int(libwps::readU16(input));
1928
16.9k
        if (val) f << "f" << j << "=" << std::hex << val << std::dec << ",";
1929
16.9k
      }
1930
4.23k
      f << "],";
1931
4.23k
    }
1932
2.94k
    break;
1933
4.07k
  }
1934
11.8k
  case 0xc: // one by file, after a level[close], before a level[open]
1935
11.8k
    f << "typec,";
1936
11.8k
    if (sz!=4)
1937
922
    {
1938
922
      WPS_DEBUG_MSG(("LotusParser::readZone1: the size seems bad for zone c\n"));
1939
922
      f << "###";
1940
922
      break;
1941
922
    }
1942
32.8k
    for (int i=0; i<2; ++i)   // always 0
1943
21.8k
    {
1944
21.8k
      val=int(libwps::readU16(input));
1945
21.8k
      if (val) f << "f" << i << "=" << val << ",";
1946
21.8k
    }
1947
10.9k
    break;
1948
150k
  case 0xd: // after a line: the coordinate, after a texbox the text
1949
150k
    isParsed=m_graphParser->readGraphDataZone(stream,endPos);
1950
150k
    break;
1951
1952
11.2k
  case 0xe: // no data, one by file
1953
11.2k
    f << "styles[def]=begin,";
1954
11.2k
    break;
1955
1.90k
  case 0xf: // no data, one by file
1956
1.90k
    f << "styles[def]=end,";
1957
1.90k
    break;
1958
58.6k
  default:
1959
58.6k
    f << "type=" << std::hex << id << std::dec << ",";
1960
58.6k
    break;
1961
1.46M
  }
1962
1.46M
  if (!isParsed)
1963
1.31M
  {
1964
1.31M
    ascFile.addPos(pos);
1965
1.31M
    ascFile.addNote(f.str().c_str());
1966
1.31M
  }
1967
1.46M
  if (input->tell()!=endPos && input->tell()!=pos)
1968
65.0k
    ascFile.addDelimiter(input->tell(),'|');
1969
1.46M
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1970
1.46M
  return true;
1971
1.46M
}
1972
1973
bool LotusParser::readSheetZone(std::shared_ptr<WPSStream> stream)
1974
129k
{
1975
129k
  if (!stream) return false;
1976
129k
  RVNGInputStreamPtr &input = stream->m_input;
1977
129k
  libwps::DebugFile &ascFile=stream->m_ascii;
1978
129k
  libwps::DebugStream f;
1979
129k
  long pos = input->tell();
1980
129k
  auto id = int(libwps::readU8(input));
1981
129k
  if (libwps::readU8(input) != 2)
1982
0
  {
1983
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1984
0
    return false;
1985
0
  }
1986
129k
  auto sz = long(libwps::readU16(input));
1987
129k
  long endPos=pos+4+sz;
1988
129k
  if (sz<0 || !stream->checkFilePosition(endPos))
1989
0
  {
1990
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1991
0
    return false;
1992
0
  }
1993
129k
  f << "Entries(SheetZone):";
1994
129k
  int val;
1995
129k
  switch (id)
1996
129k
  {
1997
14.4k
  case 0: // appear at the end of the file: pos~end-3
1998
14.4k
    f << "rList,";
1999
14.4k
    if (sz!=10)
2000
12.9k
    {
2001
12.9k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 200\n"));
2002
12.9k
      f << "###";
2003
12.9k
      break;
2004
12.9k
    }
2005
1.53k
    m_state->m_actualZoneParentId=0;
2006
1.53k
    f << "sheet[root]=Z" << int(libwps::readU32(input)) << ",";
2007
6.12k
    for (int i=0; i<3; ++i)   // f1=57
2008
4.59k
    {
2009
4.59k
      val=int(libwps::readU16(input));
2010
4.59k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2011
4.59k
    }
2012
1.53k
    break;
2013
2.81k
  case 1: // root of all sheet node
2014
2.81k
    f << "root,";
2015
2.81k
    if (sz!=78)
2016
920
    {
2017
920
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 201\n"));
2018
920
      f << "###";
2019
920
      break;
2020
920
    }
2021
20.8k
    for (int i=0; i<10; ++i)   // f0=5|7, f6:big number, f8:big number
2022
18.9k
    {
2023
18.9k
      val=int(libwps::readU16(input));
2024
18.9k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2025
18.9k
    }
2026
47.4k
    for (int i=0; i<24; ++i)   // 0
2027
45.5k
    {
2028
45.5k
      val=int(libwps::readU16(input));
2029
45.5k
      if (val) f << "g" << i << "=" << val << ",";
2030
45.5k
    }
2031
11.3k
    for (int i=0; i<5; ++i)
2032
9.48k
    {
2033
9.48k
      val=int(libwps::readU16(input));
2034
9.48k
      int const expected[]= {0x4001,0x2003,0x100,0x64,0};
2035
9.48k
      if (val!=expected[i]) f << "h" << i << "=" << std::hex << val << std::dec << ",";
2036
9.48k
    }
2037
1.89k
    break;
2038
5.20k
  case 2:    // appear after zone 0: pos~end-2
2039
5.20k
  {
2040
5.20k
    f << "list,";
2041
5.20k
    if (sz<16 || (sz%4)!=0)
2042
1.07k
    {
2043
1.07k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 202\n"));
2044
1.07k
      f << "###";
2045
1.07k
      break;
2046
1.07k
    }
2047
4.13k
    auto N=int(libwps::readU16(input));
2048
4.13k
    f << "N=" << N << ",";
2049
4.13k
    if (16+4*N!=sz)
2050
251
    {
2051
251
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the N value seems bad for zone 202\n"));
2052
251
      f << "###";
2053
251
      break;
2054
251
    }
2055
3.87k
    if (!m_state->m_sheetZoneIdList.empty())
2056
1.91k
    {
2057
1.91k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: oops the sheet list is not empty\n"));
2058
1.91k
    }
2059
3.87k
    f << "zones=[";
2060
49.4k
    for (int i=0; i<N; ++i)
2061
45.5k
    {
2062
45.5k
      m_state->m_sheetZoneIdList.push_back(int(libwps::readU32(input)));
2063
45.5k
      f << "Z" << m_state->m_sheetZoneIdList.back() << ",";
2064
45.5k
    }
2065
3.87k
    f << "],";
2066
31.0k
    for (int i=0; i<7; ++i)   // f3=1-8
2067
27.1k
    {
2068
27.1k
      val=int(libwps::readU16(input));
2069
27.1k
      if (val) f << "f" << i << "=" << val << ",";
2070
27.1k
    }
2071
3.87k
    break;
2072
4.13k
  }
2073
11.7k
  case 4:
2074
11.7k
  {
2075
11.7k
    f << "name,";
2076
11.7k
    if (sz<14)
2077
653
    {
2078
653
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 204\n"));
2079
653
      f << "###";
2080
653
      break;
2081
653
    }
2082
55.4k
    for (int i=0; i<4; ++i)   // f2=0|1
2083
44.3k
    {
2084
44.3k
      val=int(libwps::readU16(input));
2085
44.3k
      int const expected[]= {0x200,0x11a,0,0};
2086
44.3k
      if (val!=expected[i]) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2087
44.3k
    }
2088
11.0k
    auto N=int(libwps::readU16(input));
2089
11.0k
    f << "N=" << N << ",";
2090
11.0k
    if (14+N!=sz)
2091
1.22k
    {
2092
1.22k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the N value seems bad for zone 204\n"));
2093
1.22k
      f << "###";
2094
1.22k
      break;
2095
1.22k
    }
2096
9.86k
    std::string text;
2097
43.6k
    for (int i=0; i<N; ++i) text+=char(libwps::readU8(input));
2098
9.86k
    f << text << ",";
2099
29.6k
    for (int i=0; i<2; ++i)   // g0=5f|76
2100
19.7k
    {
2101
19.7k
      val=int(libwps::readU16(input));
2102
19.7k
      if (val) f << "g" << i << "=" << val << ",";
2103
19.7k
    }
2104
9.86k
    break;
2105
11.0k
  }
2106
13.4k
  case 5: // defined a child of a sheetNames
2107
13.4k
    f << "Data0,";
2108
13.4k
    if (sz!=4)
2109
434
    {
2110
434
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 205\n"));
2111
434
      f << "###";
2112
434
      break;
2113
434
    }
2114
13.0k
    val=int(libwps::readU32(input));
2115
13.0k
    if (!val) break;
2116
13.0k
    if (m_state->m_dataZoneIdToSheetZoneIdMap.find(val) !=
2117
13.0k
            m_state->m_dataZoneIdToSheetZoneIdMap.end())
2118
8.05k
    {
2119
8.05k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the zone %d has already a parent\n", m_state->m_actualZoneId));
2120
8.05k
    }
2121
4.95k
    else
2122
4.95k
      m_state->m_dataZoneIdToSheetZoneIdMap[val]=m_state->m_actualZoneId;
2123
13.0k
    f << "Z" << val << ",";
2124
13.0k
    break;
2125
2126
  // two by files: first one a sheet sub zone, second close id
2127
2.77k
  case 0x82:
2128
4.24k
  case 0x83:
2129
10.5k
  case 0x84:
2130
19.8k
  case 0x93:
2131
22.3k
  case 0x94:
2132
25.3k
  case 0x95: // column definition
2133
32.4k
  case 0x96: // row definition
2134
32.4k
  {
2135
32.4k
    auto subZId=size_t(id&0x1F);
2136
32.4k
    f << "sheetC" << std::hex << subZId << std::dec << "[" << (m_state->m_sheetSubZoneOpened[subZId] ? "close" : "open") << "],";
2137
32.4k
    m_state->m_sheetSubZoneOpened[subZId]=!m_state->m_sheetSubZoneOpened[subZId];
2138
32.4k
    break;
2139
25.3k
  }
2140
3.89k
  case 0x80: // one by sheet, between 288 and 287
2141
3.89k
    f << "sheetB0,";
2142
3.89k
    if (sz!=8)
2143
1.66k
    {
2144
1.66k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 280\n"));
2145
1.66k
      f << "###";
2146
1.66k
      break;
2147
1.66k
    }
2148
11.1k
    for (int i=0; i<4; ++i)   // 0|1
2149
8.89k
    {
2150
8.89k
      val=int(libwps::readU16(input));
2151
8.89k
      if (val) f << "f" << i << "=" << val << ",";
2152
8.89k
    }
2153
2.22k
    break;
2154
1.86k
  case 0x81: // one by sheet, in sheetData0
2155
1.86k
    f << "sheetB1,";
2156
1.86k
    if (sz!=44)
2157
69
    {
2158
69
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 281\n"));
2159
69
      f << "###";
2160
69
      break;
2161
69
    }
2162
1.79k
    val=int(libwps::readU16(input));
2163
1.79k
    if (val!=1) f << "f0=" << val << ",";
2164
1.79k
    f << "unkn=[";
2165
8.95k
    for (int i=0; i<4; ++i)   // maybe some some id
2166
7.16k
    {
2167
7.16k
      val=int(libwps::readU16(input));
2168
7.16k
      if (val)
2169
3.40k
        f << val << ",";
2170
3.75k
      else
2171
3.75k
        f << "_,";
2172
7.16k
    }
2173
1.79k
    f << "],";
2174
32.2k
    for (int i=0; i<17; ++i)   // g4=ff, g6=1fff|ffff, g8=1, g9=0|small number
2175
30.4k
    {
2176
30.4k
      val=int(libwps::read16(input));
2177
30.4k
      if (val) f << "g" << i << "=" << std::hex << val << std::dec << ",";
2178
30.4k
    }
2179
1.79k
    break;
2180
8.34k
  case 0x85: // in general, I found them in sheetData0+1 and sheetData+2 (with the same value)
2181
8.34k
    f << "data1,";
2182
8.34k
    if (sz!=4)
2183
184
    {
2184
184
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 285\n"));
2185
184
      f << "###";
2186
184
      break;
2187
184
    }
2188
8.15k
    f << "id=Z" << int(libwps::readU32(input)) << ",";
2189
8.15k
    break;
2190
1.41k
  case 0x86: // one by file in general after sheetC16
2191
1.41k
    f << "sheetB6,";
2192
1.41k
    if (sz!=8 && sz!=10)
2193
672
    {
2194
672
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 286\n"));
2195
672
      f << "###";
2196
672
      break;
2197
672
    }
2198
3.75k
    for (long i=0; i<sz/2; ++i)   // 100,0,100,2000 in 123:v4.0 , 100,0,100,0,100:v4.5
2199
3.01k
    {
2200
3.01k
      val=int(libwps::readU16(input));
2201
3.01k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2202
3.01k
    }
2203
739
    break;
2204
4.66k
  case 0x87: // one by sheet, after 280
2205
4.66k
    f << "sheetB7,";
2206
4.66k
    if (sz!=6)
2207
65
    {
2208
65
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 287\n"));
2209
65
      f << "###";
2210
65
      break;
2211
65
    }
2212
18.4k
    for (int i=0; i<3; ++i)   // 1,1,0
2213
13.8k
    {
2214
13.8k
      val=int(libwps::readU16(input));
2215
13.8k
      if (val) f << "f" << i << "=" << val << ",";
2216
13.8k
    }
2217
4.60k
    break;
2218
1.93k
  case 0x88: // one by sheet, between 281 and 280
2219
1.93k
    f << "sheetB8,";
2220
1.93k
    if (sz!=4)
2221
175
    {
2222
175
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 288\n"));
2223
175
      f << "###";
2224
175
      break;
2225
175
    }
2226
1.76k
    val=int(libwps::readU32(input)); // always 1, maybe and id
2227
1.76k
    if (val!=1) f << "f0=" << val << ",";
2228
1.76k
    break;
2229
2.42k
  case 0x92: // in sheetC2. Checkme, zone with variable size
2230
2.42k
    f << "sheetB12,";
2231
2.42k
    if (sz<28)
2232
1.59k
    {
2233
1.59k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone 288\n"));
2234
1.59k
      f << "###";
2235
1.59k
      break;
2236
1.59k
    }
2237
12.3k
    for (int i=0; i<14; ++i)   // f0=3600|438,f2=f0|c000|e040, f4=500[256]
2238
11.5k
    {
2239
11.5k
      val=int(libwps::readU16(input));
2240
11.5k
      int const expected[]= {0,0,0,0,0, 0x35d4,0,0x1003,0x2000,0, 0x60,0,0x60,0};
2241
11.5k
      if (val!=expected[i]) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2242
11.5k
    }
2243
    // after some 0 or 3ff0
2244
823
    break;
2245
8.51k
  case 0x99: // in sheetC15, sheetC16
2246
17.6k
  case 0x9a: // in sheetC4, sheetC13, sheetC14
2247
17.6k
    f << "sheetB" << std::hex << (id-0x90) << std::dec << ",";
2248
17.6k
    if (sz!=10)
2249
2.04k
    {
2250
2.04k
      WPS_DEBUG_MSG(("LotusParser::readSheetZone: the size seems bad for zone %d\n", id));
2251
2.04k
      f << "###";
2252
2.04k
      break;
2253
2.04k
    }
2254
93.5k
    for (int i=0; i<5; ++i)   // always 0
2255
77.9k
    {
2256
77.9k
      val=int(libwps::readU16(input));
2257
77.9k
      if (val) f << "f" << i << "=" << val << ",";
2258
77.9k
    }
2259
15.5k
    break;
2260
7.54k
  default:
2261
7.54k
    f << "type=" << std::hex << id << std::dec << ",";
2262
7.54k
    break;
2263
129k
  }
2264
129k
  ascFile.addPos(pos);
2265
129k
  ascFile.addNote(f.str().c_str());
2266
129k
  if (input->tell()!=endPos && input->tell()!=pos)
2267
14.5k
    ascFile.addDelimiter(input->tell(),'|');
2268
129k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2269
129k
  return true;
2270
129k
}
2271
2272
bool LotusParser::readZone4(std::shared_ptr<WPSStream> stream)
2273
341k
{
2274
341k
  if (!stream) return false;
2275
341k
  RVNGInputStreamPtr &input = stream->m_input;
2276
341k
  libwps::DebugFile &ascFile=stream->m_ascii;
2277
341k
  libwps::DebugStream f;
2278
341k
  long pos = input->tell();
2279
341k
  auto id = int(libwps::readU8(input));
2280
341k
  if (libwps::readU8(input)!=4)
2281
0
  {
2282
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2283
0
    return false;
2284
0
  }
2285
341k
  auto sz = long(libwps::readU16(input));
2286
341k
  long endPos=pos+4+sz;
2287
341k
  if (sz<0 || !stream->checkFilePosition(endPos))
2288
0
  {
2289
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2290
0
    return false;
2291
0
  }
2292
341k
  f << "Entries(Zone4):";
2293
341k
  int val;
2294
341k
  switch (id)
2295
341k
  {
2296
85.3k
  case 0:   // one by sheet, page definition ?
2297
85.3k
  {
2298
85.3k
    f << "sheet[page,def],";
2299
85.3k
    if (sz<90)
2300
79.7k
    {
2301
79.7k
      WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 0\n"));
2302
79.7k
      f << "###";
2303
79.7k
      break;
2304
79.7k
    }
2305
5.64k
    f << "dims=["; // margins + page dim?
2306
39.5k
    for (int i=0; i<6; ++i)
2307
33.8k
    {
2308
33.8k
      val=int(libwps::read32(input));
2309
33.8k
      if (val)
2310
29.3k
        f << val << ",";
2311
4.53k
      else
2312
4.53k
        f << "_,";
2313
33.8k
    }
2314
5.64k
    f << "],";
2315
5.64k
    f << "unkn=[";
2316
56.4k
    for (int i=0; i<9; ++i)   // list of 0|2|5
2317
50.8k
    {
2318
50.8k
      val=int(libwps::read16(input));
2319
50.8k
      if (val)
2320
29.5k
        f << val << ",";
2321
21.2k
      else
2322
21.2k
        f << "_,";
2323
50.8k
    }
2324
5.64k
    f << "],";
2325
22.5k
    for (int i=0; i<3; ++i)   // some zone
2326
16.9k
    {
2327
16.9k
      val=int(libwps::read32(input));
2328
16.9k
      if (val)
2329
14.7k
        f << "zone" << i << "=Z" << val << ",";
2330
16.9k
    }
2331
73.4k
    for (int i=0; i<12; ++i)   // f2=0|8, f4=119|131|137, f5=0|7, f11=0|9
2332
67.7k
    {
2333
67.7k
      val=int(libwps::read16(input));
2334
67.7k
      int const expected[]= {0,0,0,0,0x131, 0,1,1,0x270f,1, 0x64,1};
2335
67.7k
      if (val!=expected[i])
2336
53.2k
        f << "f" << i << "=" << val << ",";
2337
67.7k
    }
2338
5.64k
    f << "fl=[";
2339
62.1k
    for (int i=0; i<10; ++i)   // list of 0|1|3, often 1
2340
56.4k
    {
2341
56.4k
      val=int(libwps::readU8(input));
2342
56.4k
      if (val)
2343
33.4k
        f << val << ",";
2344
23.0k
      else
2345
23.0k
        f << "_,";
2346
56.4k
    }
2347
5.64k
    f << "],";
2348
5.64k
    if (sz<92) break;
2349
    // unsure from here, often the main style name?
2350
5.61k
    std::string name;
2351
40.1k
    while (input->tell()<endPos)
2352
40.0k
    {
2353
40.0k
      auto c=char(libwps::readU8(input));
2354
40.0k
      if (!c) break;
2355
34.4k
      name+=c;
2356
34.4k
    }
2357
5.61k
    if (!name.empty()) f << name << ",";
2358
5.61k
    break;
2359
5.64k
  }
2360
1.74k
  case 1: // after zoneA0, in general 6 item f0=0-5, tab? or item style?
2361
1.74k
    f << "zoneA1,";
2362
1.74k
    if (sz!=7)
2363
1.46k
    {
2364
1.46k
      WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 1\n"));
2365
1.46k
      f << "###";
2366
1.46k
      break;
2367
1.46k
    }
2368
276
    f << "id=" << int(libwps::readU8(input)) << ",";
2369
1.10k
    for (int i=0; i<3; ++i)   // 0
2370
828
    {
2371
828
      val=int(libwps::readU16(input));
2372
828
      if (val) f << "f" << i << "=" << val << ",";
2373
828
    }
2374
276
    break;
2375
95.1k
  case 3:   // in sheet definition, after the style
2376
95.1k
  {
2377
95.1k
    f << "footerDef,";
2378
95.1k
    if (sz<31)
2379
91.4k
    {
2380
91.4k
      WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 3\n"));
2381
91.4k
      f << "###";
2382
91.4k
      break;
2383
91.4k
    }
2384
52.6k
    for (int i=0; i<13; ++i)   // f4==5,f6=4,f7=76,f8=2,f9=2,f10=66,f11=1
2385
48.8k
    {
2386
48.8k
      val=int(libwps::readU16(input));
2387
48.8k
      if (val) f << "f" << i << "=" << val << ",";
2388
48.8k
    }
2389
3.75k
    val=int(libwps::readU8(input)); // 0
2390
3.75k
    if (val) f << "f13=" << val << ",";
2391
7.15k
    for (int s=0; s<2; ++s)
2392
6.58k
    {
2393
6.58k
      auto sSz=int(libwps::readU16(input));
2394
6.58k
      if (input->tell()+sSz+(s==0 ? 2 : 0)>endPos)
2395
3.18k
      {
2396
3.18k
        WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 3\n"));
2397
3.18k
        f << "###";
2398
3.18k
        break;
2399
3.18k
      }
2400
3.40k
      std::string name;
2401
169k
      for (int i=0; i<sSz; ++i)
2402
165k
      {
2403
165k
        auto c=char(libwps::readU8(input));
2404
165k
        if (c) name+=c;
2405
76.4k
        else if (i+1!=sSz)
2406
75.5k
        {
2407
75.5k
          WPS_DEBUG_MSG(("LotusParser::readZone4: find odd char in zone 3\n"));
2408
75.5k
          f << "###";
2409
75.5k
        }
2410
165k
      }
2411
3.40k
      if (!name.empty()) f << "string" << s << "=" << name << ",";
2412
3.40k
    }
2413
3.75k
    break;
2414
95.1k
  }
2415
656
  case 0x80: // rare, present in sheet definition
2416
656
    f << "chartSheet,";
2417
656
    if (sz!=4)
2418
532
    {
2419
532
      WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 80\n"));
2420
532
      f << "###";
2421
532
      break;
2422
532
    }
2423
124
    f << "id=Z" << int(libwps::readU32(input)) << ",";
2424
124
    break;
2425
1.01k
  case 0x81: // after 480. checkme chart series
2426
1.01k
    f << "chartSeries,";
2427
1.01k
    if (sz!=12)
2428
170
    {
2429
170
      WPS_DEBUG_MSG(("LotusParser::readZone4: the size seems bad for zone 81\n"));
2430
170
      f << "###";
2431
170
      break;
2432
170
    }
2433
845
    f << "unkn=[";
2434
3.38k
    for (int i=0; i<3; ++i)
2435
2.53k
    {
2436
2.53k
      val=int(libwps::readU32(input));
2437
2.53k
      if (val)
2438
2.52k
        f << val << ",";
2439
8
      else
2440
8
        f << "_,";
2441
2.53k
    }
2442
845
    f << "],";
2443
845
    break;
2444
157k
  default:
2445
157k
    f << "type=" << std::hex << id << std::dec << ",";
2446
157k
    break;
2447
341k
  }
2448
341k
  ascFile.addPos(pos);
2449
341k
  ascFile.addNote(f.str().c_str());
2450
341k
  if (input->tell()!=endPos && input->tell()!=pos)
2451
334k
    ascFile.addDelimiter(input->tell(),'|');
2452
341k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2453
341k
  return true;
2454
341k
}
2455
2456
bool LotusParser::readChartZone(std::shared_ptr<WPSStream> stream)
2457
30.2k
{
2458
30.2k
  if (!stream) return false;
2459
30.2k
  RVNGInputStreamPtr &input = stream->m_input;
2460
30.2k
  libwps::DebugFile &ascFile=stream->m_ascii;
2461
30.2k
  libwps::DebugStream f;
2462
30.2k
  long pos = input->tell();
2463
30.2k
  auto id = int(libwps::readU8(input));
2464
30.2k
  if (libwps::readU8(input)!=5)
2465
0
  {
2466
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2467
0
    return false;
2468
0
  }
2469
30.2k
  auto sz = long(libwps::readU16(input));
2470
30.2k
  long endPos=pos+4+sz;
2471
30.2k
  if (sz<0 || !stream->checkFilePosition(endPos))
2472
0
  {
2473
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2474
0
    return false;
2475
0
  }
2476
30.2k
  f << "Entries(ChartZone):";
2477
30.2k
  int val;
2478
30.2k
  switch (id)
2479
30.2k
  {
2480
9.21k
  case 0:
2481
9.21k
  {
2482
9.21k
    f << "name,";
2483
9.21k
    if (sz<6)
2484
3.97k
    {
2485
3.97k
      WPS_DEBUG_MSG(("LotusParser::readChartZone: the size seems bad for zone 0\n"));
2486
3.97k
      f << "###";
2487
3.97k
      break;
2488
3.97k
    }
2489
15.7k
    for (int i=0; i<2; ++i)   // always 0
2490
10.4k
    {
2491
10.4k
      val=int(libwps::readU16(input));
2492
10.4k
      if (val)
2493
9.24k
        f << "f" << i << "=" << val << ",";
2494
10.4k
    }
2495
5.24k
    auto sSz=int(libwps::readU16(input));
2496
5.24k
    if (6+sSz>sz)
2497
4.54k
    {
2498
4.54k
      WPS_DEBUG_MSG(("LotusParser::readChartZone: the size seems bad for zone 0\n"));
2499
4.54k
      f << "###";
2500
4.54k
      break;
2501
4.54k
    }
2502
694
    std::string name;
2503
65.4k
    for (int i=0; i<sSz; ++i)
2504
64.7k
    {
2505
64.7k
      auto c=char(libwps::readU8(input));
2506
64.7k
      if (c) name+=c;
2507
27.5k
      else if (i+1!=sSz)
2508
27.4k
      {
2509
27.4k
        WPS_DEBUG_MSG(("LotusParser::readChartZone: find odd char in zone 0\n"));
2510
27.4k
        f << "###";
2511
27.4k
      }
2512
64.7k
    }
2513
694
    if (!name.empty()) f << name << ",";
2514
694
    break;
2515
5.24k
  }
2516
1.29k
  case 2:
2517
1.29k
    f << "series,";
2518
1.29k
    if (sz!=12)
2519
1.09k
    {
2520
1.09k
      WPS_DEBUG_MSG(("LotusParser::readChartZone: the size seems bad for zone 2\n"));
2521
1.09k
      f << "###";
2522
1.09k
      break;
2523
1.09k
    }
2524
191
    f << "unkn=[";
2525
764
    for (int i=0; i<3; ++i)
2526
573
    {
2527
573
      val=int(libwps::readU32(input));
2528
573
      if (val)
2529
567
        f << val << ",";
2530
6
      else
2531
6
        f << "_,";
2532
573
    }
2533
191
    f << "],";
2534
191
    break;
2535
14.4k
  case 3: // last zone
2536
14.4k
    f << "end,";
2537
14.4k
    if (sz!=0)
2538
14.3k
    {
2539
14.3k
      WPS_DEBUG_MSG(("LotusParser::readChartZone: the size seems bad for zone 3\n"));
2540
14.3k
      f << "###";
2541
14.3k
      break;
2542
14.3k
    }
2543
100
    break;
2544
5.29k
  default:
2545
5.29k
    f << "type=" << std::hex << id << std::dec << ",";
2546
5.29k
    break;
2547
30.2k
  }
2548
30.2k
  ascFile.addPos(pos);
2549
30.2k
  ascFile.addNote(f.str().c_str());
2550
30.2k
  if (input->tell()!=endPos && input->tell()!=pos)
2551
27.5k
    ascFile.addDelimiter(input->tell(),'|');
2552
30.2k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2553
30.2k
  return true;
2554
30.2k
}
2555
2556
bool LotusParser::readRefZone(std::shared_ptr<WPSStream> stream)
2557
83.0k
{
2558
83.0k
  if (!stream) return false;
2559
83.0k
  RVNGInputStreamPtr &input = stream->m_input;
2560
83.0k
  libwps::DebugFile &ascFile=stream->m_ascii;
2561
83.0k
  libwps::DebugStream f;
2562
83.0k
  long pos = input->tell();
2563
83.0k
  auto id = int(libwps::readU8(input));
2564
83.0k
  if (libwps::readU8(input)!=6)
2565
0
  {
2566
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2567
0
    return false;
2568
0
  }
2569
83.0k
  auto sz = long(libwps::readU16(input));
2570
83.0k
  long endPos=pos+4+sz;
2571
83.0k
  if (sz<0 || !stream->checkFilePosition(endPos))
2572
0
  {
2573
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2574
0
    return false;
2575
0
  }
2576
83.0k
  f << "Entries(RefZone):";
2577
83.0k
  int val;
2578
83.0k
  switch (id)
2579
83.0k
  {
2580
6.34k
  case 0x40: // after 642
2581
6.34k
    f << "cells,";
2582
6.34k
    if (sz!=12)
2583
1.06k
    {
2584
1.06k
      WPS_DEBUG_MSG(("LotusParser::readRefZone: the size seems bad for zone 640\n"));
2585
1.06k
      f << "###";
2586
1.06k
      break;
2587
1.06k
    }
2588
36.9k
    for (int i=0; i<6; ++i) // C?R?S? <-> C?R?S?: checkme maybe this stores also the range
2589
31.6k
    {
2590
31.6k
      f << int(libwps::readU16(input));
2591
31.6k
      if (i==2) f << "<->";
2592
26.3k
      else if (i==5) f << ",";
2593
21.1k
      else f << ":";
2594
31.6k
    }
2595
5.27k
    break;
2596
6.71k
  case 0x42: // after 407
2597
6.71k
    f << "begin,";
2598
6.71k
    if (sz!=4)
2599
145
    {
2600
145
      WPS_DEBUG_MSG(("LotusParser::readRefZone: the size seems bad for zone 642\n"));
2601
145
      f << "###";
2602
145
      break;
2603
145
    }
2604
6.56k
    val=int(libwps::readU32(input)); // always 3
2605
6.56k
    if (val!=3) f << "f0=" << val << ",";
2606
6.56k
    break;
2607
1.78k
  case 0x43:   // find something similar to A:E7 for a cell or to B:H3..B:H80 for a cell list
2608
1.78k
  {
2609
1.78k
    f << "name,";
2610
1.78k
    if (sz<=0)
2611
333
    {
2612
333
      WPS_DEBUG_MSG(("LotusParser::readRefZone: the size seems bad for zone 643\n"));
2613
333
      f << "###";
2614
333
      break;
2615
333
    }
2616
1.45k
    std::string name;
2617
48.9k
    for (long i=0; i<sz; ++i)
2618
47.5k
    {
2619
47.5k
      auto c=char(libwps::readU8(input));
2620
47.5k
      if (c) name+=c;
2621
17.8k
      else if (i+1!=sz)
2622
16.5k
      {
2623
16.5k
        WPS_DEBUG_MSG(("LotusParser::readRefZone: find odd char in zone 643\n"));
2624
16.5k
        f << "###";
2625
16.5k
      }
2626
47.5k
    }
2627
1.45k
    if (!name.empty()) f << name << ",";
2628
1.45k
    break;
2629
1.78k
  }
2630
68.2k
  default:
2631
68.2k
    f << "type=" << std::hex << id << std::dec << ",";
2632
68.2k
    break;
2633
83.0k
  }
2634
83.0k
  ascFile.addPos(pos);
2635
83.0k
  ascFile.addNote(f.str().c_str());
2636
83.0k
  if (input->tell()!=endPos && input->tell()!=pos)
2637
60.4k
    ascFile.addDelimiter(input->tell(),'|');
2638
83.0k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2639
83.0k
  return true;
2640
83.0k
}
2641
2642
bool LotusParser::readZone7(std::shared_ptr<WPSStream> stream)
2643
36.6k
{
2644
36.6k
  if (!stream) return false;
2645
36.6k
  RVNGInputStreamPtr &input = stream->m_input;
2646
36.6k
  libwps::DebugFile &ascFile=stream->m_ascii;
2647
36.6k
  libwps::DebugStream f;
2648
36.6k
  long pos = input->tell();
2649
36.6k
  auto id = int(libwps::readU8(input));
2650
36.6k
  if (libwps::readU8(input)!=7)
2651
0
  {
2652
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2653
0
    return false;
2654
0
  }
2655
36.6k
  auto sz = long(libwps::readU16(input));
2656
36.6k
  long endPos=pos+4+sz;
2657
36.6k
  if (sz<0 || !stream->checkFilePosition(endPos))
2658
0
  {
2659
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2660
0
    return false;
2661
0
  }
2662
36.6k
  f << "Entries(Zone7)[" << std::hex << id << std::dec << "]:";
2663
2664
  // normally, 780, ..., 701, 702, ..., 703, ..., 704, ...
2665
  // in 704: the cell style
2666
36.6k
  int val;
2667
36.6k
  switch (id)
2668
36.6k
  {
2669
6.88k
  case 1:
2670
    // empty zone (or container of 702)
2671
6.88k
    if (sz!=28)
2672
6.09k
    {
2673
6.09k
      WPS_DEBUG_MSG(("LotusParser::readZone7: the size seems bad for zone 1\n"));
2674
6.09k
      f << "###";
2675
6.09k
      break;
2676
6.09k
    }
2677
3.95k
    for (int i=0; i<4; ++i)
2678
3.16k
    {
2679
3.16k
      val=int(libwps::readU16(input));
2680
3.16k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2681
3.16k
    }
2682
790
    f << "mat=[";
2683
3.95k
    for (int i=0; i<4; ++i)
2684
3.16k
    {
2685
3.16k
      double res;
2686
3.16k
      bool isNan;
2687
3.16k
      long actPos=pos;
2688
3.16k
      if (libwps::readDouble4(input, res, isNan))
2689
3.16k
        f << res << ",";
2690
0
      else
2691
0
      {
2692
0
        f << "###";
2693
0
        input->seek(actPos+2, librevenge::RVNG_SEEK_SET);
2694
0
      }
2695
3.16k
    }
2696
790
    f << "],";
2697
2.37k
    for (int i=0; i<2; ++i)
2698
1.58k
    {
2699
1.58k
      val=int(libwps::readU16(input));
2700
1.58k
      if (val) f << "g" << i << "=" << std::hex << val << std::dec << ",";
2701
1.58k
    }
2702
790
    break;
2703
2.07k
  case 2:
2704
    // precedes the LotusbE
2705
2.07k
    if (sz!=8)
2706
1.42k
    {
2707
1.42k
      WPS_DEBUG_MSG(("LotusParser::readZone7: the size seems bad for zone 2\n"));
2708
1.42k
      f << "###";
2709
1.42k
      break;
2710
1.42k
    }
2711
3.27k
    for (int i=0; i<4; ++i)   // always 0
2712
2.61k
    {
2713
2.61k
      val=int(libwps::readU16(input));
2714
2.61k
      if (val) f << "f" << i << "=" << val << ",";
2715
2.61k
    }
2716
654
    break;
2717
1.58k
  case 3:
2718
    // precedes LotuscE, Lotus1cE, the col size, the link, the sheet name, the cells content
2719
1.58k
    f << "content,";
2720
1.58k
    if (sz!=6)
2721
851
    {
2722
851
      WPS_DEBUG_MSG(("LotusParser::readZone7: the size seems bad for zone 3\n"));
2723
851
      f << "###";
2724
851
      break;
2725
851
    }
2726
2.95k
    for (int i=0; i<3; ++i)   // list of 0|1
2727
2.21k
    {
2728
2.21k
      val=int(libwps::readU16(input));
2729
2.21k
      if (val) f << "f" << i << "=" << val << ",";
2730
2.21k
    }
2731
738
    break;
2732
902
  case 4:
2733
    // precedes the cell styles
2734
902
    f << "styles,";
2735
902
    if (sz!=0)
2736
695
    {
2737
695
      WPS_DEBUG_MSG(("LotusParser::readZone7: the size seems bad for zone 4\n"));
2738
695
      f << "###";
2739
695
      break;
2740
695
    }
2741
207
    break;
2742
6.13k
  case 0x80: // first zone, precedes Data105N,Data104N,Data100N,Lotus3E
2743
6.13k
    f << "first,";
2744
6.13k
    if (sz!=12)
2745
2.78k
    {
2746
2.78k
      WPS_DEBUG_MSG(("LotusParser::readZone7: the size seems bad for zone 80\n"));
2747
2.78k
      f << "###";
2748
2.78k
      break;
2749
2.78k
    }
2750
23.4k
    for (int i=0; i<6; ++i)   // f0=6f|ef
2751
20.1k
    {
2752
20.1k
      val=int(libwps::readU16(input));
2753
20.1k
      int const expected[]= {0xef, 0, 7, 0, 0x5f, 0x57};
2754
20.1k
      if (val!=expected[i]) f << "f" << i << "=" << std::hex << val << std::dec << ",";
2755
20.1k
    }
2756
3.35k
    break;
2757
19.0k
  default:
2758
19.0k
    break;
2759
36.6k
  }
2760
36.6k
  ascFile.addPos(pos);
2761
36.6k
  ascFile.addNote(f.str().c_str());
2762
36.6k
  if (input->tell()!=endPos && input->tell()!=pos)
2763
25.7k
    ascFile.addDelimiter(input->tell(),'|');
2764
36.6k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2765
36.6k
  return true;
2766
36.6k
}
2767
2768
bool LotusParser::readZone8(std::shared_ptr<WPSStream> stream)
2769
1.52M
{
2770
1.52M
  if (!stream) return false;
2771
1.52M
  RVNGInputStreamPtr &input = stream->m_input;
2772
1.52M
  libwps::DebugFile &ascFile=stream->m_ascii;
2773
1.52M
  libwps::DebugStream f;
2774
1.52M
  long pos = input->tell();
2775
1.52M
  auto id = int(libwps::readU8(input));
2776
1.52M
  if (id==1)
2777
674k
  {
2778
674k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2779
674k
    WPSVec3i minC, maxC;
2780
674k
    m_state->getLevels(minC, maxC);
2781
674k
    return m_spreadsheetParser->readCellsFormat801
2782
674k
           (stream, minC, maxC, m_state->m_sheetSubZoneOpened[0x15] ? 0 :
2783
674k
            m_state->m_sheetSubZoneOpened[0x16] ? 1 : -1);
2784
674k
  }
2785
845k
  if (libwps::readU8(input)!=8)
2786
0
  {
2787
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2788
0
    return false;
2789
0
  }
2790
845k
  auto sz = long(libwps::readU16(input));
2791
845k
  long endPos=pos+4+sz;
2792
845k
  if (sz<0 || !stream->checkFilePosition(endPos))
2793
0
  {
2794
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2795
0
    return false;
2796
0
  }
2797
845k
  int const vers=version();
2798
845k
  f << "Entries(Zone8):";
2799
845k
  int val;
2800
845k
  switch (id)
2801
845k
  {
2802
677k
  case 0: // v4: sz2, v4.5: sz4
2803
677k
  {
2804
677k
    f << "level[select],";
2805
677k
    int const expectedSz=vers<=4 ? 2 : 4; // checkme: unsure about vers==5
2806
677k
    if (sz!=expectedSz)
2807
58.1k
    {
2808
58.1k
      WPS_DEBUG_MSG(("LotusParser::readZone8: the level size seems bad\n"));
2809
58.1k
      f << "###";
2810
58.1k
      break;
2811
58.1k
    }
2812
619k
    if (m_state->m_actualLevels.empty())
2813
14.8k
    {
2814
14.8k
      WPS_DEBUG_MSG(("LotusParser::readZone8: the level seems bad\n"));
2815
14.8k
      f << "###";
2816
14.8k
      break;
2817
14.8k
    }
2818
604k
    long count=int(sz>=4 ? libwps::readU32(input) : libwps::readU16(input));
2819
604k
    Vec2i &zone=m_state->m_actualLevels.back();
2820
604k
    if (int(zone[1]+count)<0)
2821
46.0k
    {
2822
46.0k
      WPS_DEBUG_MSG(("LotusParser::readZone8: arg the delta bad\n"));
2823
46.0k
      f << "###delta=" << count << ",";
2824
46.0k
      count=0;
2825
46.0k
    }
2826
604k
    zone[0] = zone[1];
2827
604k
    zone[1] += int(count);
2828
604k
    f << "pos=[" << m_state->getLevelsDebugName() << "],";
2829
604k
    break;
2830
619k
  }
2831
  // 1 already done
2832
15.7k
  case 2: // very often 802 and 803 are close to each other (in the sheet's zone)
2833
18.6k
  case 3:
2834
18.6k
    if (id==2)
2835
15.7k
      f << "column[def],";
2836
2.88k
    else
2837
2.88k
      f << "zoneA" << id << ",";
2838
18.6k
    if (sz!=2)
2839
4.26k
    {
2840
4.26k
      WPS_DEBUG_MSG(("LotusParser::readZone8: the size seems bad for id=%d\n", id));
2841
4.26k
      f << "###";
2842
4.26k
      break;
2843
4.26k
    }
2844
14.3k
    val=int(libwps::readU16(input)); // 1|2
2845
14.3k
    if (val!=1) f << "f0=" << val  << ",";
2846
14.3k
    break;
2847
91.3k
  case 4:
2848
91.3k
  {
2849
91.3k
    f << "zoneA4,";
2850
91.3k
    if (m_state->m_sheetSubZoneOpened[0x15]) f << "cols,";
2851
90.2k
    else if (m_state->m_sheetSubZoneOpened[0x16]) f << "rows,";
2852
91.3k
    if (sz<4)
2853
70.6k
    {
2854
70.6k
      WPS_DEBUG_MSG(("LotusParser::readZone8: the size seems bad for 804\n"));
2855
70.6k
      f << "###";
2856
70.6k
      break;
2857
70.6k
    }
2858
20.6k
    val=int(libwps::readU16(input));
2859
20.6k
    if (val!=3) f << "f0=" << val << ",";
2860
20.6k
    auto N=int(libwps::readU16(input));
2861
20.6k
    f << "N=" << N << ",";
2862
20.6k
    int const expectedSz=vers<=4 ? 2 : 4; // checkme: unsure about vers==5
2863
20.6k
    if (sz!=4+N*expectedSz)
2864
6.78k
    {
2865
6.78k
      WPS_DEBUG_MSG(("LotusParser::readZone8: the N value seems bad for 804\n"));
2866
6.78k
      f << "###";
2867
6.78k
      break;
2868
6.78k
    }
2869
13.8k
    f << "unk=[";
2870
43.9k
    for (int i=0; i<N; ++i)
2871
30.1k
    {
2872
30.1k
      f << int(libwps::readU8(input));
2873
30.1k
      f << ":" << int(libwps::readU8(input));
2874
30.1k
      if (expectedSz==4)
2875
12.8k
      {
2876
12.8k
        f << "<->" << int(libwps::readU8(input));
2877
12.8k
        f << ":" << int(libwps::readU8(input));
2878
12.8k
      }
2879
30.1k
      f << ",";
2880
30.1k
    }
2881
13.8k
    f << "],";
2882
13.8k
    break;
2883
20.6k
  }
2884
462
  case 0x83: // often the last 80X's zone
2885
462
    f << "zoneB3,";
2886
462
    if (sz!=5)
2887
108
    {
2888
108
      WPS_DEBUG_MSG(("LotusParser::readZone8: the size seems bad for 883\n"));
2889
108
      f << "###";
2890
108
      break;
2891
108
    }
2892
2.12k
    for (int i=0; i<5; ++i)   // always 0
2893
1.77k
    {
2894
1.77k
      val=int(libwps::readU8(input));
2895
1.77k
      if (val) f << "f" << i << "=" << val  << ",";
2896
1.77k
    }
2897
354
    break;
2898
58.1k
  default:
2899
58.1k
    f << "type=" << std::hex << id << std::dec << ",";
2900
58.1k
    break;
2901
845k
  }
2902
845k
  ascFile.addPos(pos);
2903
845k
  ascFile.addNote(f.str().c_str());
2904
845k
  if (input->tell()!=endPos && input->tell()!=pos)
2905
133k
    ascFile.addDelimiter(input->tell(),'|');
2906
845k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2907
845k
  return true;
2908
845k
}
2909
2910
bool LotusParser::readVersionZone(std::shared_ptr<WPSStream> stream)
2911
76.2k
{
2912
76.2k
  if (!stream) return false;
2913
76.2k
  RVNGInputStreamPtr &input = stream->m_input;
2914
76.2k
  libwps::DebugFile &ascFile=stream->m_ascii;
2915
76.2k
  libwps::DebugStream f;
2916
76.2k
  long pos = input->tell();
2917
76.2k
  auto id = int(libwps::readU8(input));
2918
76.2k
  if (libwps::readU8(input)!=0xa)
2919
0
  {
2920
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2921
0
    return false;
2922
0
  }
2923
76.2k
  auto sz = long(libwps::readU16(input));
2924
76.2k
  long endPos=pos+4+sz;
2925
76.2k
  if (sz<0 || !stream->checkFilePosition(endPos))
2926
0
  {
2927
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2928
0
    return false;
2929
0
  }
2930
76.2k
  f << "Entries(VersionZone):";
2931
  // TODO
2932
76.2k
  switch (id)
2933
76.2k
  {
2934
76.2k
  default:
2935
76.2k
    f << "type=" << std::hex << id << std::dec << ",";
2936
76.2k
    break;
2937
76.2k
  }
2938
76.2k
  ascFile.addPos(pos);
2939
76.2k
  ascFile.addNote(f.str().c_str());
2940
76.2k
  if (input->tell()!=endPos && input->tell()!=pos)
2941
70.2k
    ascFile.addDelimiter(input->tell(),'|');
2942
76.2k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2943
76.2k
  return true;
2944
76.2k
}
2945
////////////////////////////////////////////////////////////
2946
//   generic
2947
////////////////////////////////////////////////////////////
2948
bool LotusParser::readMacFontName(std::shared_ptr<WPSStream> stream, long endPos)
2949
17.2k
{
2950
17.2k
  if (!stream) return false;
2951
17.2k
  RVNGInputStreamPtr &input=stream->m_input;
2952
17.2k
  libwps::DebugFile &ascFile=stream->m_ascii;
2953
17.2k
  libwps::DebugStream f;
2954
2955
17.2k
  const int vers=version();
2956
17.2k
  long pos = input->tell();
2957
17.2k
  long sz=endPos-pos;
2958
17.2k
  f << "Entries(MacFontName):";
2959
17.2k
  if ((vers<=1 && sz<7) || (vers>1 && sz!=42))
2960
6.53k
  {
2961
6.53k
    WPS_DEBUG_MSG(("LotusParser::readMacFontName: the zone size seems bad\n"));
2962
6.53k
    f << "###";
2963
6.53k
    ascFile.addPos(pos-6);
2964
6.53k
    ascFile.addNote(f.str().c_str());
2965
6.53k
    return true;
2966
6.53k
  }
2967
10.7k
  if (vers<=1)
2968
6.67k
  {
2969
    // seems only to exist in a lotus mac file, so revert the default encoding to MacRoman if undef
2970
6.67k
    if (m_state->m_fontType==libwps_tools_win::Font::UNKNOWN)
2971
1.17k
      m_state->m_fontType=libwps_tools_win::Font::MAC_ROMAN;
2972
6.67k
    m_state->m_isMacFile=true;
2973
6.67k
    auto id=int(libwps::readU16(input));
2974
6.67k
    f << "FN" << id << ",";
2975
6.67k
    auto val=int(libwps::readU16(input)); // always 0?
2976
6.67k
    if (val)
2977
4.10k
      f << "f0=" << val << ",";
2978
6.67k
    val=int(libwps::read16(input)); // find -1, 30 (Geneva), 60 (Helvetica)
2979
6.67k
    if (val)
2980
6.17k
      f << "f1=" << val << ",";
2981
6.67k
    librevenge::RVNGString name("");
2982
6.67k
    bool nameOk=true;
2983
32.0k
    for (long i=0; i<sz-6; ++i)
2984
31.2k
    {
2985
31.2k
      auto c=char(libwps::readU8(input));
2986
31.2k
      if (!c) break;
2987
25.3k
      if (nameOk && !(c==' ' || (c>='0'&&c<='9') || (c>='a'&&c<='z') || (c>='A'&&c<='Z')))
2988
1.72k
      {
2989
1.72k
        nameOk=false;
2990
1.72k
        WPS_DEBUG_MSG(("LotusParser::readMacFontName: find odd character in name\n"));
2991
1.72k
        f << "#";
2992
1.72k
      }
2993
25.3k
      name.append(c);
2994
25.3k
    }
2995
6.67k
    f << name.cstr() << ",";
2996
6.67k
    if (m_state->m_fontsMap.find(id)!=m_state->m_fontsMap.end())
2997
1.90k
    {
2998
1.90k
      WPS_DEBUG_MSG(("LotusParser::readMacFontName: a font with id=%d already exists\n", id));
2999
1.90k
      f << "###id,";
3000
1.90k
    }
3001
4.76k
    else if (nameOk && !name.empty())
3002
2.21k
    {
3003
2.21k
      auto encoding=name!="Symbol" ? libwps_tools_win::Font::MAC_ROMAN : libwps_tools_win::Font::MAC_SYMBOL;
3004
2.21k
      LotusParserInternal::Font font(encoding);
3005
2.21k
      font.m_name=name;
3006
2.21k
      m_state->m_fontsMap.insert(std::map<int, LotusParserInternal::Font>::value_type(id,font));
3007
2.21k
    }
3008
6.67k
    ascFile.addPos(pos-6);
3009
6.67k
    ascFile.addNote(f.str().c_str());
3010
6.67k
    return true;
3011
6.67k
  }
3012
3013
4.07k
  int id=0;
3014
20.3k
  for (int i=0; i<4; ++i)
3015
16.3k
  {
3016
16.3k
    auto val=int(libwps::readU8(input)); // 0|1
3017
16.3k
    if (i==1)
3018
4.07k
    {
3019
4.07k
      id=val;
3020
4.07k
      f << "FN" << id << ",";
3021
4.07k
    }
3022
12.2k
    else if (val)
3023
4.90k
      f << "fl" << i << "=" << val << ",";
3024
16.3k
  }
3025
12.2k
  for (int i=0; i<2; ++i)   // f1=0|1288
3026
8.15k
  {
3027
8.15k
    auto val=int(libwps::read16(input));
3028
8.15k
    if (val)
3029
5.34k
      f << "f" << i << "=" << val << ",";
3030
8.15k
  }
3031
4.07k
  librevenge::RVNGString name("");
3032
4.07k
  bool nameOk=true;
3033
28.6k
  for (int i=0; i<8; ++i)
3034
27.0k
  {
3035
27.0k
    auto c=char(libwps::read8(input));
3036
27.0k
    if (!c) break;
3037
24.6k
    if (nameOk && !(c==' ' || (c>='0'&&c<='9') || (c>='a'&&c<='z') || (c>='A'&&c<='Z')))
3038
1.39k
    {
3039
1.39k
      nameOk=false;
3040
1.39k
      WPS_DEBUG_MSG(("LotusParser::readMacFontName: find odd character in name\n"));
3041
1.39k
      f << "#";
3042
1.39k
    }
3043
24.6k
    name.append(c);
3044
24.6k
  }
3045
4.07k
  f << name.cstr() << ",";
3046
4.07k
  if (m_state->m_fontsMap.find(id)!=m_state->m_fontsMap.end())
3047
1.56k
  {
3048
1.56k
    WPS_DEBUG_MSG(("LotusParser::readMacFontName: a font with id=%d already exists\n", id));
3049
1.56k
    f << "###id,";
3050
1.56k
  }
3051
2.50k
  else if (nameOk && !name.empty())
3052
1.37k
  {
3053
1.37k
    LotusParserInternal::Font font(getDefaultFontType());
3054
1.37k
    font.m_name=name;
3055
1.37k
    m_state->m_fontsMap.insert(std::map<int, LotusParserInternal::Font>::value_type(id,font));
3056
1.37k
  }
3057
4.07k
  input->seek(pos+16, librevenge::RVNG_SEEK_SET);
3058
4.07k
  if (input->tell()!=endPos)
3059
4.07k
  {
3060
4.07k
    ascFile.addDelimiter(input->tell(),'|');
3061
4.07k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
3062
4.07k
  }
3063
4.07k
  ascFile.addPos(pos-6);
3064
4.07k
  ascFile.addNote(f.str().c_str());
3065
4.07k
  return true;
3066
10.7k
}
3067
3068
bool LotusParser::readFMTStyleName(std::shared_ptr<WPSStream> stream)
3069
1.72k
{
3070
1.72k
  RVNGInputStreamPtr &input = stream->m_input;
3071
1.72k
  libwps::DebugFile &ascFile=stream->m_ascii;
3072
1.72k
  libwps::DebugStream f;
3073
3074
1.72k
  long pos = input->tell();
3075
1.72k
  auto type = int(libwps::read16(input));
3076
1.72k
  if (type!=0xb6)
3077
0
  {
3078
0
    WPS_DEBUG_MSG(("LotusParser::readFMTStyleName: not a font name definition\n"));
3079
0
    return false;
3080
0
  }
3081
1.72k
  auto sz = long(libwps::readU16(input));
3082
1.72k
  long endPos=pos+4+sz;
3083
1.72k
  if (sz<8)
3084
510
  {
3085
510
    WPS_DEBUG_MSG(("LotusParser::readFMTStyleName: the zone size seems bad\n"));
3086
510
    ascFile.addPos(pos);
3087
510
    ascFile.addNote("Entries(FMTStyleName):###");
3088
510
    return true;
3089
510
  }
3090
1.21k
  f << "Entries(FMTStyleName):";
3091
1.21k
  f << "id=" << libwps::readU16(input) << ",";
3092
1.21k
  std::string name;
3093
5.45k
  for (int i=0; i<6; ++i)
3094
4.98k
  {
3095
4.98k
    auto c=char(libwps::readU8(input));
3096
4.98k
    if (c==0) break;
3097
4.23k
    name+= c;
3098
4.23k
  }
3099
1.21k
  f << "title=" << name << ",";
3100
1.21k
  input->seek(pos+12, librevenge::RVNG_SEEK_SET);
3101
1.21k
  name.clear();
3102
74.5k
  for (long i=0; i<sz-8; ++i) name+= char(libwps::readU8(input));
3103
1.21k
  f << name << ",";
3104
1.21k
  if (input->tell()!=endPos)
3105
0
  {
3106
0
    WPS_DEBUG_MSG(("LotusParser::readFMTStyleName: find extra data\n"));
3107
0
    f << "###extra";
3108
0
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
3109
0
  }
3110
1.21k
  ascFile.addPos(pos);
3111
1.21k
  ascFile.addNote(f.str().c_str());
3112
1.21k
  return true;
3113
1.72k
}
3114
3115
bool LotusParser::readLinkZone(std::shared_ptr<WPSStream> stream)
3116
79.5k
{
3117
79.5k
  RVNGInputStreamPtr &input=stream->m_input;
3118
79.5k
  libwps::DebugFile &ascFile=stream->m_ascii;
3119
79.5k
  libwps::DebugStream f;
3120
3121
79.5k
  long pos = input->tell();
3122
79.5k
  auto type = int(libwps::read16(input));
3123
79.5k
  if (type!=0xa)
3124
0
  {
3125
0
    WPS_DEBUG_MSG(("LotusParser::readLinkZone: not a link definition\n"));
3126
0
    return false;
3127
0
  }
3128
79.5k
  auto sz = long(libwps::readU16(input));
3129
79.5k
  f << "Entries(Link):";
3130
79.5k
  if (sz < 19)
3131
2.83k
  {
3132
2.83k
    WPS_DEBUG_MSG(("LotusParser::readLinkZone: the zone is too short\n"));
3133
2.83k
    f << "###";
3134
2.83k
    ascFile.addPos(pos);
3135
2.83k
    ascFile.addNote(f.str().c_str());
3136
2.83k
    return true;
3137
2.83k
  }
3138
76.7k
  type=int(libwps::read16(input));
3139
76.7k
  if (type==0) // fixme: find if this is a note, so that we can retrieve it
3140
67.1k
    f << "chart/note/...,";
3141
9.55k
  else if (type==1)
3142
6.79k
    f << "file,";
3143
2.76k
  else
3144
2.76k
  {
3145
2.76k
    WPS_DEBUG_MSG(("LotusParser::readLinkZone: find unknown type\n"));
3146
2.76k
    f << "##type=" << type << ",";
3147
2.76k
    ascFile.addPos(pos);
3148
2.76k
    ascFile.addNote(f.str().c_str());
3149
2.76k
    return true;
3150
2.76k
  }
3151
73.9k
  f << "ID=" << int(libwps::readU8(input)) << ","; // 0,19,42,53,ff
3152
73.9k
  auto id = int(libwps::readU8(input));
3153
73.9k
  f << "id=" << id << ",";
3154
3155
73.9k
  Link link;
3156
  // C0: current selection
3157
  // ----- chart ----:
3158
  // G[23-28] color series 0->5
3159
  // G[2a-2f] hatch series 0->5
3160
  // G[39-3e]: data series 0, 1, ...
3161
  // G[3f]: chart axis 0
3162
  // G[40-45]: legend serie 0->5
3163
  // G[47][22,27,2c,31,36,3b,40,45,4a,4f,54,59,5e]: data serie 6-18 (+1 label)
3164
  // G[48][23,28,2d,32]: serie 19-22 (+1 label)
3165
3166
  // G[4c-4e]: unit axis x,y,ysecond
3167
  // G[4f-51]: label axis x,y,ysecond
3168
  // G[52-55]: title, subtile, note1, note2
3169
  // ----- unknown -----:
3170
  // P3: can contains often a basic name or cells zone
3171
  // Q[0-2]: contains often <<XXX>>YYY: link to another sheetname?
3172
252k
  for (int i=0; i<14; ++i)
3173
250k
  {
3174
250k
    auto c=char(libwps::readU8(input));
3175
250k
    if (!c) break;
3176
178k
    link.m_name += c;
3177
178k
  }
3178
73.9k
  f << "\"" << link.m_name << "\",";
3179
73.9k
  input->seek(pos+4+18, librevenge::RVNG_SEEK_SET);
3180
73.9k
  bool ok=true;
3181
73.9k
  switch (type)
3182
73.9k
  {
3183
67.1k
  case 0:
3184
67.1k
    if (sz<26)
3185
771
    {
3186
771
      WPS_DEBUG_MSG(("LotusParser::readLinkZone: the chart zone seems too short\n"));
3187
771
      f << "###";
3188
771
      break;
3189
771
    }
3190
199k
    for (int i=0; i<2; ++i)
3191
132k
    {
3192
132k
      auto row=int(libwps::readU16(input));
3193
132k
      auto table=int(libwps::readU8(input));
3194
132k
      auto col=int(libwps::readU8(input));
3195
132k
      link.m_cells[i]=WPSVec3i(col,row,table);
3196
132k
      f << "C" << col << "-" << row;
3197
132k
      if (table) f << "[" << table << "]";
3198
132k
      if (i==0)
3199
66.4k
        f << "<->";
3200
66.4k
      else
3201
66.4k
        f << ",";
3202
132k
    }
3203
66.4k
    break;
3204
6.79k
  case 1:
3205
6.79k
  {
3206
6.79k
    if (sz>18)
3207
6.79k
      link.m_linkName=libwps_tools_win::Font::unicodeString(input.get(), static_cast<unsigned long>(sz-18), getDefaultFontType());
3208
6.79k
    f << "link=" << link.m_linkName.cstr() << ",";
3209
6.79k
    break;
3210
67.1k
  }
3211
0
  default:
3212
0
    ok=false;
3213
0
    WPS_DEBUG_MSG(("LotusParser::readLinkZone: find unknown type\n"));
3214
0
    f << "###";
3215
0
    break;
3216
73.9k
  }
3217
73.9k
  if (ok) m_state->m_linkIdToLinkMap.insert(std::multimap<int,Link>::value_type(id, link));
3218
73.9k
  if (input->tell()!=pos+4+sz && input->tell()+1!=pos+4+sz)
3219
296
  {
3220
296
    WPS_DEBUG_MSG(("LotusParser::readLinkZone: the zone seems too short\n"));
3221
296
    f << "##";
3222
296
    ascFile.addDelimiter(input->tell(), '|');
3223
296
  }
3224
73.9k
  ascFile.addPos(pos);
3225
73.9k
  ascFile.addNote(f.str().c_str());
3226
73.9k
  return true;
3227
73.9k
}
3228
3229
// ----------------------------------------------------------------------
3230
// Header/Footer/PageDim
3231
// ----------------------------------------------------------------------
3232
bool LotusParser::readDocumentInfoMac(std::shared_ptr<WPSStream> stream, long endPos)
3233
1.73k
{
3234
1.73k
  RVNGInputStreamPtr &input=stream->m_input;
3235
1.73k
  libwps::DebugFile &ascFile=stream->m_ascii;
3236
1.73k
  libwps::DebugStream f;
3237
3238
1.73k
  long pos = input->tell();
3239
1.73k
  f << "Entries(DocMacInfo):";
3240
1.73k
  if (endPos-pos!=51)
3241
99
  {
3242
99
    WPS_DEBUG_MSG(("LotusParser::readDocumentInfoMac: the zone size seems bad\n"));
3243
99
    f << "###";
3244
99
    ascFile.addPos(pos-6);
3245
99
    ascFile.addNote(f.str().c_str());
3246
99
    return true;
3247
99
  }
3248
1.63k
  int dim[7];
3249
13.1k
  for (int i=0; i<7; ++i)
3250
11.4k
  {
3251
11.4k
    auto val=int(libwps::read8(input));
3252
11.4k
    if (i==0)
3253
1.63k
      f << "dim[unkn]=";
3254
9.83k
    else if (i==1)
3255
1.63k
      f << "margins=[";
3256
8.19k
    else if (i==5)
3257
1.63k
      f << "pagesize=[";
3258
11.4k
    dim[i]=int(libwps::read16(input));
3259
11.4k
    f << dim[i];
3260
11.4k
    if (val) f << "[" << val << "]";
3261
11.4k
    val=int(libwps::read8(input)); // always 0
3262
11.4k
    if (val) f << "[" << val << "]";
3263
11.4k
    f << ",";
3264
11.4k
    if (i==4 || i==6) f << "],";
3265
11.4k
  }
3266
  // check order
3267
1.63k
  if (dim[5]>dim[1]+dim[3] && dim[6]>dim[2]+dim[4])
3268
936
  {
3269
936
    m_state->m_pageSpan.setFormWidth(dim[5]);
3270
936
    m_state->m_pageSpan.setFormLength(dim[6]);
3271
936
    m_state->m_pageSpan.setMarginLeft(dim[1]);
3272
936
    m_state->m_pageSpan.setMarginTop(dim[2]);
3273
936
    m_state->m_pageSpan.setMarginRight(dim[3]);
3274
936
    m_state->m_pageSpan.setMarginBottom(dim[4]);
3275
936
  }
3276
703
  else
3277
703
    f << "###";
3278
1.63k
  f << "unkn=[";
3279
9.83k
  for (int i=0; i<5; ++i)   // 1,1,1,100|inf,1
3280
8.19k
  {
3281
8.19k
    auto val=int(libwps::read16(input));
3282
8.19k
    if (val==9999)
3283
1.06k
      f << "inf,";
3284
7.13k
    else if (val)
3285
6.58k
      f << val << ",";
3286
549
    else
3287
549
      f << "_,";
3288
8.19k
  }
3289
1.63k
  f << "],";
3290
22.9k
  for (int i=0; i<13; ++i)   // always 0?
3291
21.3k
  {
3292
21.3k
    auto val=int(libwps::read8(input));
3293
21.3k
    if (val)
3294
7.45k
      f << "g" << i << "=" << val << ",";
3295
21.3k
  }
3296
1.63k
  ascFile.addPos(pos-6);
3297
1.63k
  ascFile.addNote(f.str().c_str());
3298
1.63k
  return true;
3299
1.73k
}
3300
3301
////////////////////////////////////////////////////////////
3302
//   decode
3303
////////////////////////////////////////////////////////////
3304
RVNGInputStreamPtr LotusParser::decodeStream(RVNGInputStreamPtr input, long endPos, std::vector<uint8_t> const &key)
3305
1.18k
{
3306
1.18k
  if (!input || key.size()!=16)
3307
0
  {
3308
0
    WPS_DEBUG_MSG(("LotusParser::decodeStream: the arguments seems bad\n"));
3309
0
    return RVNGInputStreamPtr();
3310
0
  }
3311
1.18k
  long actPos=input->tell();
3312
1.18k
  input->seek(0,librevenge::RVNG_SEEK_SET);
3313
1.18k
  librevenge::RVNGBinaryData data;
3314
1.18k
  if (!libwps::readData(input, static_cast<unsigned long>(endPos), data) || long(data.size())!=endPos || !data.getDataBuffer())
3315
0
  {
3316
0
    WPS_DEBUG_MSG(("LotusParser::decodeStream: can not read the original input\n"));
3317
0
    return RVNGInputStreamPtr();
3318
0
  }
3319
1.18k
  auto *buf=const_cast<unsigned char *>(data.getDataBuffer());
3320
1.18k
  input->seek(actPos,librevenge::RVNG_SEEK_SET);
3321
1.18k
  uint8_t d7=0;
3322
1.18k
  bool transform=true;
3323
608k
  while (!input->isEnd())
3324
608k
  {
3325
608k
    long pos=input->tell();
3326
608k
    if (pos+4>endPos) break;
3327
608k
    auto type=int(libwps::readU16(input));
3328
608k
    auto sSz=int(libwps::readU16(input));
3329
608k
    if (pos+4+sSz>endPos)
3330
980
    {
3331
980
      input->seek(pos,librevenge::RVNG_SEEK_SET);
3332
980
      break;
3333
980
    }
3334
    //   Special case :
3335
    // 123 files:
3336
    //   - the style zone (between 0x10e and 0x10f) is not transformed
3337
    //   - the stack1[open|close] field are not transformed
3338
607k
    if (type==0x10e)
3339
1.45k
      transform=false;
3340
605k
    else if (type==0x10f)
3341
1.14k
      transform=true;
3342
607k
    if (type==0x104 || type==0x105 || !transform)
3343
76.3k
    {
3344
76.3k
      input->seek(pos+4+sSz,librevenge::RVNG_SEEK_SET);
3345
76.3k
      continue;
3346
76.3k
    }
3347
530k
    auto d4=uint8_t(sSz);
3348
530k
    uint8_t d5=key[13];
3349
4.89M
    for (int i=0; i<sSz; ++i)
3350
4.36M
    {
3351
4.36M
      auto c=uint8_t(libwps::readU8(input));
3352
4.36M
      buf[pos+4+i]=(c^key[d7&0xf]);
3353
4.36M
      d7=uint8_t(c+d4);
3354
4.36M
      d4=uint8_t(d4+d5++);
3355
4.36M
    }
3356
530k
  }
3357
1.18k
  if (input->tell()!=endPos)
3358
1.12k
  {
3359
1.12k
    WPS_DEBUG_MSG(("LotusParser::decodeStream: can not decode the end of the file, data may be bad %lx %lx\n", static_cast<unsigned long>(input->tell()), static_cast<unsigned long>(endPos)));
3360
1.12k
  }
3361
1.18k
  RVNGInputStreamPtr res(new WPSStringStream(data.getDataBuffer(), static_cast<unsigned int>(endPos)));
3362
1.18k
  res->seek(actPos, librevenge::RVNG_SEEK_SET);
3363
1.18k
  return res;
3364
1.18k
}
3365
3366
std::vector<uint8_t> LotusParser::retrievePasswordKeys(std::vector<uint8_t> const &fileKeys)
3367
1.28k
{
3368
  /* let try to detect short password (|password|<=14) by using the
3369
     fact that fileKeys differ from the keys in two positions.
3370
3371
     If the password length is less or equal to 12:
3372
     Using fileKeys[12] and fileKeys[14], we can "retrieve"
3373
     the password length. Then knowing this length, fileKeys[14]
3374
     and fileKeys[15] give us the key. Finally, we can retrieve the
3375
     password and check if it gives us again fileKeys.
3376
3377
     We can also test password with length 13 or 14 similarly.
3378
3379
     Note: if |password|>14, we can detect it by testing 256*256 posibilities, but :-~
3380
   */
3381
1.28k
  std::vector<uint8_t> res;
3382
1.28k
  if (fileKeys.size()!=16)
3383
0
  {
3384
0
    WPS_DEBUG_MSG(("LotusParser::retrievePasswordKeys: the file keys seems bad\n"));
3385
0
    return res;
3386
0
  }
3387
1.28k
  static uint8_t const defValues[]=
3388
1.28k
  {
3389
1.28k
    0xb9,0x5f, 0xd7,0x31, 0xdb,0x75, 9,0x72,
3390
1.28k
    0x5d,0x85, 0x32,0x11, 0x5,0x11, 0x58,0
3391
1.28k
  };
3392
1.28k
  std::map<uint8_t,size_t> diffToPosMap;
3393
19.2k
  for (size_t i=0; i<14; ++i)
3394
17.9k
    diffToPosMap[defValues[i+2]^defValues[i]]=i;
3395
1.28k
  uint8_t diff12=fileKeys[12]^fileKeys[14];
3396
1.28k
  std::vector<size_t> posToTest;
3397
1.28k
  if (diffToPosMap.find(diff12)!=diffToPosMap.end() && diffToPosMap.find(diff12)->second+2<14)
3398
48
  {
3399
48
    posToTest.push_back(diffToPosMap.find(diff12)->second+2);
3400
    // defValues[0]^defValues[2]=defValues[1]^defValues[3]=0x6e => we must add by hand this position
3401
48
    if (diff12==0x6e)
3402
9
      posToTest.push_back(2);
3403
48
  }
3404
  // check also password with length 13 or 14
3405
1.28k
  posToTest.push_back(0);
3406
1.28k
  posToTest.push_back(1);
3407
1.28k
  for (size_t actPos : posToTest)
3408
1.43k
  {
3409
1.43k
    auto key=uint16_t(((fileKeys[14]^defValues[actPos])<<8)|(fileKeys[15]^defValues[actPos+1]));
3410
1.43k
    res=fileKeys;
3411
1.43k
    res[7]=uint8_t(res[7]^key);
3412
1.43k
    res[13]=uint8_t(res[13]^(key>>8));
3413
    // now build the password
3414
1.43k
    std::string password;
3415
20.9k
    for (size_t i=0; i<size_t(16-actPos-2); ++i)
3416
19.5k
      password+=char(res[i]^(key>>((i%2)==0 ? 8 : 0)));
3417
    // check if the password is correct
3418
1.43k
    uint16_t resKey;
3419
1.43k
    std::vector<uint8_t> resKeys;
3420
1.43k
    if (libwps::encodeLotusPassword(password.c_str(), resKey, resKeys, defValues) && key==resKey && res==resKeys)
3421
1.18k
    {
3422
1.18k
      WPS_DEBUG_MSG(("LotusParser::retrievePasswordKeys: Find password %s\n", password.c_str()));
3423
1.18k
      return res;
3424
1.18k
    }
3425
1.43k
  }
3426
94
  return std::vector<uint8_t>();
3427
1.28k
}
3428
3429
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */