Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/ClarisWksSpreadsheet.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <iomanip>
35
#include <iostream>
36
#include <limits>
37
#include <map>
38
#include <sstream>
39
40
#include <librevenge/librevenge.h>
41
42
#include "MWAWCell.hxx"
43
#include "MWAWFont.hxx"
44
#include "MWAWFontConverter.hxx"
45
#include "MWAWListener.hxx"
46
#include "MWAWParser.hxx"
47
#include "MWAWSpreadsheetListener.hxx"
48
#include "MWAWTable.hxx"
49
50
#include "ClarisWksDbaseContent.hxx"
51
#include "ClarisWksDocument.hxx"
52
#include "ClarisWksStruct.hxx"
53
#include "ClarisWksStyleManager.hxx"
54
55
#include "ClarisWksSpreadsheet.hxx"
56
57
/** Internal: the structures of a ClarisWksSpreadsheet */
58
namespace ClarisWksSpreadsheetInternal
59
{
60
//! Internal the spreadsheet
61
struct Spreadsheet final : public ClarisWksStruct::DSET {
62
  // constructor
63
  explicit Spreadsheet(ClarisWksStruct::DSET const &dset = ClarisWksStruct::DSET()) :
64
424k
    ClarisWksStruct::DSET(dset), m_colWidths(), m_rowHeightMap(), m_content()
65
424k
  {
66
424k
  }
67
  //! destructor
68
  ~Spreadsheet() final;
69
  //! operator<<
70
  friend std::ostream &operator<<(std::ostream &o, Spreadsheet const &doc)
71
0
  {
72
0
    o << static_cast<ClarisWksStruct::DSET const &>(doc);
73
0
    return o;
74
0
  }
75
  //! returns the row size in point
76
  float getRowHeight(int row) const
77
6.21M
  {
78
6.21M
    if (m_rowHeightMap.find(row)!=m_rowHeightMap.end())
79
330k
      return float(m_rowHeightMap.find(row)->second);
80
5.88M
    return 14;
81
6.21M
  }
82
  //! returns the height of a row in point and updated repeated row
83
  float getRowHeight(int row, int &numRepeated) const
84
404k
  {
85
404k
    int res=14;
86
404k
    if (m_rowHeightMap.empty()) {
87
303k
      numRepeated=1000;
88
303k
      return float(res);
89
303k
    }
90
101k
    auto it=m_rowHeightMap.lower_bound(row);
91
101k
    if (it==m_rowHeightMap.end()) {
92
6.29k
      numRepeated=1000;
93
6.29k
      return float(res);
94
6.29k
    }
95
94.7k
    numRepeated=1;
96
94.7k
    if (it->first==row)
97
79.1k
      res=it++->second;
98
94.7k
    int lastRow=row;
99
126k
    while (it!=m_rowHeightMap.end()) {
100
126k
      int nRow=it->first;
101
126k
      int nextH=it++->second;
102
103
126k
      if (nRow!=lastRow+1) {
104
21.8k
        if (res!=14)
105
10.3k
          break;
106
11.4k
        else
107
11.4k
          numRepeated+=(nRow-(lastRow+1));
108
21.8k
      }
109
116k
      if (nRow==row)
110
0
        continue;
111
116k
      numRepeated=(nRow-row);
112
116k
      if (nextH!=res)
113
84.1k
        break;
114
31.9k
      ++numRepeated;
115
31.9k
      lastRow=nRow;
116
31.9k
    }
117
94.7k
    return float(res);
118
101k
  }
119
120
  //! the columns width
121
  std::vector<int> m_colWidths;
122
  //! a map row to height
123
  std::map<int, int> m_rowHeightMap;
124
  //! the data
125
  std::shared_ptr<ClarisWksDbaseContent> m_content;
126
};
127
128
Spreadsheet::~Spreadsheet()
129
424k
{
130
424k
}
131
132
//! Internal: the state of a ClarisWksSpreadsheet
133
struct State {
134
  //! constructor
135
  State()
136
500k
    : m_spreadsheetMap()
137
500k
  {
138
500k
  }
139
  //! a map zoneId to spreadsheet
140
  std::map<int, std::shared_ptr<Spreadsheet> > m_spreadsheetMap;
141
};
142
143
}
144
145
////////////////////////////////////////////////////////////
146
// constructor/destructor, ...
147
////////////////////////////////////////////////////////////
148
ClarisWksSpreadsheet::ClarisWksSpreadsheet(ClarisWksDocument &document)
149
500k
  : m_document(document)
150
500k
  , m_parserState(document.m_parserState)
151
500k
  , m_state(new ClarisWksSpreadsheetInternal::State)
152
500k
  , m_mainParser(&document.getMainParser())
153
500k
{
154
500k
}
155
156
ClarisWksSpreadsheet::~ClarisWksSpreadsheet()
157
500k
{ }
158
159
int ClarisWksSpreadsheet::version() const
160
1.03M
{
161
1.03M
  return m_parserState->m_version;
162
1.03M
}
163
164
// fixme
165
int ClarisWksSpreadsheet::numPages() const
166
167k
{
167
167k
  return 1;
168
167k
}
169
////////////////////////////////////////////////////////////
170
// Intermediate level
171
////////////////////////////////////////////////////////////
172
173
////////////////////////////////////////////////////////////
174
// a document part
175
////////////////////////////////////////////////////////////
176
std::shared_ptr<ClarisWksStruct::DSET> ClarisWksSpreadsheet::readSpreadsheetZone
177
(ClarisWksStruct::DSET const &zone, MWAWEntry const &entry, bool &complete)
178
433k
{
179
433k
  complete = false;
180
433k
  if (!entry.valid() || zone.m_fileType != 2 || entry.length() < 256)
181
8.81k
    return std::shared_ptr<ClarisWksStruct::DSET>();
182
424k
  long pos = entry.begin();
183
424k
  MWAWInputStreamPtr &input= m_parserState->m_input;
184
424k
  input->seek(pos+8+16, librevenge::RVNG_SEEK_SET); // avoid header+8 generic number
185
424k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
186
424k
  libmwaw::DebugStream f;
187
424k
  std::shared_ptr<ClarisWksSpreadsheetInternal::Spreadsheet>
188
424k
  sheet(new ClarisWksSpreadsheetInternal::Spreadsheet(zone));
189
190
424k
  f << "Entries(SpreadsheetDef):" << *sheet << ",";
191
424k
  ascFile.addDelimiter(input->tell(), '|');
192
424k
  ascFile.addPos(pos);
193
424k
  ascFile.addNote(f.str().c_str());
194
195
  // read the last part
196
424k
  long data0Length = zone.m_dataSz;
197
424k
  long N = zone.m_numData;
198
424k
  if (entry.length() -8-12 != data0Length*N + zone.m_headerSz) {
199
266k
    if (data0Length == 0 && N) {
200
5.47k
      MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: can not find definition size\n"));
201
5.47k
      input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
202
5.47k
      return std::shared_ptr<ClarisWksStruct::DSET>();
203
5.47k
    }
204
205
260k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: unexpected size for zone definition, try to continue\n"));
206
260k
  }
207
418k
  int debColSize = 0;
208
418k
  int vers = version();
209
418k
  switch (vers) {
210
111k
  case 1:
211
111k
    debColSize = 72;
212
111k
    break;
213
44.6k
  case 2:
214
96.1k
  case 3: // checkme...
215
141k
  case 4:
216
256k
  case 5:
217
256k
    debColSize = 76;
218
256k
    break;
219
50.6k
  case 6:
220
50.6k
    debColSize = 72;
221
50.6k
    break;
222
0
  default:
223
0
    break;
224
418k
  }
225
226
418k
  sheet->m_colWidths.resize(0);
227
418k
  sheet->m_colWidths.resize(256,36);
228
418k
  if (debColSize) {
229
418k
    pos = entry.begin()+debColSize;
230
418k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
231
418k
    f.str("");
232
418k
    f << "Entries(SpreadsheetCol):width,";
233
107M
    for (size_t i = 0; i < 256; ++i) {
234
107M
      auto w=static_cast<int>(input->readULong(1));
235
107M
      sheet->m_colWidths[i]=w;
236
107M
      if (w!=36) // default
237
78.7M
        f << "w" << i << "=" << w << ",";
238
107M
    }
239
418k
    ascFile.addPos(pos);
240
418k
    ascFile.addNote(f.str().c_str());
241
242
418k
    ascFile.addPos(input->tell());
243
418k
    ascFile.addNote("SpreadsheetDef-A");
244
418k
  }
245
246
418k
  long dataEnd = entry.end()-N*data0Length;
247
418k
  int numLast = version()==6 ? 4 : 0;
248
418k
  if (long(input->tell()) + data0Length + numLast <= dataEnd) {
249
188k
    ascFile.addPos(dataEnd-data0Length-numLast);
250
188k
    ascFile.addNote("SpreadsheetDef-_");
251
188k
    if (numLast) {
252
31.1k
      ascFile.addPos(dataEnd-numLast);
253
31.1k
      ascFile.addNote("SpreadsheetDef-extra");
254
31.1k
    }
255
188k
  }
256
418k
  input->seek(dataEnd, librevenge::RVNG_SEEK_SET);
257
258
1.38M
  for (long i = 0; i < N; i++) {
259
967k
    pos = input->tell();
260
261
967k
    f.str("");
262
967k
    f << "SpreadsheetDef-" << i;
263
967k
    ascFile.addPos(pos);
264
967k
    ascFile.addNote(f.str().c_str());
265
967k
    input->seek(pos+data0Length, librevenge::RVNG_SEEK_SET);
266
967k
  }
267
268
418k
  input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
269
270
418k
  if (m_state->m_spreadsheetMap.find(sheet->m_id) != m_state->m_spreadsheetMap.end()) {
271
352k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: zone %d already exists!!!\n", sheet->m_id));
272
352k
  }
273
66.6k
  else
274
66.6k
    m_state->m_spreadsheetMap[sheet->m_id] = sheet;
275
276
418k
  sheet->m_otherChilds.push_back(sheet->m_id+1);
277
418k
  pos = input->tell();
278
279
418k
  bool ok = readZone1(*sheet);
280
418k
  if (ok) {
281
291k
    pos = input->tell();
282
291k
    ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetZone2", false);
283
291k
  }
284
418k
  if (ok) {
285
250k
    pos = input->tell();
286
250k
    std::shared_ptr<ClarisWksDbaseContent> content(new ClarisWksDbaseContent(m_document, true));
287
250k
    ok = content->readContent();
288
250k
    if (ok) sheet->m_content=content;
289
250k
  }
290
418k
  if (ok) {
291
111k
    pos = input->tell();
292
111k
    if (!readRowHeightZone(*sheet)) {
293
50.3k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
294
50.3k
      ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetRowHeight", false);
295
50.3k
    }
296
111k
  }
297
418k
  if (ok && vers <= 2) { // field with size 0xa in v2
298
22.6k
    pos = input->tell();
299
22.6k
    ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetUnkn1", false);
300
22.6k
  }
301
  /* checkme: now a sequence of 5/6 lists: when filed the first two zones are a list of cell,
302
   while the last 2 lists contains only 4 numbers */
303
1.28M
  while (ok) {
304
909k
    pos=input->tell();
305
909k
    auto sz=long(input->readULong(4));
306
909k
    if (!input->checkPosition(pos+4+sz)) {
307
40.6k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
308
40.6k
      break;
309
40.6k
    }
310
    // empty or list of 2*uint16_t ?
311
869k
    if (!sz) {
312
848k
      ascFile.addPos(pos);
313
848k
      ascFile.addNote("Entries(SpreadsheetListCell):_");
314
848k
      continue;
315
848k
    }
316
20.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
317
20.9k
    std::vector<MWAWVec2i> res;
318
20.9k
    ok = m_document.readStructCellZone("SpreadsheetListCell", false, res);
319
20.9k
    if (ok) continue;
320
17.5k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
321
17.5k
    ok = ClarisWksStruct::readStructZone(*m_parserState, "SpreadsheetUnkn2", false);
322
17.5k
    if (ok) {
323
4.26k
      MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find unexpected Unkn2 zone\n"));
324
4.26k
    }
325
17.5k
  }
326
418k
  if (ok) {
327
40.6k
    pos=input->tell();
328
40.6k
    auto sz=long(input->readULong(4));
329
40.6k
    if (input->checkPosition(pos+4+sz)) {
330
0
      input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
331
0
      ascFile.addPos(pos);
332
0
      MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find some extra block\n"));
333
0
      ascFile.addNote("Entries(SpreadsheetEnd):###");
334
0
    }
335
40.6k
    else
336
40.6k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
337
40.6k
  }
338
339
418k
  if (!ok) {
340
378k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readSpreadsheetZone: find a bad block\n"));
341
378k
    ascFile.addPos(pos);
342
378k
    ascFile.addNote("Entries(SpreadsheetEnd):###");
343
378k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
344
378k
  }
345
418k
  return sheet;
346
418k
}
347
348
////////////////////////////////////////////////////////////
349
//
350
// Intermediate level
351
//
352
////////////////////////////////////////////////////////////
353
bool ClarisWksSpreadsheet::readZone1(ClarisWksSpreadsheetInternal::Spreadsheet &/*sheet*/)
354
418k
{
355
418k
  MWAWInputStreamPtr &input= m_parserState->m_input;
356
418k
  long pos = input->tell();
357
418k
  auto sz = long(input->readULong(4));
358
418k
  long endPos = pos+4+sz;
359
418k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
360
418k
  if (long(input->tell()) != endPos) {
361
107k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
362
107k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readZone1: spreadsheet\n"));
363
107k
    return false;
364
107k
  }
365
311k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
366
311k
  if (sz == 0) {
367
113k
    ascFile.addPos(pos);
368
113k
    ascFile.addNote("Nop");
369
113k
    return true;
370
113k
  }
371
197k
  int fSize = 0;
372
197k
  switch (version()) {
373
18.0k
  case 4:
374
71.0k
  case 5:
375
71.0k
    fSize = 4;
376
71.0k
    break;
377
26.0k
  case 6:
378
26.0k
    fSize = 6;
379
26.0k
    break;
380
100k
  default:
381
100k
    break;
382
197k
  }
383
197k
  if (!fSize) {
384
100k
    ascFile.addPos(pos);
385
100k
    ascFile.addNote("Entries(SpreadsheetZone1)");
386
100k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
387
100k
    return true;
388
100k
  }
389
97.1k
  long numElts = sz/fSize;
390
97.1k
  if (numElts *fSize != sz) {
391
19.8k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
392
19.8k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readZone1: unexpected size\n"));
393
19.8k
    return false;
394
19.8k
  }
395
396
77.2k
  ascFile.addPos(pos);
397
77.2k
  ascFile.addNote("Entries(SpreadsheetZone1)");
398
399
77.2k
  libmwaw::DebugStream f;
400
77.2k
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
401
1.49M
  for (long i = 0; i < numElts; i++) {
402
1.41M
    pos = input->tell();
403
404
1.41M
    f.str("");
405
1.41M
    f << "SpreadsheetZone1-" << i << ":";
406
1.41M
    f << "row?=" << input->readLong(2) << ",";
407
1.41M
    f << "col?=" << input->readLong(2) << ",";
408
1.41M
    if (fSize == 6) {
409
266k
      auto val = static_cast<int>(input->readLong(2));
410
266k
      if (val != -1)
411
229k
        f << "#unkn=" << val << ",";
412
266k
    }
413
1.41M
    ascFile.addPos(pos);
414
1.41M
    ascFile.addNote(f.str().c_str());
415
1.41M
    input->seek(pos+fSize, librevenge::RVNG_SEEK_SET);
416
1.41M
  }
417
77.2k
  return true;
418
97.1k
}
419
420
bool ClarisWksSpreadsheet::readRowHeightZone(ClarisWksSpreadsheetInternal::Spreadsheet &sheet)
421
111k
{
422
111k
  MWAWInputStreamPtr &input= m_parserState->m_input;
423
111k
  long pos = input->tell();
424
111k
  ClarisWksStruct::Struct header;
425
111k
  if (!header.readHeader(input,false)) {
426
50.3k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readRowHeightZone: can not read the header\n"));
427
50.3k
    return false;
428
50.3k
  }
429
61.0k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
430
61.0k
  libmwaw::DebugStream f;
431
61.0k
  if (header.m_size==0) {
432
25.8k
    ascFile.addPos(pos);
433
25.8k
    ascFile.addNote("Nop");
434
25.8k
    return true;
435
25.8k
  }
436
35.2k
  long endPos=pos+4+header.m_size;
437
35.2k
  f << "Entries(SpreadsheetRowHeight):" << header;
438
35.2k
  if (header.m_dataSize!=4) {
439
7.79k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
440
7.79k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::readRowHeightZone: unexpected size for fieldSize\n"));
441
7.79k
    f << "###";
442
7.79k
    ascFile.addPos(pos);
443
7.79k
    ascFile.addNote(f.str().c_str());
444
7.79k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
445
7.79k
    return true;
446
7.79k
  }
447
27.4k
  if (header.m_headerSize) {
448
15.1k
    ascFile.addDelimiter(input->tell(),'|');
449
15.1k
    input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR);
450
15.1k
  }
451
27.4k
  ascFile.addPos(pos);
452
27.4k
  ascFile.addNote(f.str().c_str());
453
454
50.6M
  for (long i = 0; i < header.m_numData; i++) {
455
50.5M
    pos = input->tell();
456
457
50.5M
    f.str("");
458
50.5M
    f << "SpreadsheetRowHeightZone-" << i << ":";
459
50.5M
    auto row=static_cast<int>(input->readLong(2));
460
50.5M
    auto h=static_cast<int>(input->readLong(2));
461
50.5M
    sheet.m_rowHeightMap[row]=h;
462
50.5M
    f << "row=" << row << ", height=" << h << ",";
463
50.5M
    ascFile.addPos(pos);
464
50.5M
    ascFile.addNote(f.str().c_str());
465
50.5M
  }
466
27.4k
  return true;
467
35.2k
}
468
469
////////////////////////////////////////////////////////////
470
//
471
// send data
472
//
473
////////////////////////////////////////////////////////////
474
bool ClarisWksSpreadsheet::sendSpreadsheet(int zId, MWAWListenerPtr listener)
475
281k
{
476
281k
  if (!listener)
477
33.0k
    listener=m_parserState->getMainListener();
478
281k
  if (!listener) {
479
0
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: called without any listener\n"));
480
0
    return false;
481
0
  }
482
281k
  if (listener->getType()!=MWAWListener::Spreadsheet ||
483
219k
      (m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET && zId!=1))
484
61.9k
    return sendSpreadsheetAsTable(zId, listener);
485
486
219k
  auto *sheetListener=static_cast<MWAWSpreadsheetListener *>(listener.get());
487
219k
  auto it=m_state->m_spreadsheetMap.find(zId);
488
219k
  if (it == m_state->m_spreadsheetMap.end() || !it->second) {
489
0
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find zone %d!!!\n", zId));
490
0
    return false;
491
0
  }
492
219k
  auto &sheet=*it->second;
493
219k
  MWAWVec2i minData, maxData;
494
219k
  if (!sheet.m_content || !sheet.m_content->getExtrema(minData,maxData)) {
495
97.7k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find content\n"));
496
97.7k
    return false;
497
97.7k
  }
498
121k
  if (m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET && zId==1)
499
477
    minData=MWAWVec2i(0,0);
500
121k
  std::vector<float> colSize(size_t(maxData[0]-minData[0]+1),72);
501
560k
  for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) {
502
439k
    if (c>=0 && c < int(sheet.m_colWidths.size()))
503
439k
      colSize[size_t(fC)]=2.0f*float(sheet.m_colWidths[size_t(c)]);
504
439k
  }
505
121k
  sheetListener->openSheet(colSize, librevenge::RVNG_POINT);
506
121k
  MWAWInputStreamPtr &input= m_parserState->m_input;
507
121k
  std::vector<int> rowsPos, colsPos;
508
121k
  if (!sheet.m_content->getRecordList(rowsPos)) {
509
0
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find the record position\n"));
510
0
    sheetListener->closeSheet();
511
0
    return true;
512
0
  }
513
121k
  bool recomputeCellPosition=(minData!=MWAWVec2i(0,0));
514
121k
  int prevRow = minData[1]-1;
515
6.21M
  for (int r : rowsPos) {
516
6.21M
    int fR=r-minData[1];
517
6.21M
    if (r>prevRow+1) {
518
738k
      while (r > prevRow+1) {
519
404k
        int numRepeat;
520
404k
        auto h=float(sheet.getRowHeight(prevRow+1, numRepeat));
521
404k
        if (r<prevRow+1+numRepeat)
522
317k
          numRepeat=r-1-prevRow;
523
404k
        sheetListener->openSheetRow(h, librevenge::RVNG_POINT, numRepeat);
524
404k
        sheetListener->closeSheetRow();
525
404k
        prevRow+=numRepeat;
526
404k
      }
527
334k
    }
528
6.21M
    sheetListener->openSheetRow(float(sheet.getRowHeight(r)), librevenge::RVNG_POINT);
529
6.21M
    prevRow=r;
530
6.21M
    colsPos.clear();
531
6.21M
    if (!sheet.m_content->getColumnList(r, colsPos)) {
532
0
      MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheet: can not find the columns for row=%d\n", r));
533
0
      sheetListener->closeSheetRow();
534
0
      continue;
535
0
    }
536
9.36M
    for (auto c : colsPos) {
537
9.36M
      ClarisWksDbaseContent::Record rec;
538
9.36M
      if (!sheet.m_content->get(MWAWVec2i(c,r),rec)) continue;
539
9.36M
      MWAWCell cell;
540
9.36M
      cell.setPosition(MWAWVec2i(c-minData[0],fR));
541
9.36M
      cell.setFormat(rec.m_format);
542
9.36M
      cell.setHAlignment(rec.m_hAlign);
543
9.36M
      cell.setFont(rec.m_font);
544
9.36M
      if (recomputeCellPosition)
545
312k
        rec.updateFormulaCells(minData);
546
      // change the reference date from 1/1/1904 to 1/1/1900
547
9.36M
      if (rec.m_format.m_format==MWAWCell::F_DATE && rec.m_content.isValueSet())
548
672k
        rec.m_content.setValue(rec.m_content.m_value+1460);
549
9.36M
      if (rec.m_borders) {
550
1.31M
        int wh=0;
551
6.58M
        for (int b=0, bit=1; b < 4; ++b, bit*=2) {
552
5.26M
          if ((rec.m_borders&bit)==0) continue;
553
2.92M
          static int const what[] = {libmwaw::LeftBit, libmwaw::TopBit, libmwaw::RightBit, libmwaw::BottomBit};
554
2.92M
          wh |= what[b];
555
2.92M
        }
556
1.31M
        cell.setBorders(wh, MWAWBorder());
557
1.31M
      }
558
9.36M
      if (!rec.m_backgroundColor.isWhite())
559
1.72k
        cell.setBackgroundColor(rec.m_backgroundColor);
560
9.36M
      sheetListener->openSheetCell(cell, rec.m_content);
561
9.36M
      if (rec.m_content.m_textEntry.valid()) {
562
283k
        long fPos = input->tell();
563
283k
        input->seek(rec.m_content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET);
564
283k
        long endPos = rec.m_content.m_textEntry.end();
565
283k
        sheetListener->setFont(rec.m_font);
566
25.8M
        while (!input->isEnd() && input->tell() < endPos) {
567
25.5M
          auto ch=static_cast<unsigned char>(input->readULong(1));
568
25.5M
          if (ch==0xd || ch==0xa)
569
371k
            sheetListener->insertEOL();
570
25.1M
          else
571
25.1M
            sheetListener->insertCharacter(ch, input, endPos);
572
25.5M
        }
573
283k
        input->seek(fPos,librevenge::RVNG_SEEK_SET);
574
283k
      }
575
9.36M
      sheetListener->closeSheetCell();
576
9.36M
    }
577
6.21M
    sheetListener->closeSheetRow();
578
6.21M
  }
579
121k
  sheetListener->closeSheet();
580
121k
  return true;
581
121k
}
582
583
bool ClarisWksSpreadsheet::sendSpreadsheetAsTable(int zId, MWAWListenerPtr listener)
584
61.9k
{
585
61.9k
  if (!listener)
586
0
    listener=m_parserState->getMainListener();
587
61.9k
  if (!listener) {
588
0
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: called without any listener\n"));
589
0
    return false;
590
0
  }
591
61.9k
  auto it=m_state->m_spreadsheetMap.find(zId);
592
61.9k
  if (it == m_state->m_spreadsheetMap.end() || !it->second) {
593
0
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: can not find zone %d!!!\n", zId));
594
0
    return false;
595
0
  }
596
61.9k
  auto &sheet=*it->second;
597
61.9k
  MWAWVec2i minData, maxData;
598
61.9k
  if (!sheet.m_content || !sheet.m_content->getExtrema(minData,maxData)) {
599
32.4k
    MWAW_DEBUG_MSG(("ClarisWksSpreadsheet::sendSpreadsheetAsTable: can not find content\n"));
600
32.4k
    return false;
601
32.4k
  }
602
29.5k
  std::vector<float> colSize(size_t(maxData[0]-minData[0]+1),72);
603
131k
  for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) {
604
102k
    if (c>=0 && c < int(sheet.m_colWidths.size()))
605
102k
      colSize[size_t(fC)]=2.0f*float(sheet.m_colWidths[size_t(c)]);
606
102k
  }
607
29.5k
  MWAWTable table(MWAWTable::TableDimBit);
608
29.5k
  table.setColsSize(colSize);
609
29.5k
  listener->openTable(table);
610
1.69M
  for (int r=minData[1], fR=0; r <= maxData[1]; ++r, ++fR) {
611
1.66M
    if (sheet.m_rowHeightMap.find(r)!=sheet.m_rowHeightMap.end())
612
99.5k
      listener->openTableRow(float(sheet.m_rowHeightMap.find(r)->second), librevenge::RVNG_POINT);
613
1.56M
    else
614
1.56M
      listener->openTableRow(14.f, librevenge::RVNG_POINT);
615
7.28M
    for (int c=minData[0], fC=0; c <= maxData[0]; ++c, ++fC) {
616
5.61M
      MWAWCell cell;
617
5.61M
      cell.setPosition(MWAWVec2i(fC,fR));
618
5.61M
      cell.setVAlignment(MWAWCell::VALIGN_BOTTOM); // always ?
619
5.61M
      listener->openTableCell(cell);
620
5.61M
      sheet.m_content->send(MWAWVec2i(c, r));
621
5.61M
      listener->closeTableCell();
622
5.61M
    }
623
1.66M
    listener->closeTableRow();
624
1.66M
  }
625
29.5k
  listener->closeTable();
626
29.5k
  return true;
627
61.9k
}
628
629
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: