Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/LotusChart.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 <cmath>
26
#include <sstream>
27
#include <limits>
28
#include <map>
29
#include <stack>
30
#include <utility>
31
32
#include <librevenge-stream/librevenge-stream.h>
33
34
#include "libwps_internal.h"
35
#include "libwps_tools_win.h"
36
37
#include "WKSChart.h"
38
#include "WKSContentListener.h"
39
#include "WPSEntry.h"
40
#include "WPSFont.h"
41
#include "WPSPosition.h"
42
#include "WPSStream.h"
43
44
#include "Lotus.h"
45
#include "LotusStyleManager.h"
46
47
#include "LotusChart.h"
48
49
namespace LotusChartInternal
50
{
51
52
///////////////////////////////////////////////////////////////////
53
//! the chart of a Lotus Pro Dos
54
class Chart final : public WKSChart
55
{
56
public:
57
  //! constructor
58
  explicit Chart(LotusChart &parser, std::shared_ptr<WPSStream> const &stream)
59
56.8k
    : WKSChart()
60
56.8k
    , m_fileType(-1)
61
56.8k
    , m_hasLegend(false)
62
56.8k
    , m_fileSerieStyles(false)
63
56.8k
    , m_parser(parser)
64
56.8k
    , m_stream(stream)
65
56.8k
  {
66
170k
    for (auto &at : m_fontAttributes) at=0;
67
56.8k
  }
68
  //! send the zone content (called when the zone is of text type)
69
  void sendContent(TextZone const &zone, WPSListenerPtr &listener) const final;
70
  //! the chart type
71
  int m_fileType;
72
  //! a flag to know if we have some legend
73
  bool m_hasLegend;
74
  //! a flag to know if we have seen some serie style
75
  bool m_fileSerieStyles;
76
  //! wk3 serie format
77
  struct SerieFormat
78
  {
79
    //! constructor
80
    SerieFormat()
81
397k
      : m_color(0)
82
397k
      , m_hash(0)
83
397k
      , m_yAxis(1)
84
397k
      , m_format(0)
85
397k
      , m_align(0)
86
397k
    {
87
397k
    }
88
    //! the color
89
    int m_color;
90
    //! the hash
91
    int m_hash;
92
    //! the y axis
93
    int m_yAxis;
94
    //! the format
95
    int m_format;
96
    //! the label alignement
97
    int m_align;
98
  };
99
100
  //! the series format
101
  SerieFormat m_serieFormats[7];
102
  //! the font attributes : title, axis, other
103
  uint32_t m_fontAttributes[3]; // USEME
104
protected:
105
  //! the parser
106
  LotusChart &m_parser;
107
  //! the input stream
108
  std::shared_ptr<WPSStream> m_stream;
109
};
110
111
void Chart::sendContent(TextZone const &zone, WPSListenerPtr &listener) const
112
2.79k
{
113
2.79k
  if (!listener.get())
114
0
  {
115
0
    WPS_DEBUG_MSG(("LotusChartInternal::Chart::sendContent: no listener\n"));
116
0
    return;
117
0
  }
118
2.79k
  long pos = m_stream->m_input->tell();
119
2.79k
  listener->setFont(zone.m_font);
120
2.79k
  bool sendText=false;
121
2.79k
  for (auto const &e : zone.m_textEntryList)
122
4.75k
  {
123
4.75k
    if (!e.valid()) continue;
124
4.75k
    if (sendText) listener->insertEOL(true);
125
4.75k
    m_parser.sendText(m_stream, e);
126
4.75k
    sendText=true;
127
4.75k
  }
128
2.79k
  m_stream->m_input->seek(pos, librevenge::RVNG_SEEK_SET);
129
2.79k
}
130
131
//! the state of LotusChart
132
struct State
133
{
134
  //! constructor
135
  State()
136
129k
    : m_version(-1)
137
129k
    , m_idChartMap()
138
129k
    , m_chartId(-1)
139
129k
  {
140
129k
  }
141
  /** returns a chart corresponding to an id, create it if needed.
142
143
    \note almost always a chart definition appears before the
144
    other chart's structures, but this is not always true...
145
   */
146
  std::shared_ptr<Chart> getChart(int id, LotusChart &parser, std::shared_ptr<WPSStream> stream)
147
358k
  {
148
358k
    if (m_idChartMap.find(id)!=m_idChartMap.end())
149
301k
      return m_idChartMap.find(id)->second;
150
56.8k
    std::shared_ptr<Chart> newChart(new LotusChartInternal::Chart(parser, stream));
151
56.8k
    if (id>=0)
152
26.9k
      m_idChartMap[id]=newChart;
153
29.8k
    else
154
29.8k
    {
155
29.8k
      WPS_DEBUG_MSG(("LotusChartInternal::State::getChart: call with id=%d, create temporary chart\n", id));
156
29.8k
    }
157
56.8k
    return newChart;
158
159
358k
  }
160
  //! the file version
161
  int m_version;
162
  //! list of chart
163
  std::map<int, std::shared_ptr<Chart> > m_idChartMap;
164
  //! the current chart id(wps3Mac)
165
  int m_chartId;
166
};
167
168
}
169
170
// constructor, destructor
171
LotusChart::LotusChart(LotusParser &parser)
172
64.7k
  : m_listener()
173
64.7k
  , m_mainParser(parser)
174
64.7k
  , m_styleManager(parser.m_styleManager)
175
64.7k
  , m_state(new LotusChartInternal::State)
176
64.7k
{
177
64.7k
}
178
179
LotusChart::~LotusChart()
180
64.7k
{
181
64.7k
}
182
183
void LotusChart::cleanState()
184
64.6k
{
185
64.6k
  m_state.reset(new LotusChartInternal::State);
186
64.6k
}
187
188
std::map<std::string, int> LotusChart::getNameToChartIdMap() const
189
28.5k
{
190
28.5k
  std::map<std::string, int> res;
191
28.5k
  for (auto const &it : m_state->m_idChartMap)
192
6.05k
  {
193
6.05k
    auto const &chart = it.second;
194
6.05k
    if (chart || !chart->m_name.empty())
195
6.05k
      res[chart->m_name.cstr()]=it.first;
196
6.05k
  }
197
28.5k
  return res;
198
28.5k
}
199
200
void LotusChart::updateState()
201
28.5k
{
202
28.5k
  std::set<int> toRemoveSet;
203
  /* In pc's wk3 files, the current chart is unamed while the others
204
     have a name.  So if we have more than one chart, suppose that
205
     the creator has named all its charts and remove the unamed
206
     chart to avoid dupplication...
207
208
     In mac's wk3 files, all used files are named, so this must be ok
209
   */
210
28.5k
  bool removeNoName=version()==1 && m_state->m_idChartMap.size()>1;
211
28.5k
  for (auto const &it : m_state->m_idChartMap)
212
18.8k
  {
213
18.8k
    auto id=it.first;
214
18.8k
    auto chart=it.second;
215
18.8k
    if (!chart || (removeNoName && chart->m_name.empty()))
216
3.02k
    {
217
3.02k
      toRemoveSet.insert(id);
218
3.02k
      continue;
219
3.02k
    }
220
15.8k
    updateChart(*chart, id);
221
    // check if the chart contain at least one serie
222
15.8k
    bool findSomeSerie=false;
223
15.8k
    for (auto cIt : chart->getIdSerieMap())
224
21.3k
    {
225
21.3k
      if (cIt.second.m_ranges[0].valid(cIt.second.m_ranges[1]))
226
6.05k
      {
227
6.05k
        findSomeSerie=true;
228
6.05k
        break;
229
6.05k
      }
230
21.3k
    }
231
15.8k
    if (!findSomeSerie)
232
9.76k
      toRemoveSet.insert(id);
233
15.8k
  }
234
28.5k
  for (auto id : toRemoveSet)
235
12.7k
    m_state->m_idChartMap.erase(id);
236
28.5k
}
237
238
int LotusChart::getNumCharts() const
239
4.50k
{
240
4.50k
  return int(m_state->m_idChartMap.size());
241
4.50k
}
242
243
int LotusChart::version() const
244
85.0k
{
245
85.0k
  if (m_state->m_version<0)
246
29.5k
    m_state->m_version=m_mainParser.version();
247
85.0k
  return m_state->m_version;
248
85.0k
}
249
250
////////////////////////////////////////////////////////////
251
// low level
252
253
////////////////////////////////////////////////////////////
254
// general
255
////////////////////////////////////////////////////////////
256
257
bool LotusChart::readChart(std::shared_ptr<WPSStream> stream)
258
22.8k
{
259
22.8k
  RVNGInputStreamPtr &input=stream->m_input;
260
22.8k
  libwps::DebugFile &ascFile=stream->m_ascii;
261
22.8k
  libwps::DebugStream f;
262
22.8k
  long pos = input->tell();
263
22.8k
  auto type = long(libwps::read16(input));
264
22.8k
  if (type != 0x11)
265
0
  {
266
0
    WPS_DEBUG_MSG(("LotusChart::readChart: not a chart name\n"));
267
0
    return false;
268
0
  }
269
22.8k
  auto sz = long(libwps::readU16(input));
270
22.8k
  long endPos=pos+4+sz;
271
22.8k
  f << "Entries(ChartDef):sz=" << sz << ",";
272
22.8k
  if (sz < 0xB2) // find b2 or b3
273
1.13k
  {
274
1.13k
    WPS_DEBUG_MSG(("LotusChart::readChart: chart name is too short\n"));
275
1.13k
    f << "###";
276
1.13k
    ascFile.addPos(pos);
277
1.13k
    ascFile.addNote(f.str().c_str());
278
1.13k
    return true;
279
1.13k
  }
280
21.7k
  auto id=int(libwps::readU8(input));
281
21.7k
  auto chart=m_state->getChart(id, *this, stream);
282
21.7k
  f << "id=" << id << ",";
283
21.7k
  std::string name("");
284
122k
  for (int i=0; i<16; ++i)
285
121k
  {
286
121k
    unsigned char c = libwps::readU8(input);
287
121k
    if (c == '\0') break;
288
100k
    name+=char(c);
289
100k
  }
290
21.7k
  if (!name.empty())
291
14.8k
  {
292
14.8k
    chart->m_name=m_mainParser.getStringForLMBCS(name);
293
14.8k
    f << m_mainParser.getDebugStringForLMBCS(name) << ",";
294
14.8k
  }
295
21.7k
  input->seek(pos+4+17, librevenge::RVNG_SEEK_SET);
296
  // group 0: title, 1: axis name, 2: axis data+note+subtitle+legend
297
21.7k
  int val;
298
86.8k
  for (int i=0; i<3; ++i) // useme
299
65.1k
  {
300
65.1k
    val=int(libwps::readU8(input));
301
65.1k
    if (val<9)
302
50.0k
    {
303
50.0k
      char const * fType[9]= {"Standart", "Serif", "SerifB", "SerifI", "SerifBI", "Serif[no]", "SerifB[no]", "SerifI[no]", "SerifBI[no]"};
304
50.0k
      f << "font[group" << i << "]=" << fType[val] << ",";
305
50.0k
      if (val && val%2==0)
306
769
        chart->m_fontAttributes[i]|=WPS_BOLD_BIT;
307
50.0k
      if (val && (val+1)%4<=1)
308
662
        chart->m_fontAttributes[i]|=WPS_ITALICS_BIT;
309
50.0k
    }
310
15.0k
    else
311
15.0k
      f << "font[group" << i << "]=" << val << ",";
312
65.1k
  }
313
173k
  for (int i=0; i<7; ++i)
314
151k
  {
315
151k
    chart->m_serieFormats[i].m_color=val=int(libwps::readU8(input));
316
151k
    if (!val) continue; // auto
317
43.7k
    if (val==255)
318
2.15k
      f << "serie" << i << "[color]=range,";
319
41.5k
    else if (val==254)
320
22
      f << "serie" << i << "[color]=hidden,";
321
41.5k
    else
322
41.5k
      f << "serie" << i << "[color]=" << val << ",";
323
43.7k
  }
324
151k
  for (int i=0; i<6; ++i)
325
130k
  {
326
130k
    chart->m_serieFormats[i].m_hash=val=int(libwps::readU8(input));
327
130k
    if (!val) continue;
328
38.8k
    if (val==255)
329
3.76k
      f << "hash[serie" << i << "]=range,";
330
35.1k
    else
331
35.1k
      f << "hash[serie" << i << "]=" << val << ",";
332
38.8k
  }
333
21.7k
  ascFile.addPos(pos);
334
21.7k
  ascFile.addNote(f.str().c_str());
335
336
21.7k
  pos=input->tell();
337
21.7k
  f.str("");
338
21.7k
  f << "ChartDef-A:";
339
21.7k
  std::string fileName;
340
21.7k
  bool fileNameEnd=false;
341
151k
  for (int i=0; i<6; ++i)   // small number
342
130k
  {
343
130k
    val=int(libwps::read8(input));
344
130k
    if (!val)
345
94.0k
    {
346
94.0k
      fileNameEnd=true;
347
94.0k
      continue;
348
94.0k
    }
349
36.1k
    if (!fileNameEnd) fileName.push_back((char)val);
350
36.1k
  }
351
86.8k
  for (int i=0; i<3; ++i) // useme
352
65.1k
  {
353
65.1k
    val=int(libwps::read8(input));
354
65.1k
    if (val) f << "fSize[group" << i << "]=" << val << ",";
355
65.1k
  }
356
21.7k
  val=int(libwps::readU8(input));
357
21.7k
  bool showGridY=(val&2);
358
21.7k
  if (val<=2)
359
8.04k
  {
360
8.04k
    chart->getAxis(0).m_showGrid=(val&1);
361
8.04k
    chart->getAxis(1).m_showGrid=(val&2);
362
8.04k
    if (val&1) f << "X,";
363
8.04k
    if (val&2) f << "Y,";
364
8.04k
  }
365
13.6k
  else f << "##grid" <<  "=" << val << ",";
366
21.7k
  val=int(libwps::readU8(input)); // can be 0: if ok,1: bw,2: color
367
21.7k
  if (val==1) f << "color=bw,";
368
18.1k
  else if (val==2) f << "color,";
369
18.0k
  else if (val) f << "##color" <<  "=" << val << ",";
370
371
21.7k
  auto const &chartType=chart->m_fileType=int(libwps::readU8(input));
372
21.7k
  chart->m_type=WKSChart::Serie::S_Bar;
373
21.7k
  switch (chartType)
374
21.7k
  {
375
6.45k
  case 0: // line
376
6.45k
    chart->m_type=WKSChart::Serie::S_Line;
377
6.45k
    break;
378
2.95k
  case 1: // bar
379
2.95k
    break;
380
1.65k
  case 2: // XY
381
1.65k
    chart->m_type=WKSChart::Serie::S_Scatter;
382
1.65k
    break;
383
233
  case 3: // bar stacked
384
233
    chart->m_dataStacked=true;
385
233
    break;
386
4.13k
  case 4: // pie
387
4.13k
    chart->m_type=WKSChart::Serie::S_Circle;
388
4.13k
    break;
389
686
  case 5: // min-max
390
686
    chart->m_type=WKSChart::Serie::S_Stock;
391
686
    break;
392
836
  case 6: // radar (checkme)
393
836
    chart->m_type=WKSChart::Serie::S_Radar;
394
836
    break;
395
746
  case 7: // mixed
396
746
    break;
397
3.99k
  default:
398
3.99k
    WPS_DEBUG_MSG(("LotusChart::readChart: unknown chart type\n"));
399
3.99k
    f << "###";
400
21.7k
  }
401
21.7k
  f << "type=" << chartType << ",";
402
403
21.7k
  char const *axisNames[]= {"X","Y","YSecond"};
404
86.8k
  for (int i=0; i<3; ++i)
405
65.1k
  {
406
65.1k
    val=int(libwps::read8(input));
407
    // 0=auto
408
65.1k
    if (val==-1)
409
1.62k
    {
410
1.62k
      chart->getAxis(i).m_automaticScaling=false;
411
1.62k
      f << "scale[" << axisNames[i] << "]=manual,";
412
1.62k
    }
413
63.4k
    else if (val) f << "###scale[" << axisNames[i] << "]=" << val << ",";
414
65.1k
  }
415
21.7k
  for (auto axisName : axisNames) // useme
416
65.1k
  {
417
65.1k
    val=int(libwps::read8(input));
418
    // 0=auto
419
65.1k
    if (val==-1) f << "setExponent[" << axisName << "]=manual,";
420
60.4k
    else if (val) f << "###setExponent[" << axisName << "]=" << val << ",";
421
65.1k
  }
422
21.7k
  for (auto axisName : axisNames) // useme
423
65.1k
  {
424
65.1k
    val=int(libwps::read8(input));
425
    // 0=auto
426
65.1k
    if (val==-1) f << "legend[" << axisName << "]=manual,";
427
63.6k
    else if (val==1) f << "legend[" << axisName << "]=none,";
428
59.7k
    else if (val) f << "###legend[" << axisName << "]=" << val << ",";
429
65.1k
  }
430
86.8k
  for (int i=0; i<3; ++i)
431
65.1k
  {
432
65.1k
    val=int(libwps::read8(input));
433
    // 0=normal
434
65.1k
    auto &axis=chart->getAxis(i);
435
65.1k
    if (val==1)
436
746
    {
437
746
      f << "axis[" << axisNames[i] << "]=log,";
438
746
      axis.m_type= WKSChart::Axis::A_Logarithmic;
439
746
    }
440
64.3k
    else
441
64.3k
    {
442
64.3k
      axis.m_type= WKSChart::Axis::A_Numeric;
443
64.3k
      if (val) f << "###axis[" << axisNames[i] << "]=" << val << ",";
444
64.3k
    }
445
65.1k
  }
446
21.7k
  for (auto axisName : axisNames)
447
65.1k
  {
448
65.1k
    val=int(libwps::read8(input));
449
    // 0=auto
450
65.1k
    if (val==-1) f << "setWidth[" << axisName << "]=manual,";
451
64.1k
    else if (val) f << "###setWidth[" << axisName << "]=" << val << ",";
452
65.1k
  }
453
21.7k
  ascFile.addPos(pos);
454
21.7k
  ascFile.addNote(f.str().c_str());
455
456
21.7k
  pos=input->tell();
457
21.7k
  f.str("");
458
21.7k
  f << "ChartDef-B:";
459
151k
  for (int i=0; i<6; ++i)
460
130k
  {
461
130k
    chart->m_serieFormats[i].m_yAxis=val=int(libwps::read8(input));
462
130k
    if (val==1) continue; // primary axis
463
65.8k
    if (val==2)
464
1.81k
      f << "serie" << i << "[axis]=secondary,";
465
64.0k
    else
466
64.0k
      f << "##serie" << i << "[axis]=" << val << ",";
467
65.8k
  }
468
151k
  for (int i=0; i<6; ++i)   // small number
469
130k
  {
470
130k
    chart->m_serieFormats[i].m_format=val=int(libwps::readU8(input));
471
130k
    if (!val) continue;
472
54.8k
    if (val<5)
473
18.8k
    {
474
18.8k
      char const *wh[]= {"both", "lines", "symbols", "neither", "area"};
475
18.8k
      f << "serie" << i << "[format]=" << wh[val] << ",";
476
18.8k
    }
477
36.0k
    else
478
36.0k
      f << "##serie" << i << "[format]=" << val << ",";
479
54.8k
  }
480
151k
  for (int i=0; i<6; ++i)   // small number
481
130k
  {
482
130k
    chart->m_serieFormats[i].m_align=val=int(libwps::readU8(input));
483
130k
    if (!val) continue;
484
41.3k
    if (val<5)
485
6.72k
    {
486
6.72k
      char const *wh[]= {"center", "right", "below", "left", "above"};
487
6.72k
      f << "serie" << i << "[align]=" << wh[val] << ",";
488
6.72k
    }
489
34.6k
    else
490
34.6k
      f << "##serie" << i << "[align]=" << val << ",";
491
41.3k
  }
492
21.7k
  ascFile.addPos(pos);
493
21.7k
  ascFile.addNote(f.str().c_str());
494
495
21.7k
  pos=input->tell();
496
21.7k
  f.str("");
497
21.7k
  f << "ChartDef-C:";
498
173k
  for (int i=0; i<7; ++i)   // small number expect f18=0|4|64
499
151k
  {
500
151k
    val=int(libwps::read8(input));
501
151k
    if (i==0)
502
21.7k
    {
503
21.7k
      chart->getAxis(1).m_showGrid=false;
504
21.7k
      chart->getAxis(2).m_showGrid=false;
505
21.7k
      if (val==0)   // 0: means y primary
506
9.33k
      {
507
9.33k
        if (showGridY) chart->getAxis(1).m_showGrid=true;
508
9.33k
      }
509
12.3k
      else if (val==1)
510
643
      {
511
643
        if (showGridY) chart->getAxis(2).m_showGrid=true;
512
643
        f << "grid[hori]=ysecond,";
513
643
      }
514
11.7k
      else if (val==2)
515
5.43k
      {
516
5.43k
        if (showGridY)
517
5.15k
        {
518
5.15k
          chart->getAxis(1).m_showGrid=true;
519
5.15k
          chart->getAxis(2).m_showGrid=true;
520
5.15k
        }
521
5.43k
        f << "grid[hori]=y+ysecond,";
522
5.43k
      }
523
6.28k
      else
524
6.28k
        f << "##grid[hori]=" << val << ",";
525
21.7k
      continue;
526
21.7k
    }
527
130k
    else if (i==1)
528
21.7k
    {
529
21.7k
      if (val&1)
530
5.12k
      {
531
5.12k
        chart->m_dataVertical=true;
532
5.12k
        f << "swapXY,"; // Y is horizontal, X vertical
533
5.12k
      }
534
21.7k
      val &= 0xfe;
535
21.7k
    }
536
108k
    else if (i==3)
537
21.7k
    {
538
21.7k
      if (val&1)
539
5.10k
      {
540
5.10k
        chart->m_dataPercentStacked=true;
541
5.10k
        f << "percentage,";
542
5.10k
      }
543
21.7k
      val &= 0xfe;
544
21.7k
    }
545
86.8k
    else if (i==4)
546
21.7k
    {
547
21.7k
      if (val&1)
548
4.36k
      {
549
4.36k
        chart->m_dataStacked=true;
550
4.36k
        f << "stacked,";
551
4.36k
      }
552
21.7k
      val &= 0xfe;
553
21.7k
    }
554
65.1k
    else if (i==5)
555
21.7k
    {
556
21.7k
      if (val&1)
557
5.33k
      {
558
5.33k
        chart->m_is3D=true;;
559
5.33k
        f << "drop[shadow],"; // ie. 2.5D
560
5.33k
      }
561
21.7k
      if (val&2)
562
5.83k
      {
563
5.83k
        chart->m_is3D=true;;
564
5.83k
        chart->m_is3DDeep=true;;
565
5.83k
        f << "3d[range],";  // ie 3D
566
5.83k
      }
567
21.7k
      if (val&4) f << "show[table],"; // show data table below the chart
568
      // plot area border
569
21.7k
      if (val&0x10) f << "noBorder[L],";
570
21.7k
      if (val&0x20) f << "noBorder[R],";
571
21.7k
      if (val&0x40) f << "noBorder[T],";
572
21.7k
      if (val&0x80) f << "noBorder[B],";
573
21.7k
      val &= 0x8;
574
21.7k
    }
575
130k
    if (val) f << "f" << i << "=" << val << ",";
576
130k
  }
577
21.7k
  for (auto axisName : axisNames)
578
65.1k
  {
579
    // useme
580
65.1k
    val=int(libwps::read8(input));
581
65.1k
    if (val) f << "color[" << axisName << "]=" << val << ",";
582
65.1k
  }
583
21.7k
  val=int(libwps::read16(input));
584
21.7k
  if (val!=1) f << "ticks=" << val << ",";
585
21.7k
  for (auto axisName : axisNames)
586
65.1k
  {
587
65.1k
    val=int(libwps::read16(input));
588
65.1k
    if (val!=14) f << "width" << axisName << "=" << val << ",";;
589
65.1k
  }
590
21.7k
  val=int(libwps::read16(input));
591
21.7k
  if (val) f << "ext=" << val << ",";
592
65.1k
  for (int i=0; i<2; ++i)
593
43.4k
  {
594
43.4k
    val=int(libwps::read8(input));
595
43.4k
    if (!val)
596
27.9k
    {
597
27.9k
      fileNameEnd=true;
598
27.9k
      continue;
599
27.9k
    }
600
15.4k
    if (!fileNameEnd) fileName.push_back((char)val);
601
15.4k
  }
602
21.7k
  if (!fileName.empty()) f << "file=" << m_mainParser.getDebugStringForLMBCS(fileName) << ",";
603
21.7k
  for (auto axisName : axisNames)
604
65.1k
  {
605
65.1k
    val=int(libwps::read16(input));
606
65.1k
    if (val) f << "exp[manual," << axisName << "]=" << val << ",";;
607
65.1k
  }
608
21.7k
  ascFile.addPos(pos);
609
21.7k
  ascFile.addNote(f.str().c_str());
610
611
21.7k
  pos=input->tell();
612
21.7k
  f.str("");
613
21.7k
  f << "ChartDef-D:";
614
21.7k
  for (auto axisName : axisNames)
615
65.1k
  {
616
    // useme
617
65.1k
    f << axisName << "=[";
618
65.1k
    val=int(libwps::readU8(input)); // or 2 bytes
619
65.1k
    if (val!=0x71) f << "fmt=" << std::hex << val << std::dec << ",";
620
260k
    for (int j=0; j<3; ++j)
621
195k
    {
622
195k
      val=int(libwps::readU8(input));
623
195k
      if (val) f << "f" << j << "=" << val << ",";
624
195k
    }
625
65.1k
    f << "],";
626
65.1k
  }
627
21.7k
  ascFile.addDelimiter(input->tell(),'|');
628
86.8k
  for (int i=0; i<3; ++i)
629
65.1k
  {
630
65.1k
    bool isNan;
631
65.1k
    long double value;
632
65.1k
    if (!libwps::readDouble10(input, value, isNan))
633
4.70k
      f << "##min" << axisNames[i] << ",";
634
60.4k
    else
635
60.4k
    {
636
60.4k
      chart->getAxis(i).m_scaling[0]=float(value);
637
60.4k
      if (value<0 || value>0)
638
23.5k
        f << "min" << axisNames[i] << "=" << value << ",";
639
60.4k
    }
640
65.1k
  }
641
86.8k
  for (int i=0; i<3; ++i)
642
65.1k
  {
643
65.1k
    bool isNan;
644
65.1k
    long double value;
645
65.1k
    if (!libwps::readDouble10(input, value, isNan))
646
4.23k
      f << "##max" << axisNames[i] << ",";
647
60.8k
    else
648
60.8k
    {
649
60.8k
      chart->getAxis(i).m_scaling[1]=float(value);
650
60.8k
      if (value<0 || value>0)
651
22.1k
        f << "max" << axisNames[i] << "=" << value << ",";
652
60.8k
    }
653
65.1k
  }
654
21.7k
  if (input->tell()!=endPos)
655
7.13k
  {
656
7.13k
    ascFile.addDelimiter(input->tell(),'|');
657
7.13k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
658
7.13k
  }
659
21.7k
  ascFile.addPos(pos);
660
21.7k
  ascFile.addNote(f.str().c_str());
661
21.7k
  return true;
662
21.7k
}
663
664
bool LotusChart::readChartName(std::shared_ptr<WPSStream> stream)
665
137k
{
666
137k
  RVNGInputStreamPtr &input=stream->m_input;
667
137k
  libwps::DebugFile &ascFile=stream->m_ascii;
668
137k
  libwps::DebugStream f;
669
137k
  long pos = input->tell();
670
137k
  auto type = long(libwps::read16(input));
671
137k
  if (type != 0x12)
672
0
  {
673
0
    WPS_DEBUG_MSG(("LotusChart::readChartName: not a chart name\n"));
674
0
    return false;
675
0
  }
676
137k
  auto sz = long(libwps::readU16(input));
677
137k
  f << "Entries(ChartName):";
678
137k
  if (sz < 3)
679
4.14k
  {
680
4.14k
    WPS_DEBUG_MSG(("LotusChart::readChartName: chart name is too short\n"));
681
4.14k
    f << "###";
682
4.14k
    ascFile.addPos(pos);
683
4.14k
    ascFile.addNote(f.str().c_str());
684
4.14k
    return true;
685
4.14k
  }
686
687
133k
  auto cId=int(libwps::readU8(input));
688
133k
  f << "chart[id]=" << cId << ",";
689
133k
  auto chart=m_state->getChart(cId, *this, stream);
690
133k
  auto id=int(libwps::readU8(input));
691
133k
  f << "data[id]=" << id << ",";
692
133k
  std::string name("");
693
774k
  for (long i = 0; i < sz-2; i++)
694
759k
  {
695
759k
    unsigned char c = libwps::readU8(input);
696
759k
    if (c == '\0') break;
697
641k
    name+=char(c);
698
641k
  }
699
133k
  f << m_mainParser.getDebugStringForLMBCS(name) << ",";
700
133k
  if (!name.empty())
701
130k
  {
702
130k
    auto uniName=m_mainParser.getStringForLMBCS(name);
703
130k
    switch (id)
704
130k
    {
705
18.4k
    case 0:
706
28.7k
    case 1:
707
36.8k
    case 2:
708
44.9k
    case 3:
709
50.6k
    case 4:
710
61.5k
    case 5:
711
61.5k
    {
712
61.5k
      auto *serie=chart->getSerie(id, true);
713
61.5k
      serie->m_legendText=uniName;
714
61.5k
      chart->m_hasLegend=true;
715
61.5k
      break;
716
50.6k
    }
717
929
    case 6:
718
2.26k
    case 7:
719
3.01k
    case 8:
720
3.01k
      chart->getAxis(id-6).m_title=uniName;
721
3.01k
      break;
722
13.1k
    case 9:
723
25.3k
    case 10:
724
25.5k
    case 11:
725
25.5k
      chart->getAxis(id-9).m_subTitle=uniName;
726
25.5k
      break;
727
16.4k
    case 12:
728
22.6k
    case 13:
729
25.8k
    case 14: // note1
730
33.5k
    case 15: // note2
731
33.5k
    {
732
33.5k
      auto wh=id==12 ? WKSChart::TextZone::T_Title :
733
33.5k
      id==13 ? WKSChart::TextZone::T_SubTitle : WKSChart::TextZone::T_Footer;
734
33.5k
      WPSEntry entry;
735
33.5k
      entry.setBegin(pos+6);
736
33.5k
      entry.setEnd(input->tell());
737
33.5k
      auto *textZone=chart->getTextZone(wh, true);
738
33.5k
      textZone->m_contentType=WKSChart::TextZone::C_Text;
739
33.5k
      textZone->m_textEntryList.push_back(entry);
740
33.5k
      break;
741
25.8k
    }
742
6.43k
    default:
743
6.43k
      break;
744
130k
    }
745
130k
  }
746
133k
  if (input->tell()!=pos+4+sz && input->tell()+1!=pos+4+sz)
747
18.7k
  {
748
18.7k
    WPS_DEBUG_MSG(("LotusChart::readChartName: the zone seems too short\n"));
749
18.7k
    f << "##";
750
18.7k
    ascFile.addDelimiter(input->tell(), '|');
751
18.7k
  }
752
133k
  ascFile.addPos(pos);
753
133k
  ascFile.addNote(f.str().c_str());
754
133k
  return true;
755
133k
}
756
757
////////////////////////////////////////////////////////////
758
// wk3mac
759
////////////////////////////////////////////////////////////
760
bool LotusChart::readMacHeader(std::shared_ptr<WPSStream> stream, long endPos, int &chartId)
761
12.1k
{
762
12.1k
  if (!stream) return false;
763
12.1k
  RVNGInputStreamPtr &input = stream->m_input;
764
12.1k
  libwps::DebugFile &ascFile=stream->m_ascii;
765
12.1k
  libwps::DebugStream f;
766
12.1k
  long pos = input->tell();
767
12.1k
  long sz=endPos-pos;
768
12.1k
  f << "Entries(ChartMac):";
769
12.1k
  if (sz<12)
770
48
  {
771
48
    WPS_DEBUG_MSG(("LotusChart::readChartMac: Oops the zone seems too short\n"));
772
48
    f << "###";
773
48
    ascFile.addPos(pos-6);
774
48
    ascFile.addNote(f.str().c_str());
775
48
    m_state->m_chartId=chartId=-1;
776
48
    return true;
777
48
  }
778
779
12.0k
  m_state->m_chartId=chartId=int(libwps::read16(input));
780
12.0k
  f << "chart[id]=" << chartId << ",";
781
12.0k
  auto chart=m_state->getChart(chartId, *this,stream);
782
72.3k
  for (int i=0; i<5; ++i)   // f1=[4c][02]5[19], f2=50, f3=14
783
60.2k
  {
784
60.2k
    auto val=int(libwps::read16(input));
785
60.2k
    if (!val) continue;
786
39.7k
    if (i==1)
787
11.6k
    {
788
11.6k
      if (val&0x20)
789
1.19k
      {
790
1.19k
        f << "area[stacked],";
791
1.19k
        chart->m_dataStacked=true;
792
1.19k
      }
793
11.6k
      val&=0xffdf;
794
11.6k
    }
795
39.7k
    if (val)
796
39.7k
      f << "f" << i << "=" << std::hex << val << std::dec << ",";
797
39.7k
  }
798
12.0k
  ascFile.addPos(pos-6);
799
12.0k
  ascFile.addNote(f.str().c_str());
800
12.0k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
801
12.0k
  return true;
802
12.1k
}
803
804
bool LotusChart::readMacAxis(std::shared_ptr<WPSStream> stream, long endPos)
805
28.6k
{
806
28.6k
  if (!stream) return false;
807
28.6k
  RVNGInputStreamPtr &input = stream->m_input;
808
28.6k
  libwps::DebugFile &ascFile=stream->m_ascii;
809
28.6k
  libwps::DebugStream f;
810
28.6k
  long pos = input->tell();
811
28.6k
  long sz=endPos-pos;
812
813
28.6k
  f << "Entries(ChartAxis):id=" << m_state->m_chartId << ",";
814
28.6k
  if (sz!=56)
815
1.45k
  {
816
1.45k
    WPS_DEBUG_MSG(("LotusChart::readMacAxis: the size seems bad\n"));
817
1.45k
    f << "##sz";
818
1.45k
    ascFile.addPos(pos-6);
819
1.45k
    ascFile.addNote(f.str().c_str());
820
1.45k
    return true;
821
1.45k
  }
822
27.1k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
823
27.1k
  auto id=int(libwps::readU8(input));
824
27.1k
  if (id>=3)
825
627
  {
826
627
    WPS_DEBUG_MSG(("LotusChart::readMacAxis: the id seems bad\n"));
827
627
    f << "###";
828
627
  }
829
27.1k
  auto &axis=chart->getAxis(id>=3 ? 4 : id);
830
27.1k
  f << "id[axis]=" << id << ",";
831
27.1k
  auto format=int(libwps::readU8(input));
832
27.1k
  if ((format&0x20)==0)
833
1.54k
  {
834
1.54k
    f << "hidden[name],";
835
1.54k
    axis.m_showTitle=false;
836
1.54k
  }
837
27.1k
  ascFile.addDelimiter(input->tell(),'|');
838
27.1k
  ascFile.addPos(pos-6);
839
27.1k
  ascFile.addNote(f.str().c_str());
840
27.1k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
841
27.1k
  return true;
842
28.6k
}
843
844
bool LotusChart::readMacSerie(std::shared_ptr<WPSStream> stream, long endPos)
845
35.1k
{
846
35.1k
  if (!stream) return false;
847
35.1k
  RVNGInputStreamPtr &input = stream->m_input;
848
35.1k
  libwps::DebugFile &ascFile=stream->m_ascii;
849
35.1k
  libwps::DebugStream f;
850
35.1k
  long pos = input->tell();
851
35.1k
  long sz=endPos-pos;
852
853
35.1k
  f << "Entries(ChartSerie):id=" << m_state->m_chartId << ",";
854
35.1k
  if (sz!=28)
855
52
  {
856
52
    WPS_DEBUG_MSG(("LotusChart::readMacSerie: the size seems bad\n"));
857
52
    f << "##sz";
858
52
    ascFile.addPos(pos-6);
859
52
    ascFile.addNote(f.str().c_str());
860
52
    return true;
861
52
  }
862
35.1k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
863
35.1k
  auto id=int(libwps::readU8(input));
864
35.1k
  f << "id[serie]=" << id << ",";
865
35.1k
  chart->m_fileSerieStyles=true;
866
35.1k
  auto *serie=chart->getSerie(id, true);
867
35.1k
  serie->m_type=chart->m_type;
868
35.1k
  auto format=int(libwps::readU8(input));
869
35.1k
  if (id>=0 && id<6)
870
32.2k
  {
871
32.2k
    auto const &sFormat=chart->m_serieFormats[id];
872
32.2k
    if (sFormat.m_yAxis==2)
873
167
      serie->m_useSecondaryY=true;
874
32.2k
    if (chart->m_fileType<=3 || chart->m_fileType==7)
875
30.6k
    {
876
30.6k
      switch (sFormat.m_format)
877
30.6k
      {
878
27.4k
      case 0: // both
879
27.4k
        if (chart->m_fileType==7 && (format&3)==1) // special case, mixed means last serie as line
880
297
          serie->m_type = WKSChart::Serie::S_Line;
881
27.4k
        serie->m_pointType=WKSChart::Serie::P_Automatic;
882
27.4k
        break;
883
176
      case 1: // lines
884
176
        serie->m_type = WKSChart::Serie::S_Line;
885
176
        break;
886
476
      case 2: // symbol
887
476
        serie->m_pointType=WKSChart::Serie::P_Automatic;
888
476
        serie->m_style.m_lineWidth=0;
889
476
        break;
890
244
      case 3:
891
244
        serie->m_style.m_lineWidth=0;
892
244
        break;
893
2.02k
      case 4:
894
2.02k
        serie->m_type = WKSChart::Serie::S_Area;
895
2.02k
        break;
896
227
      default:
897
227
        break;
898
30.6k
      }
899
30.6k
    }
900
32.2k
  }
901
2.88k
  else
902
2.88k
  {
903
2.88k
    switch (format&3)
904
2.88k
    {
905
664
    case 1:
906
664
      f << "line,";
907
664
      if (chart->m_fileType==7)
908
154
        serie->m_type=serie->S_Line;
909
664
      serie->m_pointType=WKSChart::Serie::P_Automatic;
910
664
      break;
911
1.39k
    case 2: // bar
912
1.39k
      break;
913
823
    default:
914
823
      f << "##format[low]=" << (format&3) << ",";
915
2.88k
    }
916
2.88k
    if (format&4)
917
789
    {
918
789
      if (chart->m_fileType<=3 || chart->m_fileType==7) // force area
919
749
        serie->m_type=serie->S_Area;
920
789
      f << "area,";
921
789
    }
922
2.88k
  }
923
35.1k
  if (format&0xf8) f << "##format[high]=" << (format>>5) << ",";
924
35.1k
  auto val=int(libwps::readU16(input));
925
35.1k
  if ((val>>8)==0x10)
926
32.0k
    f << "L" << (val&0xff) << "[select],";
927
3.06k
  else
928
3.06k
    f << "##L[select]=" << std::hex << val << std::dec << ",";
929
35.1k
  val=int(libwps::readU16(input));
930
35.1k
  if ((val>>8)==0x20)
931
31.4k
  {
932
31.4k
    f << "C" << (val&0xff) << ",";
933
31.4k
    m_styleManager->updateSurfaceStyle(val&0xff, serie->m_style);
934
31.4k
  }
935
3.68k
  else
936
3.68k
    f << "##C=" << std::hex << val << std::dec << ",";
937
105k
  for (int i=0; i<2; ++i)   // i==0: ? , i==1: surface border
938
70.2k
  {
939
70.2k
    val=int(libwps::readU16(input));
940
70.2k
    if ((val>>8)==0x10)
941
60.0k
    {
942
60.0k
      f << "L" << (val&0xff) << (i==1 ? "[1]" : "") << ",";
943
60.0k
      if (i==0)
944
30.1k
        m_styleManager->updateLineStyle(val&0xff, serie->m_style);
945
60.0k
    }
946
10.1k
    else
947
10.1k
      f << "##L"  << (i==1 ? "[1]" : "") << "=" << std::hex << val << std::dec << ",";
948
70.2k
  }
949
35.1k
  val=int(libwps::readU16(input));
950
35.1k
  if ((val>>8)==0x20)   // surface external: used for pattern, ...
951
29.6k
  {
952
29.6k
    f << "C" << (val&0xff) << "[ext],";
953
29.6k
    m_styleManager->updateSurfaceStyle(val&0xff, serie->m_style);
954
29.6k
  }
955
5.50k
  else
956
5.50k
    f << "##Cext=" << std::hex << val << std::dec << ",";
957
35.1k
  val=int(libwps::readU16(input));
958
35.1k
  if (val!=id) f << "P" << val << ",";
959
35.1k
  if (serie->m_pointType != WKSChart::Serie::P_None)
960
28.8k
  {
961
28.8k
    switch (val)
962
28.8k
    {
963
6.61k
    case 0: // square
964
12.2k
    case 3: // hollow square
965
12.2k
      serie->m_pointType=WKSChart::Serie::P_Square;
966
12.2k
      break;
967
5.23k
    case 1: // diamond
968
5.27k
    case 4: // hollow diamond
969
5.27k
      serie->m_pointType=WKSChart::Serie::P_Diamond;
970
5.27k
      break;
971
6.27k
    case 2: // triangle
972
6.52k
    case 5: // hollow triangle
973
6.52k
      serie->m_pointType=WKSChart::Serie::P_Arrow_Up;
974
6.52k
      break;
975
250
    case 8: // triangle inverted
976
250
      serie->m_pointType=WKSChart::Serie::P_Arrow_Down;
977
250
      break;
978
25
    case 6: // circle
979
25
      serie->m_pointType=WKSChart::Serie::P_Circle;
980
25
      break;
981
36
    case 7: // star
982
36
      serie->m_pointType=WKSChart::Serie::P_Star;
983
36
      break;
984
318
    case 12: // x
985
318
      serie->m_pointType=WKSChart::Serie::P_X;
986
318
      break;
987
438
    case 14: // *
988
438
      serie->m_pointType=WKSChart::Serie::P_Asterisk;
989
438
      break;
990
255
    case 16: // +
991
255
      serie->m_pointType=WKSChart::Serie::P_Plus;
992
255
      break;
993
473
    case 18: // Y inverted
994
473
      serie->m_pointType=WKSChart::Serie::P_Bow_Tie;
995
473
      break;
996
451
    case 19: // -
997
451
      serie->m_pointType=WKSChart::Serie::P_Horizontal_Bar;
998
451
      break;
999
215
    case 20: // |
1000
215
      serie->m_pointType=WKSChart::Serie::P_Vertical_Bar;
1001
215
      break;
1002
2.34k
    default:
1003
2.34k
      break;
1004
28.8k
    }
1005
28.8k
  }
1006
1007
280k
  for (int i=0; i<7; ++i)   // 0
1008
245k
  {
1009
245k
    val=int(libwps::readU16(input));
1010
245k
    if (val)
1011
22.7k
      f << "f" << i+1 << "=" << val << ",";
1012
245k
  }
1013
35.1k
  ascFile.addPos(pos-6);
1014
35.1k
  ascFile.addNote(f.str().c_str());
1015
35.1k
  return true;
1016
35.1k
}
1017
1018
bool LotusChart::readMacPlacement(std::shared_ptr<WPSStream> stream, long endPos)
1019
25.5k
{
1020
25.5k
  if (!stream) return false;
1021
25.5k
  RVNGInputStreamPtr &input = stream->m_input;
1022
25.5k
  libwps::DebugFile &ascFile=stream->m_ascii;
1023
25.5k
  libwps::DebugStream f;
1024
25.5k
  long pos = input->tell();
1025
25.5k
  long sz=endPos-pos;
1026
1027
25.5k
  f << "Entries(ChartPlacement):id=" << m_state->m_chartId << ",";
1028
25.5k
  if (sz!=8)
1029
86
  {
1030
86
    WPS_DEBUG_MSG(("LotusChart::readMacPlacement: the size seems bad\n"));
1031
86
    f << "##sz";
1032
86
    ascFile.addPos(pos-6);
1033
86
    ascFile.addNote(f.str().c_str());
1034
86
    return true;
1035
86
  }
1036
25.4k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
1037
25.4k
  auto val=int(libwps::readU8(input));
1038
25.4k
  if ((val&0x10)==0)
1039
7.11k
    f << "hidden,";
1040
25.4k
  switch (val&3)
1041
25.4k
  {
1042
9.25k
  case 1:
1043
9.25k
    f << "title,";
1044
9.25k
    if ((val&0x10)==0)
1045
3.00k
    {
1046
3.00k
      WKSChart::TextZone::Type const allTypes[]= {WKSChart::TextZone::T_Title, WKSChart::TextZone::T_SubTitle};
1047
3.00k
      for (auto type : allTypes)
1048
6.00k
        chart->getTextZone(type,true)->m_show=false;
1049
3.00k
    }
1050
9.25k
    break;
1051
12.8k
  case 2:
1052
12.8k
    f << "note,";
1053
12.8k
    if ((val&0x10)==0) chart->getTextZone(WKSChart::TextZone::T_Footer,true)->m_show=false;
1054
12.8k
    break;
1055
3.39k
  default:
1056
3.39k
    f << "##wh=" << (val&3) << ",";
1057
3.39k
    break;
1058
25.4k
  }
1059
25.4k
  val &= 0xec;
1060
25.4k
  if (val) f << "fl0=" << std::hex << val << std::dec << ",";
1061
25.4k
  val=int(libwps::readU8(input));
1062
25.4k
  if (val&0x10)
1063
6.15k
    f << "manual,";
1064
19.3k
  else if (val!=1)
1065
13.0k
    f << "pos=" << val << ",";
1066
25.4k
  ascFile.addPos(pos-6);
1067
25.4k
  ascFile.addNote(f.str().c_str());
1068
25.4k
  return true;
1069
25.4k
}
1070
1071
bool LotusChart::readMacFloor(std::shared_ptr<WPSStream> stream, long endPos)
1072
5.34k
{
1073
5.34k
  if (!stream) return false;
1074
5.34k
  RVNGInputStreamPtr &input = stream->m_input;
1075
5.34k
  libwps::DebugFile &ascFile=stream->m_ascii;
1076
5.34k
  libwps::DebugStream f;
1077
5.34k
  long pos = input->tell();
1078
5.34k
  long sz=endPos-pos;
1079
1080
5.34k
  f << "Entries(ChartFloor):id=" << m_state->m_chartId << ",";
1081
5.34k
  if (sz!=17)
1082
50
  {
1083
50
    WPS_DEBUG_MSG(("LotusChart::readMacFloor: the size seems bad\n"));
1084
50
    f << "##sz";
1085
50
    ascFile.addPos(pos-6);
1086
50
    ascFile.addNote(f.str().c_str());
1087
50
    return true;
1088
50
  }
1089
5.29k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
1090
26.4k
  for (int i=0; i<4; ++i)
1091
21.1k
  {
1092
21.1k
    auto val=int(libwps::readU8(input));
1093
21.1k
    int const expected[]= {0xf,0x1e,0x12,0};
1094
21.1k
    if (val!=expected[i])
1095
452
      f << "f" << i << "=" << val << ",";
1096
21.1k
  }
1097
31.7k
  for (int i=0; i<5; ++i)   // i=4: floor style
1098
26.4k
  {
1099
26.4k
    auto val=int(libwps::readU16(input));
1100
26.4k
    if ((val>>8)==0x20)
1101
24.7k
    {
1102
24.7k
      f << "C" << (val&0xff) << "[" << i << "],";
1103
24.7k
      if (i==4)
1104
4.95k
        m_styleManager->updateSurfaceStyle(val&0xff,chart->m_floorStyle);
1105
24.7k
    }
1106
1.70k
    else
1107
1.70k
      f << "##C=" << std::hex << val << std::dec << "[" << i << "],";
1108
26.4k
  }
1109
5.29k
  auto val=int(libwps::readU16(input));
1110
5.29k
  if ((val>>8)==0x10)
1111
4.85k
    f << "L" << (val&0xff) << ",";
1112
444
  else
1113
444
    f << "##L=" << std::hex << val << std::dec << ",";
1114
5.29k
  val=int(libwps::readU8(input)); // 0
1115
5.29k
  if (val) f << "f4=" << val << ",";
1116
5.29k
  ascFile.addPos(pos-6);
1117
5.29k
  ascFile.addNote(f.str().c_str());
1118
5.29k
  return true;
1119
5.34k
}
1120
1121
bool LotusChart::readMacLegend(std::shared_ptr<WPSStream> stream, long endPos)
1122
13.4k
{
1123
13.4k
  if (!stream) return false;
1124
13.4k
  RVNGInputStreamPtr &input = stream->m_input;
1125
13.4k
  libwps::DebugFile &ascFile=stream->m_ascii;
1126
13.4k
  libwps::DebugStream f;
1127
13.4k
  long pos = input->tell();
1128
13.4k
  long sz=endPos-pos;
1129
1130
13.4k
  f << "Entries(ChartLegend):id=" << m_state->m_chartId << ",";
1131
13.4k
  if (sz!=7)
1132
72
  {
1133
72
    WPS_DEBUG_MSG(("LotusChart::readMacLegend: the size seems bad\n"));
1134
72
    f << "##sz";
1135
72
    ascFile.addPos(pos-6);
1136
72
    ascFile.addNote(f.str().c_str());
1137
72
    return true;
1138
72
  }
1139
13.3k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
1140
13.3k
  auto val=int(libwps::readU8(input));
1141
13.3k
  if (val&0x10)
1142
277
    f << "manual,";
1143
13.3k
  val&=0xef;
1144
13.3k
  if (val!=4) f << "f0=" << std::hex << val << std::dec << ",";
1145
13.3k
  val=int(libwps::readU8(input));
1146
13.3k
  if ((val&0x1)==0)
1147
432
  {
1148
432
    f << "hidden,";
1149
432
    chart->m_hasLegend=false;
1150
432
  }
1151
13.3k
  val&=0xfe;
1152
13.3k
  if (val!=2) f << "f1=" << std::hex << val << std::dec << ",";
1153
13.3k
  val=int(libwps::readU16(input));
1154
13.3k
  if ((val>>8)==0x40)
1155
12.9k
    f << "G" << (val&0xff) << ",";
1156
363
  else
1157
363
    f << "##G=" << std::hex << val << std::dec << ",";
1158
13.3k
  val=int(libwps::readU16(input));
1159
13.3k
  if (val!=2)
1160
382
    f << "f2=" << val << ",";
1161
13.3k
  val=int(libwps::readU8(input)); // vertical/horizontal?
1162
13.3k
  if (val) f << "f3=" << val << ",";
1163
13.3k
  ascFile.addPos(pos-6);
1164
13.3k
  ascFile.addNote(f.str().c_str());
1165
13.3k
  return true;
1166
13.4k
}
1167
1168
bool LotusChart::readMacPlotArea(std::shared_ptr<WPSStream> stream, long endPos)
1169
13.1k
{
1170
13.1k
  if (!stream) return false;
1171
13.1k
  RVNGInputStreamPtr &input = stream->m_input;
1172
13.1k
  libwps::DebugFile &ascFile=stream->m_ascii;
1173
13.1k
  libwps::DebugStream f;
1174
13.1k
  long pos = input->tell();
1175
13.1k
  long sz=endPos-pos;
1176
1177
13.1k
  f << "Entries(ChartPlotArea):id=" << m_state->m_chartId << ",";
1178
13.1k
  if (sz!=18)
1179
88
  {
1180
88
    WPS_DEBUG_MSG(("LotusChart::readMacPlotArea: the size seems bad\n"));
1181
88
    f << "##sz";
1182
88
    ascFile.addPos(pos-6);
1183
88
    ascFile.addNote(f.str().c_str());
1184
88
    return true;
1185
88
  }
1186
13.1k
  auto chart=m_state->getChart(m_state->m_chartId, *this,stream);
1187
13.1k
  auto val=int(libwps::readU16(input));
1188
13.1k
  if ((val>>8)==0x10)
1189
10.5k
  {
1190
10.5k
    f << "L" << (val&0xff) << ",";
1191
10.5k
    m_styleManager->updateLineStyle(val&0xff, chart->m_wallStyle);
1192
10.5k
  }
1193
2.57k
  else
1194
2.57k
    f << "##L[select]=" << std::hex << val << std::dec << ",";
1195
13.1k
  val=int(libwps::readU16(input));
1196
13.1k
  if ((val>>8)==0x20)
1197
11.1k
  {
1198
11.1k
    f << "C" << (val&0xff) << ",";
1199
11.1k
    m_styleManager->updateSurfaceStyle(val&0xff, chart->m_wallStyle);
1200
11.1k
  }
1201
1.92k
  else
1202
1.92k
    f << "##C=" << std::hex << val << std::dec << ",";
1203
13.1k
  val=int(libwps::readU8(input));
1204
13.1k
  if (val&0x10)
1205
2.63k
    f << "manual,";
1206
13.1k
  val&=0xef;
1207
13.1k
  if (val) f << "f0=" << std::hex << val << std::dec << ",";
1208
13.1k
  ascFile.addPos(pos-6);
1209
13.1k
  ascFile.addNote(f.str().c_str());
1210
13.1k
  return true;
1211
13.1k
}
1212
1213
bool LotusChart::readMacPosition(std::shared_ptr<WPSStream> stream, long endPos)
1214
9.40k
{
1215
9.40k
  if (!stream) return false;
1216
9.40k
  RVNGInputStreamPtr &input = stream->m_input;
1217
9.40k
  libwps::DebugFile &ascFile=stream->m_ascii;
1218
9.40k
  libwps::DebugStream f;
1219
9.40k
  long pos = input->tell();
1220
9.40k
  long sz=endPos-pos;
1221
1222
9.40k
  f << "Entries(ChartPosition):id=" << m_state->m_chartId << ",";
1223
9.40k
  if (sz!=9)
1224
147
  {
1225
147
    WPS_DEBUG_MSG(("LotusChart::readMacPosition: the size seems bad\n"));
1226
147
    f << "##sz";
1227
147
    ascFile.addPos(pos-6);
1228
147
    ascFile.addNote(f.str().c_str());
1229
147
    return true;
1230
147
  }
1231
9.25k
  int dim[4];
1232
37.0k
  for (auto &d : dim) d=int(libwps::read16(input));
1233
9.25k
  if (dim[2]||dim[3])
1234
6.51k
  {
1235
    // USEME
1236
6.51k
    float const scale=1.f/65536.f;
1237
6.51k
    f << "pos=" << Vec2f(scale*float(dim[0]),scale*float(dim[3]))
1238
6.51k
      << "<->" << Vec2f(scale*float(dim[2]),scale*float(dim[1])) << "%,";
1239
6.51k
  }
1240
9.25k
  auto val=int(libwps::readU8(input));
1241
9.25k
  if (val) f << "f0=" << val << ",";
1242
9.25k
  ascFile.addPos(pos-6);
1243
9.25k
  ascFile.addNote(f.str().c_str());
1244
9.25k
  return true;
1245
9.40k
}
1246
////////////////////////////////////////////////////////////
1247
// Windows wk3 and wk4 files
1248
////////////////////////////////////////////////////////////
1249
bool LotusChart::readSerie(std::shared_ptr<WPSStream> stream, long endPos)
1250
62.3k
{
1251
62.3k
  if (!stream) return false;
1252
62.3k
  RVNGInputStreamPtr &input = stream->m_input;
1253
62.3k
  libwps::DebugFile &ascFile=stream->m_ascii;
1254
62.3k
  libwps::DebugStream f;
1255
62.3k
  long pos = input->tell();
1256
62.3k
  long sz=endPos-pos;
1257
1258
62.3k
  f << "Entries(ChartSerie):";
1259
62.3k
  if (sz!=22)
1260
829
  {
1261
829
    WPS_DEBUG_MSG(("LotusChart::readSerie: the size seems bad\n"));
1262
829
    f << "##sz";
1263
829
    ascFile.addPos(pos-6);
1264
829
    ascFile.addNote(f.str().c_str());
1265
829
    return true;
1266
829
  }
1267
61.5k
  auto cId=int(libwps::readU8(input));
1268
61.5k
  f << "id[chart]=" << cId  << ",";
1269
61.5k
  auto chart=m_state->getChart(cId, *this,stream);
1270
61.5k
  chart->m_fileSerieStyles=true;
1271
246k
  for (int i=0; i<3; ++i)   // f0=0|b4
1272
184k
  {
1273
184k
    auto val=int(libwps::readU8(input));
1274
184k
    if (val)
1275
66.5k
      f << "f" << i << "=" << val << ",";
1276
184k
  }
1277
61.5k
  auto id=int(libwps::readU8(input));
1278
61.5k
  f << "id[serie]=" << id << ",";
1279
61.5k
  auto *serie=chart->getSerie(id, true);
1280
61.5k
  serie->m_type = chart->m_type;
1281
61.5k
  auto format=int(libwps::readU8(input));
1282
61.5k
  if (format==2)
1283
2.56k
  {
1284
2.56k
    serie->m_useSecondaryY=true;
1285
2.56k
    f << "secondary[y],";
1286
2.56k
  }
1287
58.9k
  else if (format!=1)
1288
53.8k
    f << "##yAxis=" << format << ",";
1289
61.5k
  format=int(libwps::readU8(input));
1290
61.5k
  if (format&8)
1291
19.2k
    f << "bar[force],";
1292
42.3k
  else if (chart->m_fileType==7)
1293
899
    serie->m_type = WKSChart::Serie::S_Line;
1294
61.5k
  format &= 0xf7;
1295
61.5k
  serie->m_style.m_lineWidth=1;
1296
61.5k
  if (format>=0 && format<5)
1297
34.9k
  {
1298
34.9k
    char const *wh[]= {"both", "lines", "symbols", "neither", "area"};
1299
34.9k
    f << "format=" << wh[format] << ",";
1300
34.9k
    if (chart->m_fileType<=3 || chart->m_fileType==7)
1301
31.4k
    {
1302
31.4k
      switch (format)
1303
31.4k
      {
1304
9.47k
      case 0: // both
1305
        //if (chart->m_fileType==7) // special case, mixed means last serie as line
1306
        //  serie->m_type = WKSChart::Serie::S_Line;
1307
9.47k
        serie->m_pointType=WKSChart::Serie::P_Automatic;
1308
9.47k
        break;
1309
6.18k
      case 1: // lines
1310
6.18k
        if (chart->m_fileType==7)
1311
97
          serie->m_type = WKSChart::Serie::S_Line;
1312
6.18k
        break;
1313
11.5k
      case 2: // symbol
1314
11.5k
        serie->m_pointType=WKSChart::Serie::P_Automatic;
1315
11.5k
        serie->m_style.m_lineWidth=0;
1316
11.5k
        break;
1317
184
      case 3:
1318
184
        serie->m_style.m_lineWidth=0;
1319
184
        break;
1320
3.99k
      case 4:
1321
3.99k
        if (chart->m_fileType==0)
1322
475
          chart->m_dataStacked=true;
1323
3.99k
        serie->m_type = WKSChart::Serie::S_Area;
1324
3.99k
        break;
1325
0
      default:
1326
0
        break;
1327
31.4k
      }
1328
31.4k
    }
1329
34.9k
  }
1330
26.6k
  else
1331
26.6k
    f << "###format=" << format << ",";
1332
61.5k
  int val;
1333
184k
  for (int i=0; i<2; ++i)
1334
123k
  {
1335
123k
    val=int(libwps::readU8(input));
1336
123k
    if (val)
1337
65.8k
      f << "f" << i+3 << "=" << std::hex << val << std::dec << ",";
1338
123k
  }
1339
61.5k
  auto col=int(libwps::readU8(input));  // 32|44|46|7c|81|a8|ff: checkme classic color 256 ?
1340
61.5k
  WPSColor color[3]= {WPSColor(255,0,0), WPSColor::white(), WPSColor::black()};
1341
61.5k
  if (m_styleManager->getColor256(col, color[0]))
1342
61.5k
    f << "color=" << color[0] << ",";
1343
0
  else
1344
0
    f << "##color=" << col << ",";
1345
430k
  for (int i=0; i<6; ++i)   // g0=1|3,g1=0-3,g3=0|-1,g4=0|1
1346
369k
  {
1347
369k
    val=int(libwps::read8(input));
1348
369k
    if (i==0)
1349
61.5k
    {
1350
61.5k
      if (val!=1)
1351
55.7k
        f << "line[style]=" << val << ",";
1352
61.5k
      switch (val)
1353
61.5k
      {
1354
8.87k
      case 0: // hidden
1355
8.87k
        serie->m_style.m_lineWidth=0;
1356
8.87k
        break;
1357
4.24k
      case 2: // long dash
1358
4.24k
        serie->m_style.m_lineDashWidth.push_back(7);
1359
4.24k
        serie->m_style.m_lineDashWidth.push_back(3);
1360
4.24k
        break;
1361
200
      case 3: // dotted line
1362
14.8k
      case 6: // chain dotted line
1363
14.8k
        serie->m_style.m_lineDashWidth.push_back(1);
1364
14.8k
        serie->m_style.m_lineDashWidth.push_back(3);
1365
14.8k
        break;
1366
5.24k
      case 4: // chain dash line ?
1367
5.55k
      case 7: // dash line
1368
5.55k
        serie->m_style.m_lineDashWidth.push_back(3);
1369
5.55k
        serie->m_style.m_lineDashWidth.push_back(3);
1370
5.55k
        break;
1371
2.19k
      case 5: // long dotted
1372
2.19k
        serie->m_style.m_lineDashWidth.push_back(2);
1373
2.19k
        serie->m_style.m_lineDashWidth.push_back(3);
1374
2.19k
        break;
1375
5.73k
      case 1: // solid
1376
25.8k
      default:
1377
25.8k
        break;
1378
61.5k
      }
1379
61.5k
      continue;
1380
61.5k
    }
1381
307k
    else if (i==2)
1382
61.5k
    {
1383
61.5k
      if (val!=1)
1384
58.6k
        f << "symbol=" << val << ",";
1385
61.5k
      if (serie->m_pointType != WKSChart::Serie::P_None)
1386
35.2k
      {
1387
35.2k
        switch (val)
1388
35.2k
        {
1389
2.07k
        case 1: // square
1390
3.01k
        case 4: // hollow square
1391
3.01k
          serie->m_pointType=WKSChart::Serie::P_Square;
1392
3.01k
          break;
1393
4.41k
        case 2: // diamond
1394
7.06k
        case 5: // hollow diamond
1395
7.06k
          serie->m_pointType=WKSChart::Serie::P_Diamond;
1396
7.06k
          break;
1397
800
        case 3: // triangle
1398
960
        case 6: // hollow triangle
1399
960
          serie->m_pointType=WKSChart::Serie::P_Circle;
1400
960
          break;
1401
2.44k
        case 13: // x in square
1402
3.57k
        case 16:
1403
3.57k
          serie->m_pointType=WKSChart::Serie::P_X;
1404
3.57k
          break;
1405
70
        case 14: // + in diamond
1406
115
        case 17:
1407
115
          serie->m_pointType=WKSChart::Serie::P_Plus;
1408
115
          break;
1409
155
        case 19: // Y inverted in triangle
1410
4.39k
        case 22: // Y inverted
1411
4.39k
          serie->m_pointType=WKSChart::Serie::P_Bow_Tie;
1412
4.39k
          break;
1413
16.1k
        default:
1414
16.1k
          break;
1415
35.2k
        }
1416
35.2k
      }
1417
61.5k
      continue;
1418
61.5k
    }
1419
246k
    else if (i==3)
1420
61.5k
    {
1421
61.5k
      if (m_styleManager->getColor256(uint8_t(val), color[2]))
1422
61.5k
      {
1423
61.5k
        if (!color[2].isBlack())
1424
52.6k
          f << "color[line]=" << color[2] << ",";
1425
61.5k
      }
1426
0
      else
1427
0
        f << "##color[line]=" << uint8_t(val) << ",";
1428
61.5k
      continue;
1429
61.5k
    }
1430
184k
    else if (i==4)
1431
61.5k
    {
1432
      // 0: none, 1: normal, 2: long dash, 3: dash
1433
61.5k
      if (val!=1) f << "line[style]=" << val << ",";
1434
61.5k
      continue;
1435
61.5k
    }
1436
123k
    else if (i==5)
1437
61.5k
    {
1438
61.5k
      if (!val) continue;
1439
34.1k
      if (val>0 && val<8 && serie->m_style.m_lineWidth>0)
1440
1.60k
        serie->m_style.m_lineWidth=float(val+1);
1441
34.1k
      f << "line[width]=" << val+1 << ",";
1442
34.1k
      continue;
1443
61.5k
    }
1444
61.5k
    if (!val) continue;
1445
42.6k
    f << "g" << i << "=" << val << ",";
1446
42.6k
  }
1447
61.5k
  col=int(libwps::readU8(input));
1448
61.5k
  if (m_styleManager->getColor256(col, color[1]))
1449
61.5k
  {
1450
61.5k
    if (!color[1].isWhite())
1451
36.3k
      f << "color[surf]=" << color[1] << ",";
1452
61.5k
  }
1453
0
  else
1454
0
    f << "##color[surf2]=" << col << ",";
1455
61.5k
  int patternId=1;
1456
369k
  for (int i=0; i<5; ++i)   // h0=f
1457
307k
  {
1458
307k
    val=int(libwps::read8(input));
1459
307k
    if (i==1)
1460
61.5k
    {
1461
61.5k
      patternId=val;
1462
61.5k
      if (val!=1) f << "pattern[id]=" << val << ",";
1463
61.5k
      continue;
1464
61.5k
    }
1465
246k
    else if (i==4)   // see chartDef
1466
61.5k
    {
1467
      // useme: ie. probably better than to use the pattern id
1468
1469
      // 1: solid, 2: fine cross, 3: fine double, 4: fine triple
1470
      // 5: coarse cross, 6: coarse double, 7: coarse single, 8: hollow
1471
61.5k
      if (val==-1) f << "hash[id]=range,";
1472
61.3k
      else if (val!=1) f << "hash[id]=" << val << ",";
1473
61.5k
      continue;
1474
61.5k
    }
1475
184k
    if (!val) continue;
1476
88.5k
    f << "h" << i << "=" << val << ",";
1477
88.5k
  }
1478
61.5k
  WPSGraphicStyle::Pattern pattern;
1479
61.5k
  bool has0D=serie->m_pointType!=WKSChart::Serie::P_None;
1480
61.5k
  bool has1D=serie->is1DStyle() || (chart->m_fileType==2 && serie->m_style.m_lineWidth>0);
1481
61.5k
  bool has2D=!serie->is1DStyle() || (has1D && chart->m_is3D);
1482
61.5k
  if (patternId>0 && m_styleManager->getPattern64(patternId,pattern))
1483
40.6k
  {
1484
40.6k
    if (version()>=3)
1485
38.7k
    {
1486
38.7k
      pattern.m_colors[0]=color[0];
1487
38.7k
      pattern.m_colors[1]=color[1];
1488
38.7k
    }
1489
1.92k
    else
1490
1.92k
    {
1491
1.92k
      pattern.m_colors[0]=WPSColor::white();
1492
1.92k
      pattern.m_colors[1]=color[0];
1493
1.92k
    }
1494
40.6k
    WPSColor finalColor;
1495
40.6k
    if (has0D || has2D)
1496
34.3k
    {
1497
34.3k
      if (pattern.getUniqueColor(finalColor))
1498
28.8k
        serie->m_style.setSurfaceColor(finalColor);
1499
5.45k
      else
1500
5.45k
        serie->m_style.setPattern(pattern);
1501
34.3k
    }
1502
40.6k
    if (has1D && pattern.getAverageColor(finalColor))
1503
16.5k
      serie->m_style.m_lineColor=finalColor;
1504
40.6k
  }
1505
20.8k
  else
1506
20.8k
  {
1507
20.8k
    if (has1D || patternId==0)
1508
13.3k
      serie->m_style.m_lineColor=color[0];
1509
20.8k
    if (has0D || (has2D && patternId!=0))
1510
15.1k
      serie->m_style.setSurfaceColor(color[0]);
1511
20.8k
  }
1512
61.5k
  ascFile.addPos(pos-6);
1513
61.5k
  ascFile.addNote(f.str().c_str());
1514
61.5k
  return true;
1515
61.5k
}
1516
1517
bool LotusChart::readSerieName(std::shared_ptr<WPSStream> stream, long endPos)
1518
3.85k
{
1519
3.85k
  if (!stream) return false;
1520
3.85k
  RVNGInputStreamPtr &input = stream->m_input;
1521
3.85k
  libwps::DebugFile &ascFile=stream->m_ascii;
1522
3.85k
  libwps::DebugStream f;
1523
3.85k
  long pos = input->tell();
1524
3.85k
  long sz=endPos-pos;
1525
1526
3.85k
  f << "Entries(ChartSerName):";
1527
3.85k
  if (sz<6)
1528
53
  {
1529
53
    WPS_DEBUG_MSG(("LotusChart::readSerieName: the size seems bad\n"));
1530
53
    f << "##sz";
1531
53
    ascFile.addPos(pos-6);
1532
53
    ascFile.addNote(f.str().c_str());
1533
53
    return true;
1534
53
  }
1535
3.80k
  auto cId=int(libwps::readU8(input));
1536
3.80k
  f << "id[chart]=" << cId  << ",";
1537
3.80k
  auto chart=m_state->getChart(cId, *this,stream);
1538
15.2k
  for (int i=0; i<3; ++i)   // 0
1539
11.4k
  {
1540
11.4k
    auto val=int(libwps::readU8(input));
1541
11.4k
    if (val)
1542
6.96k
      f << "f" << i << "=" << val << ",";
1543
11.4k
  }
1544
3.80k
  auto id=int(libwps::readU8(input));
1545
3.80k
  f << "id[serie]=" << id << ",";
1546
3.80k
  std::string name("");
1547
15.5k
  for (long i = 0; i < sz-5; i++)
1548
15.3k
  {
1549
15.3k
    unsigned char c = libwps::readU8(input);
1550
15.3k
    if (c == '\0') break;
1551
11.7k
    name+=char(c);
1552
11.7k
  }
1553
3.80k
  if (!name.empty())
1554
2.10k
  {
1555
2.10k
    f << m_mainParser.getDebugStringForLMBCS(name) << ",";
1556
2.10k
    auto *serie=chart->getSerie(id, true);
1557
2.10k
    serie->m_legendText=m_mainParser.getStringForLMBCS(name);
1558
2.10k
    chart->m_hasLegend=true;
1559
2.10k
  }
1560
3.80k
  ascFile.addPos(pos-6);
1561
3.80k
  ascFile.addNote(f.str().c_str());
1562
3.80k
  return true;
1563
3.85k
}
1564
1565
bool LotusChart::readSerieWidth(std::shared_ptr<WPSStream> stream, long endPos)
1566
5.61k
{
1567
5.61k
  if (!stream) return false;
1568
5.61k
  RVNGInputStreamPtr &input = stream->m_input;
1569
5.61k
  libwps::DebugFile &ascFile=stream->m_ascii;
1570
5.61k
  libwps::DebugStream f;
1571
5.61k
  long pos = input->tell();
1572
5.61k
  long sz=endPos-pos;
1573
1574
5.61k
  f << "Entries(ChartSerWidth):";
1575
5.61k
  if (sz!=8)
1576
600
  {
1577
600
    WPS_DEBUG_MSG(("LotusChart::readSerieWidth: the size seems bad\n"));
1578
600
    f << "##sz";
1579
600
    ascFile.addPos(pos-6);
1580
600
    ascFile.addNote(f.str().c_str());
1581
600
    return true;
1582
600
  }
1583
5.01k
  f << "id[chart]=" << int(libwps::readU8(input)) << ",";
1584
20.0k
  for (int i=0; i<3; ++i)   // 0
1585
15.0k
  {
1586
15.0k
    auto val=int(libwps::readU8(input));
1587
15.0k
    if (val)
1588
191
      f << "f" << i << "=" << val << ",";
1589
15.0k
  }
1590
5.01k
  f << "id[serie]=" << int(libwps::readU8(input)) << ",";
1591
  // checkme
1592
5.01k
  auto val=int(libwps::readU8(input)); // 0
1593
5.01k
  if (val) f << "f3=" << val << ",";
1594
5.01k
  f << "w[inv]=" << int(libwps::readU16(input)) << ",";
1595
5.01k
  ascFile.addPos(pos-6);
1596
5.01k
  ascFile.addNote(f.str().c_str());
1597
5.01k
  return true;
1598
5.61k
}
1599
1600
bool LotusChart::readPlotArea(std::shared_ptr<WPSStream> stream, long endPos)
1601
9.58k
{
1602
9.58k
  if (!stream) return false;
1603
9.58k
  RVNGInputStreamPtr &input = stream->m_input;
1604
9.58k
  libwps::DebugFile &ascFile=stream->m_ascii;
1605
9.58k
  libwps::DebugStream f;
1606
9.58k
  long pos = input->tell();
1607
9.58k
  long sz=endPos-pos;
1608
1609
9.58k
  f << "Entries(ChartPlotArea):";
1610
9.58k
  if (sz!=111)
1611
6.55k
  {
1612
6.55k
    WPS_DEBUG_MSG(("LotusChart::readPlotArea: the size seems bad\n"));
1613
6.55k
    f << "##sz";
1614
6.55k
    ascFile.addPos(pos-6);
1615
6.55k
    ascFile.addNote(f.str().c_str());
1616
6.55k
    return true;
1617
6.55k
  }
1618
3.03k
  auto cId=int(libwps::readU8(input));
1619
3.03k
  f << "id[chart]=" << cId  << ",";
1620
3.03k
  auto chart=m_state->getChart(cId, *this,stream);
1621
12.1k
  for (int i=0; i<3; ++i)   // f0=0|c,f,3a
1622
9.09k
  {
1623
9.09k
    auto val=int(libwps::readU8(input));
1624
9.09k
    if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1625
9.09k
  }
1626
3.03k
  bool isNan;
1627
3.03k
  long double value;
1628
21.2k
  for (int i=0; i<6; ++i)
1629
18.1k
  {
1630
18.1k
    if (!libwps::readDouble10(input, value, isNan))
1631
493
      f << "##value,";
1632
17.6k
    else if (value<0 || value>0)
1633
3.44k
      f << "v" << i << "=" << value << ",";
1634
18.1k
  }
1635
3.03k
  ascFile.addPos(pos-6);
1636
3.03k
  ascFile.addNote(f.str().c_str());
1637
1638
3.03k
  pos=input->tell();
1639
3.03k
  f.str("");
1640
3.03k
  f << "ChartPlotArea-A:";
1641
12.1k
  for (int i=0; i<3; ++i)   // f0=0|1, f1=0|1|5, f2=0|1
1642
9.09k
  {
1643
9.09k
    auto val=int(libwps::read16(input));
1644
9.09k
    if (val) f << "f" << i << "=" << val << ",";
1645
9.09k
  }
1646
3.03k
  char const *zonesName[]= {"title", "note", "serie,legend", "plot"};
1647
15.1k
  for (int i=0; i<4; ++i)
1648
12.1k
  {
1649
12.1k
    int dim[4]; // in percent * 65536
1650
48.4k
    for (auto &d : dim) d=int(libwps::readU16(input));
1651
12.1k
    if (dim[0]==0 && dim[1]==0 && dim[2]==0 && dim[3]==0)
1652
3.75k
      continue;
1653
8.36k
    float const scale=1.f/65536.f;
1654
8.36k
    WPSBox2f box(Vec2f(scale*float(dim[0]),1.f-scale*float(dim[1])), Vec2f(scale*float(dim[2]),1.f-scale*float(dim[3])));
1655
8.36k
    f << "pos[" << zonesName[i] << "]=" << box << "%,";
1656
8.36k
    if (i==2)
1657
2.21k
    {
1658
2.21k
      auto &legend=chart->getLegend();
1659
2.21k
      legend.m_autoPosition=false;
1660
2.21k
      chart->m_legendPosition=box;
1661
2.21k
    }
1662
6.14k
    else if (i==3)
1663
2.36k
      chart->m_plotAreaPosition=box;
1664
8.36k
  }
1665
15.1k
  for (int i=0; i<4; ++i) // UseME
1666
12.1k
  {
1667
12.1k
    auto val=int(libwps::readU8(input));
1668
12.1k
    if (!val) continue;
1669
8.85k
    f << "pos[" << zonesName[i] << "]=[";
1670
8.85k
    if (val&0x10)
1671
594
      f << "manual,";
1672
8.85k
    if (i<2)
1673
4.29k
    {
1674
4.29k
      if ((val&0x10)==0)
1675
4.03k
      {
1676
4.03k
        if (val&1) f << "left,";
1677
4.03k
        if (val&2) f << "center,";
1678
4.03k
        if (val&4) f << "right,";
1679
4.03k
      }
1680
4.29k
      val &= 0xf8;
1681
4.29k
    }
1682
4.56k
    else if (i==2)
1683
2.28k
    {
1684
2.28k
      if ((val&0x10)==0)
1685
2.12k
      {
1686
2.12k
        if (val&4) f << "right,";
1687
2.12k
        if (val&8) f << "below,";
1688
2.12k
      }
1689
2.28k
      val &= 0xf3;
1690
2.28k
    }
1691
8.85k
    val &= 0xef;
1692
8.85k
    if (val)
1693
6.07k
      f << "fl=" << std::hex << val << std::dec << ",";
1694
8.85k
    f << "],";
1695
8.85k
  }
1696
3.03k
  char const *axisNames[]= {"X","Y","YSecond"};
1697
3.03k
  for (auto axisName : axisNames) // useme
1698
9.09k
  {
1699
9.09k
    auto val=int(libwps::readU8(input));
1700
9.09k
    if (val==0x10) continue;
1701
4.41k
    f << axisName << "[";
1702
4.41k
    if ((val&0x10)==0) f << "not10,";
1703
4.41k
    if (val&0x40) f << "major,";
1704
4.41k
    if (val&0x80) f << "minor,";
1705
4.41k
    val &= 0x2f;
1706
4.41k
    if (val)
1707
3.72k
      f << "fl=" << std::hex << val << std::dec;
1708
4.41k
    f << "],";
1709
4.41k
  }
1710
3.03k
  auto val=int(libwps::readU8(input));
1711
3.03k
  if (val) f << "fl=" << val << ",";
1712
3.03k
  val=int(libwps::readU8(input));
1713
3.03k
  if (val)
1714
983
  {
1715
983
    f << "type=" << val << ",";
1716
983
    if (val==8)
1717
79
      chart->m_type=WKSChart::Serie::S_Radar;
1718
983
  }
1719
3.03k
  ascFile.addPos(pos);
1720
3.03k
  ascFile.addNote(f.str().c_str());
1721
1722
3.03k
  return true;
1723
9.58k
}
1724
1725
bool LotusChart::readFontsStyle(std::shared_ptr<WPSStream> stream, long endPos)
1726
3.34k
{
1727
3.34k
  if (!stream) return false;
1728
3.34k
  RVNGInputStreamPtr &input = stream->m_input;
1729
3.34k
  libwps::DebugFile &ascFile=stream->m_ascii;
1730
3.34k
  libwps::DebugStream f;
1731
3.34k
  long pos = input->tell();
1732
3.34k
  long sz=endPos-pos;
1733
1734
3.34k
  f << "Entries(ChartFontsStyle):";
1735
3.34k
  if (sz!=38)
1736
357
  {
1737
357
    WPS_DEBUG_MSG(("LotusChart::readFontsStyle: the size seems bad\n"));
1738
357
    f << "##sz";
1739
357
    ascFile.addPos(pos-6);
1740
357
    ascFile.addNote(f.str().c_str());
1741
357
    return true;
1742
357
  }
1743
2.99k
  f << "id[chart]=" << int(libwps::readU8(input)) << ",";
1744
11.9k
  for (int i=0; i<3; ++i)   // 0
1745
8.97k
  {
1746
8.97k
    auto val=int(libwps::readU8(input));
1747
8.97k
    if (val)
1748
72
      f << "f" << i << "=" << val << ",";
1749
8.97k
  }
1750
2.99k
  int prev=-1;
1751
2.99k
  f << "val=[";
1752
53.8k
  for (int i=0; i<17; ++i)   // 20-3e, 57, ...
1753
50.8k
  {
1754
50.8k
    auto val=int(libwps::readU16(input));
1755
50.8k
    if (val==prev)
1756
28.1k
      f << "=,";
1757
22.6k
    else
1758
22.6k
      f << "F" << val << ",";
1759
50.8k
    prev=val;
1760
50.8k
  }
1761
2.99k
  f << "],";
1762
2.99k
  ascFile.addPos(pos-6);
1763
2.99k
  ascFile.addNote(f.str().c_str());
1764
2.99k
  return true;
1765
3.34k
}
1766
1767
bool LotusChart::readFramesStyle(std::shared_ptr<WPSStream> stream, long endPos)
1768
4.57k
{
1769
4.57k
  if (!stream) return false;
1770
4.57k
  RVNGInputStreamPtr &input = stream->m_input;
1771
4.57k
  libwps::DebugFile &ascFile=stream->m_ascii;
1772
4.57k
  libwps::DebugStream f;
1773
4.57k
  long pos = input->tell();
1774
4.57k
  long sz=endPos-pos;
1775
1776
4.57k
  f << "Entries(ChartFramesStyle):";
1777
4.57k
  if (sz!=102)
1778
531
  {
1779
531
    WPS_DEBUG_MSG(("LotusChart::readFramesStyle: the size seems bad\n"));
1780
531
    f << "##sz";
1781
531
    ascFile.addPos(pos-6);
1782
531
    ascFile.addNote(f.str().c_str());
1783
531
    return true;
1784
531
  }
1785
4.03k
  auto cId=int(libwps::readU8(input));
1786
4.03k
  f << "id[chart]=" << cId << ",";
1787
4.03k
  auto chart=m_state->getChart(cId, *this,stream);
1788
16.1k
  for (int i=0; i<3; ++i)   // 0
1789
12.1k
  {
1790
12.1k
    auto val=int(libwps::readU8(input));
1791
12.1k
    if (val)
1792
1.48k
      f << "f" << i << "=" << val << ",";
1793
12.1k
  }
1794
4.03k
  ascFile.addPos(pos-6);
1795
4.03k
  ascFile.addNote(f.str().c_str());
1796
1797
20.1k
  for (int i=0; i<4; ++i)
1798
16.1k
  {
1799
16.1k
    pos=input->tell();
1800
16.1k
    char const *zonesName[]= {"title", "serie,legend", "note", "plot"};
1801
16.1k
    f.str("");
1802
16.1k
    f << "ChartFramesStyle-" << zonesName[i] << ":";
1803
16.1k
    WPSColor color[4]= {WPSColor::black(), WPSColor::white(), WPSColor::black(), WPSColor::black()};
1804
16.1k
    auto val=int(libwps::readU8(input));
1805
16.1k
    WPSGraphicStyle style;
1806
16.1k
    if (!m_styleManager->getColor256(val, color[2]))
1807
0
      f << "col[lineId]=###" << val << ",";
1808
16.1k
    else if (!color[2].isBlack())
1809
7.30k
    {
1810
7.30k
      f << "col[line]=" << color[2] << ",";
1811
7.30k
      style.m_lineColor=color[2];
1812
7.30k
    }
1813
16.1k
    val=int(libwps::readU8(input));
1814
16.1k
    if (val!=1)
1815
10.5k
    {
1816
10.5k
      f << "line[style]=" << val << ",";
1817
10.5k
      if (val==0) style.m_lineWidth=0;
1818
10.5k
    }
1819
16.1k
    val=int(libwps::readU8(input));
1820
16.1k
    if (val)
1821
7.57k
    {
1822
7.57k
      f << "line[width]=" << val+1 << ",";
1823
7.57k
      if (style.m_lineWidth>0)
1824
5.65k
        style.m_lineWidth=float(val+1);
1825
7.57k
    }
1826
48.4k
    for (int j=0; j<2; ++j)
1827
32.3k
    {
1828
32.3k
      val=int(libwps::readU8(input));
1829
32.3k
      if (!m_styleManager->getColor256(val, color[j]))
1830
0
        f << "col[surf" << j << "]=###" << val << ",";
1831
32.3k
    }
1832
16.1k
    auto patId=int(libwps::readU8(input));
1833
16.1k
    WPSGraphicStyle::Pattern pattern;
1834
16.1k
    if (patId>0 && m_styleManager->getPattern64(patId,pattern))
1835
6.63k
    {
1836
6.63k
      pattern.m_colors[0]=color[1];
1837
6.63k
      pattern.m_colors[1]=color[0];
1838
1839
6.63k
      WPSColor finalColor;
1840
6.63k
      if (!pattern.getUniqueColor(finalColor))
1841
2.81k
      {
1842
2.81k
        style.setPattern(pattern);
1843
2.81k
        f << pattern << ",";
1844
2.81k
      }
1845
3.81k
      else
1846
3.81k
      {
1847
3.81k
        style.setSurfaceColor(finalColor);
1848
3.81k
        if (!finalColor.isWhite())
1849
425
          f << "surf=" << finalColor << ",";
1850
3.81k
      }
1851
6.63k
    }
1852
9.52k
    else
1853
9.52k
      f << "pattern[id]=##" << patId << ",";
1854
16.1k
    val=int(libwps::readU8(input));
1855
16.1k
    if (!m_styleManager->getColor256(val, color[3]))
1856
0
      f << "frame[colId]=###" << val << ",";
1857
16.1k
    else if (!color[3].isBlack())
1858
9.69k
      f << "col[frame]=" << color[3] << ",";
1859
16.1k
    val=int(libwps::readU8(input));
1860
16.1k
    if ((i!=3 && val!=2) || (i==3 && val)) f << "type[frame]" << val << ",";
1861
16.1k
    if (i==0)
1862
4.03k
    {
1863
4.03k
      auto title=chart->getTextZone(WKSChart::TextZone::T_Title, true);
1864
4.03k
      title->m_style=style;
1865
4.03k
    }
1866
12.1k
    else if (i==1)
1867
4.03k
      chart->getLegend().m_style = style;
1868
8.07k
    else if (i==3)
1869
4.03k
      chart->m_wallStyle = chart->m_floorStyle = style;
1870
16.1k
    ascFile.addPos(pos);
1871
16.1k
    ascFile.addNote(f.str().c_str());
1872
16.1k
  }
1873
4.03k
  pos=input->tell();
1874
4.03k
  f.str("");
1875
4.03k
  f << "ChartFramesStyle-A:";
1876
4.03k
  int val;
1877
4.03k
  f << "plot[line1]=[";
1878
4.03k
  val=int(libwps::readU8(input));
1879
4.03k
  WPSColor lineColor;
1880
4.03k
  if (!m_styleManager->getColor256(val, lineColor))
1881
0
    f << "colId=###" << val << ",";
1882
4.03k
  else if (!lineColor.isBlack())
1883
3.19k
    f << lineColor << ",";
1884
4.03k
  val=int(libwps::readU8(input));
1885
4.03k
  if (val!=1)
1886
3.32k
  {
1887
3.32k
    f << "style=" << val << ",";
1888
3.32k
    if (val==0) chart->m_floorStyle.m_lineWidth=0;
1889
3.32k
  }
1890
4.03k
  val=int(libwps::readU8(input));
1891
4.03k
  if (val)
1892
2.42k
    f << "width=" << val+1 << ",";
1893
4.03k
  f << "],";
1894
4.03k
  ascFile.addDelimiter(input->tell(),'|');
1895
4.03k
  input->seek(pos+15, librevenge::RVNG_SEEK_SET);
1896
4.03k
  f << "plot[line2]=[";
1897
4.03k
  val=int(libwps::readU8(input));
1898
4.03k
  if (!m_styleManager->getColor256(val, lineColor))
1899
0
    f << "colId=###" << val << ",";
1900
4.03k
  else if (!lineColor.isBlack())
1901
2.96k
    f << lineColor << ",";
1902
4.03k
  val=int(libwps::readU8(input));
1903
4.03k
  if (val!=1)
1904
3.14k
  {
1905
3.14k
    f << "style=" << val << ",";
1906
3.14k
    if (val==0) chart->m_floorStyle.m_lineWidth=0;
1907
3.14k
  }
1908
4.03k
  val=int(libwps::readU8(input));
1909
4.03k
  if (val)
1910
2.56k
    f << "width=" << val+1 << ",";
1911
4.03k
  f << "],";
1912
4.03k
  ascFile.addPos(pos);
1913
4.03k
  ascFile.addNote(f.str().c_str());
1914
1915
4.03k
  pos=input->tell();
1916
4.03k
  f.str("");
1917
4.03k
  f << "ChartFramesStyle-B:";
1918
4.03k
  input->seek(pos+12, librevenge::RVNG_SEEK_SET);
1919
4.03k
  ascFile.addDelimiter(input->tell(),'|');
1920
4.03k
  f << "plot[line3]=[";
1921
4.03k
  val=int(libwps::readU8(input));
1922
4.03k
  if (!m_styleManager->getColor256(val, lineColor))
1923
0
    f << "colId=###" << val << ",";
1924
4.03k
  else if (!lineColor.isBlack())
1925
3.05k
    f << lineColor << ",";
1926
4.03k
  val=int(libwps::readU8(input));
1927
4.03k
  if (val!=1)
1928
3.23k
  {
1929
3.23k
    f << "style=" << val << ",";
1930
3.23k
    if (val==0) chart->m_wallStyle.m_lineWidth=0;
1931
3.23k
  }
1932
4.03k
  val=int(libwps::readU8(input));
1933
4.03k
  if (val)
1934
1.74k
    f << "width=" << val+1 << ",";
1935
4.03k
  f << "],";
1936
4.03k
  ascFile.addDelimiter(input->tell(),'|');
1937
4.03k
  input->seek(pos+24, librevenge::RVNG_SEEK_SET);
1938
4.03k
  ascFile.addPos(pos);
1939
4.03k
  ascFile.addNote(f.str().c_str());
1940
1941
4.03k
  pos=input->tell();
1942
4.03k
  f.str("");
1943
4.03k
  f << "ChartFramesStyle-C:";
1944
4.03k
  input->seek(pos+24, librevenge::RVNG_SEEK_SET);
1945
4.03k
  ascFile.addPos(pos);
1946
4.03k
  ascFile.addNote(f.str().c_str());
1947
1948
4.03k
  return true;
1949
4.57k
}
1950
1951
////////////////////////////////////////////////////////////
1952
// send data
1953
////////////////////////////////////////////////////////////
1954
bool LotusChart::convert(LotusParser::Link const &link, WKSChart::Position(&positions)[2]) const
1955
20.2k
{
1956
60.6k
  for (int i=0; i<2; ++i)
1957
40.4k
  {
1958
40.4k
    auto const &c = link.m_cells[i];
1959
40.4k
    positions[i].m_pos=Vec2i(c[0], c[1]);
1960
40.4k
    positions[i].m_sheetName = m_mainParser.getSheetName(c[2]);
1961
40.4k
  }
1962
20.2k
  return positions[0].valid(positions[1]);
1963
20.2k
}
1964
1965
void LotusChart::updateChart(LotusChartInternal::Chart &chart, int id)
1966
15.8k
{
1967
15.8k
  int const vers=version();
1968
  // .wk4 pie chart does no have legend
1969
15.8k
  if (chart.m_hasLegend && (vers<3 || chart.m_fileType!=4))
1970
7.16k
  {
1971
7.16k
    chart.getLegend().m_show=true;
1972
7.16k
    chart.getLegend().m_autoPosition=true;
1973
7.16k
    chart.getLegend().m_relativePosition=WPSBorder::RightBit;
1974
7.16k
  }
1975
8.65k
  else
1976
8.65k
    chart.getLegend().m_show=false;
1977
15.8k
  std::string chartId(1,char(0x19));
1978
15.8k
  chartId+=std::string(1,char(id))+"G";
1979
1980
  // G[39-3e]: data series 0, 1, ...
1981
  // G[40-45]: legend serie 0->5
1982
15.8k
  if (!chart.m_fileSerieStyles)   // wks3 dos pc
1983
12.2k
  {
1984
    // we must create the serie, if there have data, ...
1985
12.2k
    bool findSerie=false;
1986
86.0k
    for (int i=5; i>=0; --i)
1987
73.7k
    {
1988
73.7k
      WKSChart::Position ranges[2];
1989
73.7k
      auto lnk=m_mainParser.getLink(chartId+char(0x39+i));
1990
73.7k
      if (lnk==nullptr || !convert(*lnk,ranges))
1991
60.9k
        continue;
1992
12.7k
      auto *serie=chart.getSerie(i, true);
1993
38.3k
      for (int r=0; r<2; ++r) serie->m_ranges[r]=ranges[r];
1994
1995
      // check label
1996
12.7k
      lnk=m_mainParser.getLink(chartId+char(0x40+i));
1997
12.7k
      if (lnk && convert(*lnk,ranges))
1998
130
      {
1999
390
        for (int r=0; r<2; ++r) serie->m_labelRanges[r]=ranges[r];
2000
130
      }
2001
      // now update the style
2002
12.7k
      auto const &format=chart.m_serieFormats[i];
2003
12.7k
      if (format.m_yAxis==2)
2004
134
        serie->m_useSecondaryY=true;
2005
12.7k
      serie->m_type=chart.m_type;
2006
12.7k
      serie->m_style.m_lineWidth=1;
2007
12.7k
      if (chart.m_fileType==0 || chart.m_fileType==2 || chart.m_fileType==3 || chart.m_fileType==7)
2008
4.90k
      {
2009
4.90k
        switch (format.m_format)
2010
4.90k
        {
2011
3.38k
        case 0: // both
2012
3.38k
          if (chart.m_fileType==7 && !findSerie) // special case, mixed means last serie as line
2013
172
            serie->m_type = WKSChart::Serie::S_Line;
2014
3.38k
          serie->m_pointType=WKSChart::Serie::P_Automatic;
2015
3.38k
          break;
2016
168
        case 1: // lines
2017
168
          serie->m_type = WKSChart::Serie::S_Line;
2018
168
          break;
2019
215
        case 2: // symbol
2020
215
          serie->m_pointType=WKSChart::Serie::P_Automatic;
2021
215
          serie->m_style.m_lineWidth=0;
2022
215
          break;
2023
80
        case 3:
2024
80
          serie->m_style.m_lineWidth=0;
2025
80
          break;
2026
711
        case 4:
2027
711
          serie->m_type = WKSChart::Serie::S_Area;
2028
711
          break;
2029
346
        default:
2030
346
          break;
2031
4.90k
        }
2032
4.90k
      }
2033
12.7k
      findSerie=true;
2034
12.7k
      uint32_t const defColor[6] = {0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xff00ff};
2035
12.7k
      WPSColor color=WPSColor(defColor[i]);
2036
12.7k
      if (format.m_color)
2037
1.24k
        m_styleManager->getColor256(format.m_color, color);
2038
      // useme m_hash: H8->P2, H3->P3, H4->P4, H5->P12, H7->P6
2039
12.7k
      bool has0D=serie->m_pointType!=WKSChart::Serie::P_None;
2040
12.7k
      bool has1D=serie->is1DStyle();
2041
12.7k
      bool has2D=!serie->is1DStyle();
2042
12.7k
      if (has1D || format.m_hash==0)
2043
11.9k
        serie->m_style.m_lineColor=color;
2044
12.7k
      if (has0D || has2D)
2045
12.1k
        serie->m_style.setSurfaceColor(color);
2046
12.7k
    }
2047
12.2k
  }
2048
3.53k
  else
2049
3.53k
  {
2050
    // G[47][22,27,2c,31,36,3b,40,45,4a,4f,54,59,5e]: data serie 6-18 (+1 label)
2051
    // G[48][23,28,2d,32]: serie 19-22 (+1 label)
2052
16.3k
    for (auto it=chart.getIdSerieMap().begin(); it!=chart.getIdSerieMap().end(); ++it)
2053
12.8k
    {
2054
12.8k
      int sId=it->first;
2055
12.8k
      if (sId<0 || sId>22)
2056
1.14k
      {
2057
1.14k
        WPS_DEBUG_MSG(("LotusChart::updateChart: find unexpected id=%d\n", sId));
2058
1.14k
        continue;
2059
1.14k
      }
2060
11.6k
      std::string dataName=chartId, labelName=chartId;
2061
11.6k
      if (sId<6)
2062
11.3k
      {
2063
11.3k
        dataName+=char(0x39+sId);
2064
11.3k
        labelName+=char(0x40+sId);
2065
11.3k
      }
2066
376
      else if (sId<=18)
2067
312
      {
2068
312
        dataName+=char(0x47);
2069
312
        dataName+=char(0x22+5*(sId-6));
2070
312
        labelName+=char(0x47);
2071
312
        labelName+=char(0x23+5*(sId-6));
2072
312
      }
2073
64
      else
2074
64
      {
2075
64
        dataName+=char(0x48);
2076
64
        dataName+=char(0x23+5*(sId-19));
2077
64
        labelName+=char(0x48);
2078
64
        labelName+=char(0x24+5*(sId-19));
2079
64
      }
2080
11.6k
      WKSChart::Position ranges[2];
2081
11.6k
      auto lnk=m_mainParser.getLink(dataName);
2082
11.6k
      if (lnk==nullptr || !convert(*lnk,ranges))
2083
6.68k
      {
2084
6.68k
        if (vers>1)
2085
4.26k
        {
2086
4.26k
          WPS_DEBUG_MSG(("LotusChart::updateChart: can find data for serie %d in chart %d\n", sId, id));
2087
4.26k
        }
2088
6.68k
        continue;
2089
6.68k
      }
2090
5.01k
      auto *serie = chart.getSerie(sId, true);
2091
15.0k
      for (int i=0; i<2; ++i) serie->m_ranges[i]=ranges[i];
2092
5.01k
      lnk=m_mainParser.getLink(labelName);
2093
5.01k
      if (lnk==nullptr || !convert(*lnk,ranges))
2094
4.98k
        continue;
2095
72
      for (int i=0; i<2; ++i) serie->m_labelRanges[i]=ranges[i];
2096
24
    }
2097
3.53k
  }
2098
126k
  for (int i=0; i<7; ++i)
2099
110k
  {
2100
    // G[4f-51]: label axis x,y,ysecond
2101
    // G[52-53]: title, subtile
2102
    // G[54-55]: note1, note2
2103
110k
    WKSChart::Position ranges[2];
2104
110k
    auto lnk=m_mainParser.getLink(chartId+char(0x4f+i));
2105
110k
    if (lnk==nullptr || !convert(*lnk,ranges))
2106
110k
      continue;
2107
472
    if (i<3)
2108
171
      chart.getAxis(i).m_titleRange=ranges[0];
2109
301
    else
2110
301
    {
2111
301
      auto *zone=chart.getTextZone(i==3 ? WKSChart::TextZone::T_Title :
2112
301
                     i==4 ? WKSChart::TextZone::T_SubTitle : WKSChart::TextZone::T_Footer, true);
2113
301
      zone->m_contentType=zone->C_Cell;
2114
301
      zone->m_cell=ranges[0];
2115
301
    }
2116
472
  }
2117
  // G[3f]: axis 0
2118
15.8k
  WKSChart::Position ranges[2];
2119
15.8k
  auto lnk=m_mainParser.getLink(chartId+char(0x3f));
2120
15.8k
  if (lnk && convert(*lnk,ranges))
2121
661
  {
2122
661
    auto &axis = chart.getAxis(0);
2123
1.98k
    for (int r=0; r<2; ++r)  axis.m_labelRanges[r]=ranges[r];
2124
661
  }
2125
15.1k
  else if (chart.m_fileType==2)
2126
492
  {
2127
    // if chart is a scatter, the first serie can store the xaxis data...
2128
492
    auto *serie = chart.getSerie(0, false);
2129
492
    if (serie)
2130
360
    {
2131
360
      auto &axis=chart.getAxis(0);
2132
1.08k
      for (int i=0; i<2; ++i)
2133
720
      {
2134
720
        axis.m_labelRanges[i]=serie->m_ranges[i];
2135
720
        serie->m_ranges[i]=WKSChart::Position();
2136
720
      }
2137
360
    }
2138
492
  }
2139
  // G[23-28] color series 0->5
2140
  // G[2a-2f] hatch series 0->5
2141
  // G[4c-4e]: unit axis x,y,ysecond
2142
15.8k
}
2143
2144
bool LotusChart::sendText(std::shared_ptr<WPSStream> stream, WPSEntry const &entry)
2145
4.75k
{
2146
4.75k
  if (m_listener.get() == nullptr)
2147
0
  {
2148
0
    WPS_DEBUG_MSG(("LotusChart::sendText: I can not find the listener\n"));
2149
0
    return false;
2150
0
  }
2151
4.75k
  if (stream.get() == nullptr || !entry.valid())
2152
0
    return true;
2153
4.75k
  m_mainParser.sendText(stream->m_input, entry);
2154
4.75k
  return true;
2155
4.75k
}
2156
2157
bool LotusChart::sendCharts()
2158
537
{
2159
537
  if (m_listener.get() == nullptr)
2160
0
  {
2161
0
    WPS_DEBUG_MSG(("LotusChart::sendCharts: I can not find the listener\n"));
2162
0
    return false;
2163
0
  }
2164
537
  Vec2i actPos(0,0);
2165
537
  int actSquare=0;
2166
537
  WPSGraphicStyle emptyStyle(WPSGraphicStyle::emptyStyle());
2167
537
  for (auto &it : m_state->m_idChartMap)
2168
1.43k
  {
2169
1.43k
    if (!it.second || it.second->getIdSerieMap().empty()) continue;
2170
1.43k
    WPSPosition pos(Vec2f(float(512*actPos[0]),float(350*actPos[1])), Vec2f(512,350), librevenge::RVNG_POINT);
2171
1.43k
    pos.m_anchorTo = WPSPosition::Page;
2172
1.43k
    it.second->m_dimension=Vec2f(512,350); // set basic dimension
2173
1.43k
    sendChart(it.first, pos, emptyStyle);
2174
1.43k
    if (actPos[0]<actSquare)
2175
312
      actPos[0]+=1;
2176
1.12k
    else if (actPos[1]<actSquare)
2177
445
    {
2178
445
      actPos[1]+=1;
2179
445
      actPos[0]=actPos[1]==actSquare ? 0 : actSquare;
2180
445
    }
2181
675
    else
2182
675
      actPos=Vec2i(++actSquare, 0);
2183
1.43k
  }
2184
537
  return true;
2185
537
}
2186
2187
bool LotusChart::sendChart(int cId, WPSPosition const &pos, WPSGraphicStyle const &style)
2188
7.39k
{
2189
7.39k
  if (m_listener.get() == nullptr)
2190
0
  {
2191
0
    WPS_DEBUG_MSG(("LotusChart::sendChart: I can not find the listener\n"));
2192
0
    return false;
2193
0
  }
2194
7.39k
  auto it=m_state->m_idChartMap.find(cId);
2195
7.39k
  if (it==m_state->m_idChartMap.end() || !it->second)
2196
2.59k
  {
2197
2.59k
    WPS_DEBUG_MSG(("LotusChart::sendChart: I can not find the chart with id=%d\n", cId));
2198
2.59k
    return false;
2199
2.59k
  }
2200
4.80k
  if ((it->second->m_dimension[0]<=0 || it->second->m_dimension[1]<=0) &&
2201
1.47k
          pos.size()[0]>0 && pos.size()[1]>0)   // set basic dimension
2202
1.18k
  {
2203
1.18k
    float factor=WPSPosition::getScaleFactor(pos.unit(), librevenge::RVNG_POINT);
2204
1.18k
    it->second->m_dimension=factor*pos.size();
2205
1.18k
  }
2206
4.80k
  it->second->m_style=style;
2207
4.80k
  m_listener->insertChart(pos, *it->second);
2208
4.80k
  return true;
2209
7.39k
}
2210
2211
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */