Coverage Report

Created: 2026-04-29 07:28

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