Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/ClarisWksDbaseContent.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 <time.h>
35
36
#include <cmath>
37
#include <cstring>
38
#include <ctime>
39
#include <iomanip>
40
#include <iostream>
41
#include <set>
42
#include <sstream>
43
#include <limits>
44
45
#include <librevenge/librevenge.h>
46
47
#include "MWAWDebug.hxx"
48
#include "MWAWHeader.hxx"
49
#include "MWAWInputStream.hxx"
50
#include "MWAWListener.hxx"
51
#include "MWAWParagraph.hxx"
52
#include "MWAWParser.hxx"
53
54
#include "ClarisWksDocument.hxx"
55
#include "ClarisWksStyleManager.hxx"
56
57
#include "ClarisWksDbaseContent.hxx"
58
59
ClarisWksDbaseContent::ClarisWksDbaseContent(ClarisWksDocument &document, bool spreadsheet)
60
613k
  : m_version(0)
61
613k
  , m_isSpreadsheet(spreadsheet)
62
613k
  , m_document(document)
63
613k
  , m_parserState(document.m_parserState)
64
613k
  , m_idColumnMap()
65
613k
  , m_positionSet()
66
613k
  , m_dbFormatList()
67
613k
{
68
613k
  if (!m_parserState || !m_parserState->m_header) {
69
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::ClarisWksDbaseContent: can not find the file header\n"));
70
0
    return;
71
0
  }
72
613k
  m_version = m_parserState->m_header->getMajorVersion();
73
613k
}
74
75
ClarisWksDbaseContent::~ClarisWksDbaseContent()
76
613k
{
77
613k
}
78
79
void ClarisWksDbaseContent::setDatabaseFormats(std::vector<ClarisWksStyleManager::CellFormat> const &format)
80
3.70k
{
81
3.70k
  if (m_isSpreadsheet) {
82
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::setDatabaseFormats: called with spreadsheet\n"));
83
0
    return;
84
0
  }
85
3.70k
  m_dbFormatList=format;
86
3.70k
}
87
88
bool ClarisWksDbaseContent::getExtrema(MWAWVec2i &min, MWAWVec2i &max) const
89
170k
{
90
170k
  if (m_idColumnMap.empty())
91
15.5k
    return false;
92
154k
  bool first=true;
93
260k
  for (auto const &it : m_idColumnMap) {
94
260k
    int col=it.first;
95
260k
    Column const &column=it.second;
96
260k
    if (column.m_idRecordMap.empty())
97
0
      continue;
98
260k
    max[0]=col;
99
11.2M
    for (auto const &rIt : column.m_idRecordMap) {
100
11.2M
      int row=rIt.first;
101
11.2M
      if (first) {
102
154k
        min[0]=col;
103
154k
        min[1]=max[1]=row;
104
154k
        first=false;
105
154k
      }
106
11.1M
      else if (row < min[1])
107
5.69k
        min[1]=row;
108
11.1M
      else if (row > max[1])
109
6.52M
        max[1]=row;
110
11.2M
    }
111
260k
  }
112
154k
  return !first;
113
170k
}
114
115
void ClarisWksDbaseContent::updateCellPositionsSet() const
116
6.21M
{
117
6.21M
  if (!m_positionSet.empty() || m_idColumnMap.empty())
118
6.20M
    return;
119
23.8k
  for (auto const &it : m_idColumnMap) {
120
23.8k
    int col=it.first;
121
23.8k
    Column const &column=it.second;
122
1.02M
    for (auto const &rIt : column.m_idRecordMap) {
123
1.02M
      int row=rIt.first;
124
1.02M
      m_positionSet.insert(MWAWVec2i(col,row));
125
1.02M
    }
126
23.8k
  }
127
13.1k
}
128
129
bool ClarisWksDbaseContent::getRecordList(std::vector<int> &list) const
130
125k
{
131
125k
  list.resize(0);
132
125k
  if (m_idColumnMap.empty())
133
0
    return false;
134
125k
  std::set<int> set;
135
209k
  for (auto const &it : m_idColumnMap) {
136
209k
    Column const &column=it.second;
137
209k
    for (auto const &rIt : column.m_idRecordMap)
138
9.46M
      set.insert(rIt.first);
139
209k
  }
140
125k
  if (set.empty())
141
0
    return false;
142
125k
  list = std::vector<int>(set.begin(), set.end());
143
144
125k
  return true;
145
125k
}
146
147
bool ClarisWksDbaseContent::getColumnList(int row, std::vector<int> &list) const
148
6.21M
{
149
6.21M
  list.resize(0);
150
6.21M
  if (m_idColumnMap.empty())
151
0
    return false;
152
153
6.21M
  updateCellPositionsSet();
154
6.21M
  auto rIt=m_positionSet.lower_bound(MWAWVec2i(-1,row));
155
15.5M
  while (rIt!=m_positionSet.end()) {
156
15.4M
    MWAWVec2i const &pos=*(rIt++);
157
15.4M
    if (pos[1]!=row)
158
6.09M
      break;
159
9.36M
    list.push_back(pos[0]);
160
9.36M
  }
161
162
6.21M
  return !list.empty();
163
6.21M
}
164
165
bool ClarisWksDbaseContent::readContent()
166
558k
{
167
558k
  if (!m_parserState) return false;
168
558k
  MWAWInputStreamPtr &input= m_parserState->m_input;
169
558k
  long pos = input->tell();
170
558k
  auto sz = long(input->readULong(4));
171
  /** ARGHH: this zone is almost the only zone which count the header in sz ... */
172
558k
  long endPos = pos+sz;
173
558k
  std::string zoneName(m_isSpreadsheet ? "spread" : "dbase");
174
558k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
175
558k
  if (long(input->tell()) != endPos || sz < 6) {
176
96.7k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
177
96.7k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readContent: file is too short\n"));
178
96.7k
    return false;
179
96.7k
  }
180
181
461k
  input->seek(pos+4, librevenge::RVNG_SEEK_SET);
182
461k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
183
461k
  libmwaw::DebugStream f;
184
461k
  f << "Entries(DBHeader)[" << zoneName << "]:";
185
461k
  auto N = static_cast<int>(input->readULong(2));
186
461k
  f << "N=" << N << ",";
187
461k
  ascFile.addPos(pos);
188
461k
  ascFile.addNote(f.str().c_str());
189
190
461k
  input->pushLimit(endPos);
191
461k
  readColumnList();
192
193
461k
  if (input->tell() == endPos) {
194
151k
    input->popLimit();
195
151k
    return true;
196
151k
  }
197
  /* can we have more than one sheet ? If so, going into the while
198
     loop may be ok, we will not read the data...*/
199
309k
  MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readContent: find extra data\n"));
200
309k
  bool ok=true;
201
2.03M
  while (input->tell() < endPos) {
202
1.91M
    pos = input->tell();
203
1.91M
    sz = long(input->readULong(4));
204
1.91M
    long zoneEnd=pos+4+sz;
205
1.91M
    if (zoneEnd > endPos || (sz && sz < 12)) {
206
188k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
207
188k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readContent: find a odd content field\n"));
208
188k
      ok=false;
209
188k
      break;
210
188k
    }
211
1.72M
    if (!sz) {
212
1.60M
      ascFile.addPos(pos);
213
1.60M
      ascFile.addNote("Nop");
214
1.60M
      continue;
215
1.60M
    }
216
119k
    std::string name("");
217
595k
    for (int i = 0; i < 4; i++)
218
476k
      name+=char(input->readULong(1));
219
119k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readContent: find unexpected content field\n"));
220
119k
    f << "DBHeader[" << zoneName << "]:###" << name;
221
119k
    ascFile.addDelimiter(input->tell(),'|');
222
119k
    ascFile.addPos(pos);
223
119k
    ascFile.addNote(f.str().c_str());
224
119k
    input->seek(zoneEnd, librevenge::RVNG_SEEK_SET);
225
119k
  }
226
309k
  input->popLimit();
227
309k
  return ok;
228
461k
}
229
230
bool ClarisWksDbaseContent::readColumnList()
231
461k
{
232
461k
  if (!m_parserState) return false;
233
461k
  MWAWInputStreamPtr &input= m_parserState->m_input;
234
461k
  long pos=input->tell();
235
461k
  long sz=input->readLong(4);
236
461k
  std::string hName("");
237
2.30M
  for (int i=0; i < 4; ++i) hName+=char(input->readULong(1));
238
461k
  if (sz!=0x408 || hName!="CTAB" || !input->checkPosition(pos+4+sz)) {
239
252k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readCOLM: the entry seems bad\n"));
240
252k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
241
252k
    return false;
242
252k
  }
243
244
208k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
245
208k
  libmwaw::DebugStream f;
246
208k
  if (m_isSpreadsheet)
247
132k
    f << "Entries(DBCTAB)[spread]:";
248
76.6k
  else
249
76.6k
    f << "Entries(DBCTAB)[dbase]:";
250
208k
  auto N=static_cast<int>(input->readLong(2));
251
208k
  if (N) f << "Ncols=" << N << ",";
252
208k
  auto val=static_cast<int>(input->readLong(2));
253
208k
  if (val) f << "Nrows=" << val << ",";
254
208k
  if (N<0 || N>255) {
255
1.86k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readColumnList: the entries number of elements seems bad\n"));
256
1.86k
    f << "####";
257
1.86k
    ascFile.addPos(pos);
258
1.86k
    ascFile.addNote(f.str().c_str());
259
1.86k
    return false;
260
1.86k
  }
261
207k
  f << "ptr=[";
262
207k
  long ptr;
263
207k
  std::vector<long> listIds;
264
5.44M
  for (int i=0; i <= N; i++) {
265
5.23M
    ptr=long(input->readULong(4));
266
5.23M
    listIds.push_back(ptr);
267
5.23M
    if (ptr)
268
1.42M
      f << std::hex << ptr << std::dec << ",";
269
3.80M
    else
270
3.80M
      f << "_,";
271
5.23M
  }
272
207k
  f << "],";
273
47.9M
  for (int i=N+1; i<256; i++) { // always 0
274
47.7M
    ptr=long(input->readULong(4));
275
47.7M
    if (!ptr) continue;
276
4.20M
    static bool first=true;
277
4.20M
    if (first) {
278
37
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readColumnList: find some extra values\n"));
279
37
      first=false;
280
37
    }
281
4.20M
    f << "#g" << i << "=" << ptr << ",";
282
4.20M
  }
283
207k
  ascFile.addPos(pos);
284
207k
  ascFile.addNote(f.str().c_str());
285
601k
  for (size_t c=0; c<listIds.size(); c++) {
286
570k
    if (!listIds[c]) continue;
287
420k
    pos=input->tell();
288
420k
    if (readColumn(int(c)))
289
245k
      continue;
290
175k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
291
175k
    return false;
292
420k
  }
293
31.4k
  return true;
294
207k
}
295
296
bool ClarisWksDbaseContent::readColumn(int c)
297
420k
{
298
420k
  if (!m_parserState) return false;
299
420k
  MWAWInputStreamPtr &input= m_parserState->m_input;
300
420k
  long pos=input->tell();
301
420k
  long sz=input->readLong(4);
302
420k
  std::string hName("");
303
2.10M
  for (int i=0; i < 4; ++i) hName+=char(input->readULong(1));
304
420k
  int cPos[2];
305
420k
  for (int &i : cPos)
306
841k
    i=static_cast<int>(input->readLong(2));
307
420k
  if (sz!=8+4*(cPos[1]-cPos[0]+1) || hName!="COLM" || !input->checkPosition(pos+4+sz)) {
308
140k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readCOLM: the entry seems bad\n"));
309
140k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
310
140k
    return false;
311
140k
  }
312
280k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
313
280k
  libmwaw::DebugStream f;
314
280k
  if (m_isSpreadsheet)
315
172k
    f << "Entries(DBCOLM)[spread]:";
316
108k
  else
317
108k
    f << "Entries(DBCOLM)[dbase]:";
318
280k
  f << "ptr[" << cPos[0] << "<=>" << cPos[1] << "]=[";
319
280k
  std::vector<long> listIds;
320
280k
  listIds.resize(size_t(cPos[0]),0);
321
560k
  for (int i=cPos[0]; i <= cPos[1]; i++) {
322
280k
    auto ptr=long(input->readULong(4));
323
280k
    listIds.push_back(ptr);
324
280k
    if (ptr)
325
279k
      f << std::hex << ptr << std::dec << ",";
326
407
    else
327
407
      f << "_,";
328
280k
  }
329
280k
  f << "],";
330
280k
  ascFile.addPos(pos);
331
280k
  ascFile.addNote(f.str().c_str());
332
333
  // now read the chnk
334
280k
  ClarisWksDbaseContent::Column col;
335
280k
  bool ok=true;
336
2.70M
  for (size_t i=0; i < listIds.size(); ++i) {
337
2.46M
    pos=input->tell();
338
2.46M
    if (!listIds[i] || readRecordList(MWAWVec2i(c,64*int(i)), col))
339
2.42M
      continue;
340
35.1k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
341
35.1k
    ok=false;
342
35.1k
    break;
343
2.46M
  }
344
280k
  if (!col.m_idRecordMap.empty())
345
244k
    m_idColumnMap[c]=col;
346
280k
  return ok;
347
420k
}
348
349
bool ClarisWksDbaseContent::readRecordList(MWAWVec2i const &where, Column &col)
350
279k
{
351
279k
  if (!m_parserState) return false;
352
279k
  MWAWInputStreamPtr &input= m_parserState->m_input;
353
279k
  long pos=input->tell();
354
279k
  long sz=input->readLong(4);
355
279k
  long endPos=pos+4+sz;
356
279k
  std::string hName("");
357
1.39M
  for (int i=0; i < 4; ++i) hName+=char(input->readULong(1));
358
279k
  auto N=static_cast<int>(input->readULong(2));
359
279k
  if (sz<6+134 || hName!="CHNK" || !input->checkPosition(pos+4+sz) || N>0x40) {
360
20.2k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordList: the entry seems bad\n"));
361
20.2k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
362
20.2k
    return false;
363
20.2k
  }
364
365
259k
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
366
259k
  libmwaw::DebugStream f;
367
259k
  std::string zoneName(m_isSpreadsheet ? "spread" : "dbase");
368
259k
  f << "Entries(DBCHNK)[" << zoneName << "]:N=" << N << ",";
369
259k
  auto type=static_cast<int>(input->readULong(2)); // often 400, 800...
370
259k
  f << "type=" << std::hex << type << std::dec << ",";
371
259k
  int dim[2]; // checkme
372
519k
  for (auto &d : dim) d=static_cast<int>(input->readLong(2));
373
259k
  f << "dim=" << dim[0] << "x" << dim[1] << ",";
374
375
259k
  f << "depl=[";
376
259k
  std::vector<long> ptrLists(64,0);
377
259k
  int find=0;
378
16.3M
  for (size_t i=0; i < 64; ++i) {
379
16.0M
    auto depl=long(input->readLong(2));
380
16.0M
    if (depl==0) {
381
7.25M
      f << "_,";
382
7.25M
      continue;
383
7.25M
    }
384
8.82M
    find++;
385
8.82M
    long fPos=pos+4+depl;
386
8.82M
    if (fPos > endPos) {
387
14.9k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordList: the %d ptr seems bad\n", static_cast<int>(i)));
388
14.9k
      f << "###";
389
14.9k
      ascFile.addPos(pos);
390
14.9k
      ascFile.addNote(f.str().c_str());
391
14.9k
      return false;
392
14.9k
    }
393
8.81M
    f << std::hex << depl << std::dec << ",";
394
8.81M
    ptrLists[i]=fPos;
395
8.81M
  }
396
244k
  f << "],";
397
244k
  if (find!=N) {
398
220k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordList: the number of find data seems bad\n"));
399
220k
    f << "###find=" << find << "!=" << N << ",";
400
220k
  }
401
244k
  ascFile.addPos(pos);
402
244k
  ascFile.addNote(f.str().c_str());
403
404
15.9M
  for (size_t i=0; i<64; ++i) {
405
15.6M
    if (!ptrLists[i]) continue;
406
8.56M
    Record record;
407
8.56M
    MWAWVec2i wh(where[0],where[1]+static_cast<int>(i));
408
8.56M
    if ((m_isSpreadsheet && readRecordSS(wh, ptrLists[i], record)) ||
409
7.46M
        (!m_isSpreadsheet && readRecordDB(wh, ptrLists[i], record))) {
410
7.46M
      col.m_idRecordMap[wh[1]]=record;
411
7.46M
      continue;
412
7.46M
    }
413
414
1.10M
    f.str("");
415
1.10M
    f << "DBCHNK[" << zoneName << wh << "]:#";
416
1.10M
    input->seek(ptrLists[i], librevenge::RVNG_SEEK_SET);
417
1.10M
    auto fType=static_cast<int>(input->readULong(1));
418
1.10M
    f << "type=" << std::hex << fType << std::dec << ",";
419
1.10M
    ascFile.addPos(ptrLists[i]);
420
1.10M
    ascFile.addNote(f.str().c_str());
421
1.10M
    col.m_idRecordMap[wh[1]]=record;
422
1.10M
  }
423
424
244k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
425
244k
  return true;
426
259k
}
427
428
bool ClarisWksDbaseContent::readRecordSSV1(MWAWVec2i const &id, long pos, ClarisWksDbaseContent::Record &record)
429
4.08M
{
430
4.08M
  record=ClarisWksDbaseContent::Record();
431
4.08M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
432
4.08M
  libmwaw::DebugStream f;
433
4.08M
  f << "DBCHNK[spread" << id << "]:";
434
4.08M
  MWAWInputStreamPtr &input= m_parserState->m_input;
435
4.08M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
436
4.08M
  auto val=static_cast<int>(input->readULong(1));
437
4.08M
  int type=(val>>4);
438
4.08M
  int fileFormat=(val&0xF);
439
4.08M
  auto &format=record.m_format;
440
4.08M
  switch (fileFormat) {
441
1.32M
  case 0: // general
442
1.32M
    break;
443
288k
  case 1:
444
288k
    format.m_format=MWAWCell::F_NUMBER;
445
288k
    format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY;
446
288k
    break;
447
188k
  case 2:
448
188k
    format.m_format=MWAWCell::F_NUMBER;
449
188k
    format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT;
450
188k
    break;
451
510k
  case 3:
452
510k
    format.m_format=MWAWCell::F_NUMBER;
453
510k
    format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC;
454
510k
    break;
455
178k
  case 4:
456
178k
    format.m_format=MWAWCell::F_NUMBER;
457
178k
    format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
458
178k
    break;
459
127k
  case 5:
460
326k
  case 6:
461
387k
  case 7:
462
570k
  case 8:
463
636k
  case 9: {
464
636k
    static char const* const wh[]= {"%m/%d/%y", "%B %d, %y", "%B %d, %Y", "%a, %b %d %y", "%A, %B %d %Y" };
465
636k
    format.m_format=MWAWCell::F_DATE;
466
636k
    format.m_DTFormat=wh[fileFormat-5];
467
636k
    break;
468
570k
  }
469
100k
  case 10:
470
201k
  case 11:
471
584k
  case 12:
472
655k
  case 13: {
473
655k
    static char const* const wh[]= {"%I:%M %p", "%I:%M:%S %p", "%H:%M", "%H:%M:%S" };
474
655k
    format.m_format=MWAWCell::F_TIME;
475
655k
    format.m_DTFormat=wh[fileFormat-10];
476
655k
    break;
477
584k
  }
478
305k
  default: // unknown
479
305k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: find unknown format\n"));
480
305k
    f << "format=##" << fileFormat << ",";
481
305k
    break;
482
4.08M
  }
483
484
4.08M
  bool ok=true;
485
4.08M
  auto ord=static_cast<int>(input->readULong(1));
486
4.08M
  if (ord&8) {
487
1.23M
    f << "commas[thousand],";
488
1.23M
    ord &= 0xF7;
489
1.23M
  }
490
4.08M
  if (ord&4) {
491
1.41M
    f << "parenthese[negative],";
492
1.41M
    ord &= 0xFB;
493
1.41M
  }
494
4.08M
  if (ord&2) {
495
1.39M
    f << "lock,";
496
1.39M
    ord &= 0xFD;
497
1.39M
  }
498
4.08M
  if (ord&1) {
499
1.66M
    if (!input->checkPosition(pos+8)) {
500
408k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: can not read format\n"));
501
408k
      f << "###";
502
408k
      ok = false;
503
408k
    }
504
1.25M
    else {
505
1.25M
      MWAWFont &font = record.m_font;
506
1.25M
      font = MWAWFont();
507
1.25M
      auto fId= static_cast<int>(input->readULong(2));
508
1.25M
      if (fId!=0xFFFF)
509
1.16M
        font.setId(m_document.getStyleManager()->getFontId(static_cast<int>(fId)));
510
1.25M
      font.setSize(float(input->readULong(1)));
511
1.25M
      auto flag =static_cast<int>(input->readULong(1));
512
1.25M
      uint32_t flags=0;
513
1.25M
      if (flag&0x1) flags |= MWAWFont::boldBit;
514
1.25M
      if (flag&0x2) flags |= MWAWFont::italicBit;
515
1.25M
      if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
516
1.25M
      if (flag&0x8) flags |= MWAWFont::embossBit;
517
1.25M
      if (flag&0x10) flags |= MWAWFont::shadowBit;
518
1.25M
      if (flag&0x20) font.setDeltaLetterSpacing(-1);
519
1.25M
      if (flag&0x40) font.setDeltaLetterSpacing(1);
520
1.25M
      if (flag&0x80) font.setStrikeOutStyle(MWAWFont::Line::Simple);
521
1.25M
      font.setFlags(flags);
522
1.25M
      auto colId = static_cast<int>(input->readULong(1));
523
1.25M
      if (colId!=1) {
524
1.20M
        MWAWColor col;
525
1.20M
        if (m_document.getStyleManager()->getColor(colId, col))
526
1.09M
          font.setColor(col);
527
109k
        else {
528
109k
          MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: unknown color %d\n", colId));
529
109k
        }
530
1.20M
      }
531
1.25M
      f << "font=[" << font.getDebugString(m_parserState->m_fontConverter) << "],";
532
1.25M
      val=static_cast<int>(input->readULong(1));
533
1.25M
      record.m_borders = (val>>4);
534
1.25M
      if (record.m_borders) {
535
635k
        f << "border=";
536
635k
        if (record.m_borders&1) f << "L";
537
635k
        if (record.m_borders&2) f << "T";
538
635k
        if (record.m_borders&4) f << "R";
539
635k
        if (record.m_borders&8) f << "B";
540
635k
        f << ",";
541
635k
      }
542
1.25M
      val &=0xF;
543
1.25M
      switch ((val>>2)) {
544
519k
      case 1:
545
519k
        record.m_hAlign=MWAWCell::HALIGN_LEFT;
546
519k
        f << "left,";
547
519k
        break;
548
125k
      case 2:
549
125k
        record.m_hAlign=MWAWCell::HALIGN_CENTER;
550
125k
        f << "center,";
551
125k
        break;
552
173k
      case 3:
553
173k
        record.m_hAlign=MWAWCell::HALIGN_RIGHT;
554
173k
        f << "right,";
555
173k
        break;
556
438k
      default:
557
438k
        break;
558
1.25M
      }
559
1.25M
      val &=0x3;
560
1.25M
      if (val) f << "#unk=" << val << ",";
561
1.25M
      ascFile.addDelimiter(pos+2,'|');
562
1.25M
      input->seek(pos+8, librevenge::RVNG_SEEK_SET);
563
1.25M
      ascFile.addDelimiter(pos+8,'|');
564
1.25M
      ord &= 0xFE;
565
1.25M
    }
566
1.66M
  }
567
4.08M
  format.m_digits=(ord>>4);
568
4.08M
  ord &= 0xF;
569
4.08M
  if (ok && ord) {
570
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: find unexpected order\n"));
571
0
    f << "###ord=" << std::hex << ord << std::dec;
572
0
    ok = false;
573
0
  }
574
4.08M
  auto &content=record.m_content;
575
4.08M
  if (ok && type==4) {
576
273k
    f << "formula,";
577
273k
    long actPos=input->tell();
578
273k
    auto formSz=static_cast<int>(input->readULong(1));
579
273k
    if (!input->checkPosition(actPos+2+formSz)) {
580
514
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: the formula seems bad\n"));
581
514
      f << "###";
582
514
      ok = false;
583
514
    }
584
272k
    else {
585
272k
      ascFile.addDelimiter(input->tell(),'|');
586
272k
      std::vector<MWAWCellContent::FormulaInstruction> formula;
587
272k
      std::string error;
588
272k
      if (readFormula(id, actPos+1+formSz, formula, error)) {
589
21.8k
        content.m_contentType=MWAWCellContent::C_FORMULA;
590
21.8k
        content.m_formula=formula;
591
21.8k
      }
592
251k
      else {
593
251k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: can not read a formula\n"));
594
251k
        f << "###";
595
251k
      }
596
272k
      f << "form=";
597
272k
      for (auto const &fo : formula)
598
657k
        f << fo;
599
272k
      f << error << ",";
600
272k
      if ((formSz%2)==0) ++formSz;
601
272k
      input->seek(actPos+1+formSz, librevenge::RVNG_SEEK_SET);
602
272k
      ascFile.addDelimiter(input->tell(),'|');
603
272k
      val=static_cast<int>(input->readULong(1));
604
272k
      type=(val>>4);
605
272k
      if (val&0xF) f << "unkn0=" << (val&0xF) << ",";
606
272k
      val=static_cast<int>(input->readULong(1));
607
272k
      if (val) f << "unkn1=" << (val) << ",";
608
272k
    }
609
273k
  }
610
4.08M
  if (ok) {
611
3.67M
    long actPos=input->tell();
612
3.67M
    switch (type) {
613
1.83M
    case 0:
614
1.93M
    case 1:
615
1.93M
      if (type==0)
616
1.83M
        f << "int,";
617
94.6k
      else
618
94.6k
        f << "long,";
619
1.93M
      if (!input->checkPosition(actPos+2+2*type)) {
620
1.87k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: unexpected size for a int\n"));
621
1.87k
        f << "###";
622
1.87k
        ok = false;
623
1.87k
        break;
624
1.87k
      }
625
1.93M
      record.m_valueType=MWAWCellContent::C_NUMBER;
626
1.93M
      content.setValue(double(input->readLong(2+2*type)));
627
1.93M
      f << "val=" << content.m_value << ",";
628
1.93M
      break;
629
261k
    case 2: {
630
261k
      f << "float,";
631
261k
      if (!input->checkPosition(actPos+10)) {
632
2.76k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: unexpected size for a float\n"));
633
2.76k
        f << "###";
634
2.76k
        ok=false;
635
2.76k
        break;
636
2.76k
      }
637
258k
      record.m_valueType=MWAWCellContent::C_NUMBER;
638
258k
      double value;
639
258k
      if (input->readDouble10(value, record.m_hasNaNValue)) {
640
236k
        content.setValue(value);
641
236k
        f << "val=" << value << ",";
642
236k
      }
643
21.6k
      else {
644
21.6k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: can not read a float\n"));
645
21.6k
        f << "###,";
646
21.6k
      }
647
258k
      break;
648
261k
    }
649
135k
    case 3: {
650
135k
      f << "string,";
651
135k
      auto stringSize = static_cast<int>(input->readULong(1));
652
135k
      if (!input->checkPosition(actPos+1+stringSize)) {
653
461
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: the string(II) seems bad\n"));
654
461
        f << "###";
655
461
        ok=false;
656
461
        break;
657
461
      }
658
134k
      record.m_valueType=MWAWCellContent::C_TEXT;
659
134k
      content.m_textEntry.setBegin(input->tell());
660
134k
      content.m_textEntry.setLength(long(stringSize));
661
134k
      std::string data("");
662
9.75M
      for (int c=0; c < stringSize; ++c) data+=char(input->readULong(1));
663
134k
      f << "val=" << data << ",";
664
134k
      break;
665
135k
    }
666
    // case 4: the formula is already read
667
154k
    case 5: // bool
668
154k
      if (input->checkPosition(actPos+1)) {
669
153k
        if (!fileFormat)
670
10.3k
          format.m_format=MWAWCell::F_BOOLEAN;
671
153k
        record.m_valueType=MWAWCellContent::C_NUMBER;
672
153k
        content.setValue(double(input->readLong(1)));
673
153k
        f << "val=" << content.m_value << ",";
674
153k
        break;
675
153k
      }
676
954
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: can not read a bool\n"));
677
954
      f << "###bool,";
678
954
      break;
679
83.6k
    case 6:
680
83.6k
      if (input->checkPosition(actPos+1)) {
681
81.4k
        record.m_valueType=MWAWCellContent::C_NUMBER;
682
81.4k
        content.setValue(std::numeric_limits<double>::quiet_NaN());
683
81.4k
        record.m_hasNaNValue = true;
684
81.4k
        f << "val=nan" << input->readLong(1) << ",";
685
81.4k
        break;
686
81.4k
      }
687
2.19k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: can not read a nanc[formula]\n"));
688
2.19k
      f << "###nan[res],";
689
2.19k
      break;
690
40.9k
    case 7: // empty
691
40.9k
      break;
692
374k
    case 8: // checkme: does such cell can have data?
693
374k
      f << "recovered,";
694
374k
      break;
695
690k
    default:
696
690k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSSV1: unexpected type\n"));
697
690k
      f << "###type=" << type << ",";
698
690k
      ok=false;
699
690k
      break;
700
3.67M
    }
701
3.67M
  }
702
4.08M
  if (content.m_contentType!=MWAWCellContent::C_FORMULA)
703
4.06M
    content.m_contentType=record.m_valueType;
704
4.08M
  if (format.m_format==MWAWCell::F_UNKNOWN && content.isValueSet()) {
705
1.30M
    format.m_format=MWAWCell::F_NUMBER;
706
1.30M
    format.m_numberFormat=MWAWCell::F_NUMBER_GENERIC;
707
1.30M
  }
708
4.08M
  f << format << ",";
709
4.08M
  ascFile.addPos(pos);
710
4.08M
  ascFile.addNote(f.str().c_str());
711
4.08M
  if (ok) {
712
2.97M
    ascFile.addPos(input->tell());
713
2.97M
    ascFile.addNote("_");
714
2.97M
  }
715
4.08M
  return ok;
716
4.08M
}
717
718
bool ClarisWksDbaseContent::readRecordSS(MWAWVec2i const &id, long pos, ClarisWksDbaseContent::Record &record)
719
6.33M
{
720
6.33M
  if (m_version <= 3)
721
4.08M
    return readRecordSSV1(id, pos, record);
722
2.25M
  record=ClarisWksDbaseContent::Record();
723
2.25M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
724
2.25M
  libmwaw::DebugStream f;
725
2.25M
  f << "DBCHNK[spread" << id << "]:";
726
2.25M
  MWAWInputStreamPtr &input= m_parserState->m_input;
727
2.25M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
728
2.25M
  auto sz=long(input->readULong(2));
729
2.25M
  long endPos=pos+sz+2;
730
2.25M
  if (!input->checkPosition(endPos) || sz < 4) {
731
1.52M
    f << "###sz=" << sz;
732
1.52M
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the sz seems bad\n"));
733
1.52M
    ascFile.addPos(pos);
734
1.52M
    ascFile.addNote(f.str().c_str());
735
1.52M
    return true;
736
1.52M
  }
737
723k
  auto type=static_cast<int>(input->readULong(1));
738
  // next some format ?
739
723k
  auto val= static_cast<int>(input->readULong(1)); // 0-46
740
723k
  if (val) f << "format=" << std::hex << val << std::dec << ",";
741
723k
  record.m_style=static_cast<int>(input->readLong(2));
742
723k
  if (record.m_style) f << "Style-" << record.m_style << ",";
743
744
723k
  int fileFormat=0;
745
723k
  ClarisWksStyleManager::Style style;
746
723k
  ClarisWksStyleManager::CellFormat format;
747
723k
  if (m_document.getStyleManager()->get(record.m_style, style)) {
748
7.51k
    if (m_document.getStyleManager()->get(style.m_cellFormatId, format)) {
749
7.04k
      f << format << ",";
750
7.04k
      fileFormat=format.m_fileFormat;
751
7.04k
    }
752
7.51k
    if (style.m_fontId>=0)
753
7.37k
      m_document.getStyleManager()->get(style.m_fontId, record.m_font);
754
7.51k
    MWAWGraphicStyle graphStyle;
755
7.51k
    if (style.m_graphicId>=0 && m_document.getStyleManager()->get(style.m_graphicId, graphStyle)) {
756
7.06k
      if (graphStyle.hasSurfaceColor())
757
6.88k
        record.m_backgroundColor=graphStyle.m_surfaceColor;
758
7.06k
    }
759
7.51k
  }
760
723k
  switch (fileFormat) {
761
719k
  case 0: // general
762
719k
    break;
763
278
  case 1:
764
278
    format.m_format=MWAWCell::F_NUMBER;
765
278
    format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY;
766
278
    break;
767
245
  case 2:
768
245
    format.m_format=MWAWCell::F_NUMBER;
769
245
    format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT;
770
245
    break;
771
289
  case 3:
772
289
    format.m_format=MWAWCell::F_NUMBER;
773
289
    format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC;
774
289
    break;
775
601
  case 4:
776
601
    format.m_format=MWAWCell::F_NUMBER;
777
601
    format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
778
601
    break;
779
275
  case 5:
780
341
  case 6:
781
431
  case 7:
782
684
  case 8:
783
1.09k
  case 9: {
784
1.09k
    static char const* const wh[]= {"%m/%d/%y", "%B %d, %y", "%B %d, %Y", "%a, %b %d %y", "%A, %B %d %Y" };
785
1.09k
    format.m_format=MWAWCell::F_DATE;
786
1.09k
    format.m_DTFormat=wh[fileFormat-5];
787
1.09k
    break;
788
684
  }
789
0
  case 10:  // unknown
790
17
  case 11:
791
17
    break;
792
84
  case 12:
793
159
  case 13:
794
251
  case 14:
795
503
  case 15: {
796
503
    static char const* const wh[]= {"%H:%M", "%H:%M:%S", "%I:%M %p", "%I:%M:%S %p" };
797
503
    format.m_format=MWAWCell::F_TIME;
798
503
    format.m_DTFormat=wh[fileFormat-12];
799
503
    break;
800
251
  }
801
183
  default: // unknown
802
183
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: find unknown format\n"));
803
183
    f << "format=##" << fileFormat << ",";
804
183
    break;
805
723k
  }
806
807
723k
  auto &content=record.m_content;
808
723k
  bool ok=true;
809
723k
  if (type==4) {
810
90.8k
    f << "formula,";
811
90.8k
    if (sz<7) {
812
2.23k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the formula seems bad\n"));
813
2.23k
      f << "##sz,";
814
2.23k
      ok = false;
815
2.23k
    }
816
88.6k
    else {
817
88.6k
      type=static_cast<int>(input->readULong(1));
818
88.6k
      val=static_cast<int>(input->readLong(1));
819
88.6k
      if (val) f << "unkn=" << val << ","; // 1: maybe an enum stored by value instead of by id
820
88.6k
      auto formSz=static_cast<int>(input->readULong(1));
821
88.6k
      long actPos=input->tell();
822
88.6k
      ascFile.addDelimiter(actPos,'|');
823
824
88.6k
      if (8+formSz > sz) {
825
18.3k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the formula seems bad\n"));
826
18.3k
        f << "###";
827
18.3k
        ok=false;
828
18.3k
      }
829
70.2k
      else {
830
70.2k
        std::vector<MWAWCellContent::FormulaInstruction> formula;
831
70.2k
        std::string error;
832
70.2k
        if (readFormula(id, actPos+1+formSz, formula, error)) {
833
21.1k
          content.m_contentType=MWAWCellContent::C_FORMULA;
834
21.1k
          content.m_formula=formula;
835
21.1k
        }
836
49.1k
        else {
837
49.1k
          MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: can not read a formule\n"));
838
49.1k
          f << "###";
839
49.1k
        }
840
70.2k
        f << "form=";
841
70.2k
        for (auto const &fo : formula)
842
137k
          f << fo;
843
70.2k
        f << error << ",";
844
845
        /** checkme: there does not seem to be alignment, but another
846
            variable before the result */
847
70.2k
        input->seek(actPos+formSz+1, librevenge::RVNG_SEEK_SET);
848
70.2k
        ascFile.addDelimiter(input->tell(),'|');
849
70.2k
        sz=4+int(endPos-input->tell());
850
70.2k
      }
851
88.6k
    }
852
90.8k
  }
853
723k
  if (ok) {
854
702k
    switch (type) {
855
189k
    case 0:
856
220k
    case 1:
857
220k
      if (type==0)
858
189k
        f << "int,";
859
30.9k
      else
860
30.9k
        f << "long,";
861
220k
      if (sz==4) {
862
        // rare, broken file ? AppleWorks seems to display a 0, but show a different number in the formula
863
5.88k
        record.m_valueType=MWAWCellContent::C_NUMBER;
864
5.88k
        content.setValue(0);
865
5.88k
        f << "##val=" << 0 << ",";
866
5.88k
        break;
867
5.88k
      }
868
214k
      if (sz<6+2*type) {
869
7.32k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: unexpected size for a int\n"));
870
7.32k
        f << "###";
871
7.32k
        break;
872
7.32k
      }
873
207k
      record.m_valueType=MWAWCellContent::C_NUMBER;
874
207k
      content.setValue(double(input->readLong(2+2*type)));
875
207k
      f << "val=" << content.m_value << ",";
876
207k
      break;
877
40.4k
    case 2: {
878
40.4k
      f << "float,";
879
40.4k
      if (sz<0xe) {
880
5.90k
        if (sz>=0xc && input->checkPosition(input->tell()+10)) {
881
          // rare, broken file ? but as we have the main 8 bytes, let continue
882
1.71k
          MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: unexpected size for a float, try to read it\n"));
883
1.71k
          f << "#";
884
1.71k
        }
885
4.18k
        else {
886
4.18k
          MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: unexpected size for a float\n"));
887
4.18k
          f << "###";
888
4.18k
          break;
889
4.18k
        }
890
5.90k
      }
891
36.2k
      record.m_valueType=MWAWCellContent::C_NUMBER;
892
36.2k
      double value;
893
36.2k
      if (input->readDouble10(value, record.m_hasNaNValue)) {
894
33.3k
        content.setValue(value);
895
33.3k
        f << value << ",";
896
33.3k
      }
897
2.90k
      else {
898
2.90k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: can not read a float\n"));
899
2.90k
        f << "###,";
900
2.90k
      }
901
36.2k
      break;
902
40.4k
    }
903
82.0k
    case 3: {
904
82.0k
      f << "string,";
905
82.0k
      if (sz<5) {
906
2.51k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the string seems bad\n"));
907
2.51k
        f << "###";
908
2.51k
        break;
909
2.51k
      }
910
79.5k
      auto stringSize = static_cast<int>(input->readULong(1));
911
79.5k
      if (stringSize+5>sz) {
912
        // rare, broken file ? let try to read the beginning of the file
913
8.89k
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the string(II) seems bad, try to read the beginning\n"));
914
8.89k
        f << "###";
915
8.89k
        if (sz==5)
916
7.02k
          break;
917
1.86k
        stringSize=int(sz)-5;
918
1.86k
      }
919
72.4k
      record.m_valueType=MWAWCellContent::C_TEXT;
920
72.4k
      content.m_textEntry.setBegin(input->tell());
921
72.4k
      content.m_textEntry.setLength(long(stringSize));
922
72.4k
      std::string data("");
923
1.10M
      for (int c=0; c < stringSize; ++c) data+=char(input->readULong(1));
924
72.4k
      f << data << ",";
925
72.4k
      break;
926
79.5k
    }
927
    // 4: formula
928
19.7k
    case 5: // bool
929
19.7k
      if (sz>=4+1) {
930
18.9k
        if (format.m_format==MWAWCell::F_UNKNOWN)
931
18.9k
          format.m_format=MWAWCell::F_BOOLEAN;
932
18.9k
        record.m_valueType=MWAWCellContent::C_NUMBER;
933
18.9k
        content.setValue(double(input->readLong(1)));
934
18.9k
        f << "val=" << content.m_value << ",";
935
18.9k
        break;
936
18.9k
      }
937
794
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: can not read a bool\n"));
938
794
      f << "###bool,";
939
794
      break;
940
15.7k
    case 6:
941
15.7k
      if (sz>=4+1) {
942
11.0k
        record.m_valueType=MWAWCellContent::C_NUMBER;
943
11.0k
        content.setValue(std::numeric_limits<double>::quiet_NaN());
944
11.0k
        record.m_hasNaNValue = true;
945
11.0k
        f << "val=nan" << input->readLong(1) << ",";
946
11.0k
        break;
947
11.0k
      }
948
4.72k
      break;
949
4.72k
    case 7: // link/anchor/goto
950
3.13k
      if (sz<4) {
951
0
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the mark size seems bad\n"));
952
0
        f << "###mark";
953
0
        break;
954
0
      }
955
3.13k
      f << "mark,";
956
3.13k
      break;
957
25.1k
    case 8:
958
28.6k
    case 9:
959
28.6k
      f << "type" << type << ",";
960
28.6k
      if (sz<4) {
961
0
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordSS: the type%d seems bad\n", type));
962
0
        f << "###";
963
0
        break;
964
0
      }
965
28.6k
      break;
966
292k
    default:
967
292k
      f << "#type=" << type << ",";
968
702k
    }
969
702k
  }
970
723k
  if (content.m_contentType!=MWAWCellContent::C_FORMULA)
971
701k
    content.m_contentType=record.m_valueType;
972
723k
  record.m_format=format;
973
723k
  record.m_hAlign=format.m_hAlign;
974
723k
  record.m_borders=format.m_borders;
975
723k
  ascFile.addPos(pos);
976
723k
  ascFile.addNote(f.str().c_str());
977
723k
  ascFile.addPos(endPos);
978
723k
  ascFile.addNote("_");
979
723k
  return true;
980
723k
}
981
982
bool ClarisWksDbaseContent::readRecordDB(MWAWVec2i const &id, long pos, ClarisWksDbaseContent::Record &record)
983
2.23M
{
984
2.23M
  record=ClarisWksDbaseContent::Record();
985
2.23M
  libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
986
2.23M
  libmwaw::DebugStream f;
987
2.23M
  f << "DBCHNK[dbase" << id << "]:";
988
2.23M
  MWAWInputStreamPtr &input= m_parserState->m_input;
989
2.23M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
990
2.23M
  long sz=0;
991
2.23M
  long endPos=-1;
992
2.23M
  if (m_version>3) {
993
919k
    sz=long(input->readULong(2));
994
919k
    endPos=pos+sz+2;
995
919k
    if (!input->checkPosition(endPos) || sz < 2) {
996
413k
      f << "###sz=" << sz;
997
413k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: the sz seems bad\n"));
998
413k
      ascFile.addPos(pos);
999
413k
      ascFile.addNote(f.str().c_str());
1000
413k
      return true;
1001
413k
    }
1002
919k
  }
1003
1.81M
  auto val=static_cast<int>(input->readULong(2));
1004
1.81M
  int type=(val>>12);
1005
1.81M
  val = int(val&0xFFF);
1006
1.81M
  MWAWCellContent &content=record.m_content;
1007
1.81M
  switch (type) {
1008
746k
  case 0: {
1009
746k
    f << "string,";
1010
746k
    if ((m_version<=3&&!input->checkPosition(pos+2+val)) ||
1011
696k
        (m_version>3 && (val+2>sz || val+4<sz))) {
1012
140k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: the string(II) seems bad\n"));
1013
140k
      f << "###";
1014
140k
      break;
1015
140k
    }
1016
606k
    content.m_contentType=MWAWCellContent::C_TEXT;
1017
606k
    content.m_textEntry.setBegin(input->tell());
1018
606k
    content.m_textEntry.setLength(long(val));
1019
606k
    std::string data("");
1020
55.4M
    for (int c=0; c < val; ++c) data+=char(input->readULong(1));
1021
606k
    f << data << ",";
1022
606k
    break;
1023
746k
  }
1024
312k
  case 2: {
1025
312k
    if ((m_version<=3&&!input->checkPosition(pos+2+val+2)) ||
1026
276k
        (m_version>3 && val+2>sz)) {
1027
156k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: can not read a text and style field\n"));
1028
156k
      f << "##string2" << type << "[" << val << "],";
1029
156k
      break;
1030
156k
    }
1031
155k
    content.m_contentType=MWAWCellContent::C_TEXT;
1032
155k
    content.m_textEntry.setBegin(input->tell());
1033
155k
    content.m_textEntry.setLength(long(val));
1034
155k
    std::string data("");
1035
197M
    for (int c=0; c < val; ++c) data+=char(input->readULong(1));
1036
155k
    f << "string2," << data << ",";
1037
155k
    if (val&1) input->seek(1, librevenge::RVNG_SEEK_CUR);
1038
155k
    auto N=int(input->readULong(2));
1039
155k
    f << "N=" << N << ",";
1040
155k
    int fontSize = m_version<=3 ? 10 : m_version<=5 ? 12 : 18;
1041
155k
    if ((m_version<=3 && !input->checkPosition(input->tell()+fontSize*N)) ||
1042
117k
        (m_version>3 && input->tell()+fontSize*N>endPos)) {
1043
52.2k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: can not read the text's style\n"));
1044
52.2k
      f << "##N";
1045
52.2k
      break;
1046
52.2k
    }
1047
9.59M
    for (int i=0; i<N; ++i) {
1048
9.48M
      MWAWFont font;
1049
9.48M
      int posChar;
1050
9.48M
      if (!m_document.getStyleManager()->readFontAndPos(i, posChar, font)) {
1051
0
        MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: can not read the text's style\n"));
1052
0
        f << "##font";
1053
0
        break;
1054
0
      }
1055
9.48M
      record.m_posToFontMap[posChar]=font;
1056
9.48M
    }
1057
103k
    break;
1058
155k
  }
1059
102k
  case 4:
1060
    // find also some string here when val is not null so let test
1061
102k
    if (val && ((m_version>3 && val+2<=sz && val+4>=sz) || (m_version<=3 && input->checkPosition(pos+2+val)))) {
1062
70.4k
      content.m_contentType=MWAWCellContent::C_TEXT;
1063
70.4k
      content.m_textEntry.setBegin(input->tell());
1064
70.4k
      content.m_textEntry.setLength(long(val));
1065
70.4k
      std::string data("");
1066
95.9M
      for (int c=0; c < val; ++c) data+=char(input->readULong(1));
1067
70.4k
      f << "string4," << data << ",";
1068
70.4k
      break;
1069
70.4k
    }
1070
32.0k
    f << "intDB,";
1071
32.0k
    if ((m_version<=3&&!input->checkPosition(pos+2)) || (m_version>3 && sz!=2)) {
1072
12.5k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: unexpected size for a int\n"));
1073
12.5k
      f << "###";
1074
12.5k
      break;
1075
12.5k
    }
1076
19.5k
    content.m_contentType=MWAWCellContent::C_NUMBER;
1077
19.5k
    content.setValue(double(input->readLong(1)));
1078
19.5k
    break;
1079
160k
  case 8:
1080
182k
  case 9: {
1081
182k
    if (val) f << "unkn=" << std::hex << val << std::dec << ",";
1082
182k
    f << "float" << type << ",";
1083
182k
    if ((m_version<=3&&!input->checkPosition(pos+12)) || (m_version>3 && sz!=12)) {
1084
9.05k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: unexpected size for a float\n"));
1085
9.05k
      f << "###";
1086
9.05k
      break;
1087
9.05k
    }
1088
173k
    double value;
1089
173k
    if (input->readDouble10(value, record.m_hasNaNValue)) {
1090
166k
      content.m_contentType=MWAWCellContent::C_NUMBER;
1091
166k
      content.setValue(value);
1092
166k
      f << value << ",";
1093
166k
    }
1094
6.68k
    else {
1095
6.68k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readRecordDB: can not read a float\n"));
1096
6.68k
      f << "###,";
1097
6.68k
    }
1098
173k
    break;
1099
182k
  }
1100
475k
  default:
1101
475k
    if (val) f << "unkn=" << std::hex << val << std::dec << ",";
1102
475k
    f << "#type=" << type << ",";
1103
1.81M
  }
1104
1.81M
  ascFile.addPos(pos);
1105
1.81M
  ascFile.addNote(f.str().c_str());
1106
1.81M
  if (m_version>3) {
1107
506k
    ascFile.addPos(endPos);
1108
506k
    ascFile.addNote("_");
1109
506k
  }
1110
1.81M
  return true;
1111
1.81M
}
1112
1113
bool ClarisWksDbaseContent::get(MWAWVec2i const &pos, ClarisWksDbaseContent::Record &record) const
1114
15.2M
{
1115
15.2M
  auto it=m_idColumnMap.find(pos[0]);
1116
15.2M
  if (it==m_idColumnMap.end()) return false;
1117
12.4M
  Column const &col=it->second;
1118
12.4M
  auto rIt=col.m_idRecordMap.find(pos[1]);
1119
12.4M
  if (rIt==col.m_idRecordMap.end()) return false;
1120
11.2M
  record=rIt->second;
1121
11.2M
  if (m_isSpreadsheet) return true;
1122
1123
91.6k
  static bool first=true;
1124
91.6k
  if (pos[0]>=0&&pos[0]<int(m_dbFormatList.size())) {
1125
91.6k
    auto const &format=m_dbFormatList[size_t(pos[0])];
1126
91.6k
    record.m_format=format;
1127
91.6k
    record.m_fileFormat=format.m_fileFormat;
1128
91.6k
    record.m_hAlign=format.m_hAlign;
1129
91.6k
  }
1130
0
  else if (first) {
1131
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::get: can not find format for field %d\n", pos[0]));
1132
0
    first=false;
1133
0
  }
1134
91.6k
  return true;
1135
11.2M
}
1136
1137
bool ClarisWksDbaseContent::send(MWAWVec2i const &pos)
1138
5.61M
{
1139
5.61M
  MWAWListenerPtr listener=m_parserState->getMainListener();
1140
5.61M
  if (!listener) {
1141
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::send: can not find the listener\n"));
1142
0
    return false;
1143
0
  }
1144
5.61M
  Record record;
1145
5.61M
  if (!get(pos, record)) return true;
1146
1.80M
  auto const &content=record.m_content;
1147
1.80M
  listener->setFont(record.m_font);
1148
1.80M
  auto contentType= content.m_contentType==MWAWCellContent::C_FORMULA ? record.m_valueType : content.m_contentType;
1149
1.80M
  MWAWParagraph para;
1150
1.80M
  para.m_justify =
1151
1.80M
    record.m_hAlign==MWAWCell::HALIGN_LEFT ? MWAWParagraph::JustificationLeft :
1152
1.80M
    record.m_hAlign==MWAWCell::HALIGN_CENTER ? MWAWParagraph::JustificationCenter :
1153
1.70M
    record.m_hAlign==MWAWCell::HALIGN_RIGHT ? MWAWParagraph::JustificationRight :
1154
1.65M
    contentType==MWAWCellContent::C_TEXT ? MWAWParagraph::JustificationLeft :
1155
1.56M
    MWAWParagraph::JustificationRight;
1156
1.80M
  listener->setParagraph(para);
1157
1.80M
  switch (contentType) {
1158
1.18M
  case MWAWCellContent::C_NUMBER:
1159
1.18M
    if (record.m_fileFormat)
1160
0
      send(content.m_value, record.m_hasNaNValue, ClarisWksStyleManager::CellFormat(record.m_format));
1161
1.18M
    else {
1162
1.18M
      std::stringstream s;
1163
1.18M
      s << content.m_value;
1164
1.18M
      listener->insertUnicodeString(librevenge::RVNGString(s.str().c_str()));
1165
1.18M
    }
1166
1.18M
    break;
1167
70.9k
  case MWAWCellContent::C_TEXT:
1168
70.9k
    if (content.m_textEntry.valid()) {
1169
63.3k
      MWAWInputStreamPtr &input= m_parserState->m_input;
1170
63.3k
      long fPos = input->tell();
1171
63.3k
      input->seek(content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET);
1172
63.3k
      long endPos = content.m_textEntry.end();
1173
7.12M
      while (!input->isEnd() && input->tell() < endPos) {
1174
7.06M
        auto c=static_cast<unsigned char>(input->readULong(1));
1175
7.06M
        if (c==0x9)
1176
51.6k
          listener->insertTab();
1177
7.01M
        else if (c==0xd || c==0xa)
1178
94.8k
          listener->insertEOL();
1179
6.91M
        else
1180
6.91M
          listener->insertCharacter(c, input, endPos);
1181
7.06M
      }
1182
63.3k
      input->seek(fPos,librevenge::RVNG_SEEK_SET);
1183
63.3k
    }
1184
70.9k
    break;
1185
0
  case MWAWCellContent::C_FORMULA:
1186
0
  case MWAWCellContent::C_NONE:
1187
551k
  case MWAWCellContent::C_UNKNOWN:
1188
#if !defined(__clang__)
1189
  default:
1190
#endif
1191
551k
    break;
1192
1.80M
  }
1193
1.80M
  return true;
1194
1.80M
}
1195
1196
void ClarisWksDbaseContent::send(double val, bool isNotANumber, ClarisWksStyleManager::CellFormat const &format)
1197
0
{
1198
0
  MWAWListenerPtr listener=m_parserState->getMainListener();
1199
0
  if (!listener)
1200
0
    return;
1201
0
  std::stringstream s;
1202
0
  int const &type=format.m_fileFormat;
1203
  // note: if val*0!=0, val is a NaN so better so simply print NaN
1204
0
  if (type <= 0 || type >=16 || type==10 || type==11 || isNotANumber) {
1205
0
    s << val;
1206
0
    listener->insertUnicodeString(librevenge::RVNGString(s.str().c_str()));
1207
0
    return;
1208
0
  }
1209
0
  std::string value("");
1210
  // FIXME: must not be here, change the reference date from 1/1/1904 to 1/1/1900
1211
0
  if (MWAWCellContent::double2String(format.m_format==MWAWCell::F_DATE ? val+1460 : val, format, value))
1212
0
    s << value;
1213
0
  else {
1214
0
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::send: can not convert the actual value\n"));
1215
0
    s << val;
1216
0
  }
1217
0
  listener->insertUnicodeString(librevenge::RVNGString(s.str().c_str()));
1218
0
}
1219
1220
////////////////////////////////////////////////////////////
1221
// formula
1222
////////////////////////////////////////////////////////////
1223
bool ClarisWksDbaseContent::readCellInFormula(MWAWVec2i const &pos, MWAWCellContent::FormulaInstruction &instr)
1224
102k
{
1225
102k
  MWAWInputStreamPtr input=m_parserState->m_input;
1226
102k
  instr=MWAWCellContent::FormulaInstruction();
1227
102k
  instr.m_type=MWAWCellContent::FormulaInstruction::F_Cell;
1228
102k
  bool absolute[2] = { true, true};
1229
102k
  int cPos[2]= {0,0};
1230
306k
  for (int i=0; i<2; ++i) {
1231
204k
    auto val = static_cast<int>(input->readULong(2));
1232
204k
    if (val & 0x8000) {
1233
42.9k
      absolute[1-i]=false;
1234
42.9k
      if (val&0x4000)
1235
21.6k
        cPos[1-i] = pos[1-i]-1+(val-0xFFFF);
1236
21.3k
      else
1237
21.3k
        cPos[1-i] = pos[1-i]-1+(val-0x7FFF);
1238
42.9k
    }
1239
161k
    else
1240
161k
      cPos[1-i]=val;
1241
204k
  }
1242
102k
  if (m_version==6) {
1243
    // checkme: what is this number
1244
9.67k
    auto val=static_cast<int>(input->readLong(2));
1245
9.67k
    static bool first = true;
1246
9.67k
    if (val!=-1 && first) {
1247
37
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readCellInFormula: ARGHHH value after cell is %d\n", val));
1248
37
      first=false;
1249
37
    }
1250
9.67k
  }
1251
1252
102k
  if (cPos[0] < 0 || cPos[1] < 0) {
1253
13.0k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readCellInFormula: can not read cell position\n"));
1254
13.0k
    return false;
1255
13.0k
  }
1256
89.2k
  instr.m_position[0]=MWAWVec2i(cPos[0],cPos[1]);
1257
89.2k
  instr.m_positionRelative[0]=MWAWVec2b(!absolute[0], !absolute[1]);
1258
89.2k
  return true;
1259
102k
}
1260
1261
bool ClarisWksDbaseContent::readString(long endPos, std::string &res)
1262
34.5k
{
1263
34.5k
  res="";
1264
34.5k
  MWAWInputStreamPtr input=m_parserState->m_input;
1265
34.5k
  long pos=input->tell();
1266
34.5k
  auto stringSize=static_cast<int>(input->readULong(1));
1267
34.5k
  if (pos+1+stringSize>endPos || !input->checkPosition(pos+1+stringSize)) {
1268
3.61k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readString: can not read string size\n"));
1269
3.61k
    return false;
1270
3.61k
  }
1271
797k
  for (int i=0; i<stringSize; ++i)
1272
766k
    res += char(input->readULong(1));
1273
30.9k
  return true;
1274
34.5k
}
1275
1276
bool ClarisWksDbaseContent::readNumber(long endPos, double &res, bool &isNan)
1277
28.3k
{
1278
28.3k
  MWAWInputStreamPtr input=m_parserState->m_input;
1279
28.3k
  long pos=input->tell();
1280
28.3k
  if (pos+10>endPos) {
1281
6.87k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readNumber: can not read a number\n"));
1282
6.87k
    return false;
1283
6.87k
  }
1284
21.4k
  return input->readDouble10(res, isNan);
1285
28.3k
}
1286
1287
namespace ClarisWksDbaseContentInternal
1288
{
1289
struct Operators {
1290
  char const *m_name;
1291
  int m_arity;
1292
};
1293
1294
static Operators const s_listOperators[] = {
1295
  { "<", 2}, { ">", 2}, { "=", 2}, { "<=", 2},
1296
  { ">=", 2}, { "<>", 2}, { "&", 2},{ "+", 2},
1297
1298
  { "-", 2}, { "*", 2}, { "/", 2}, { "^", 2},
1299
  { "%", 1}/*percent*/, { "-", 1}, { "(", 1}, { "", -2} /*UNKN*/,
1300
};
1301
}
1302
1303
bool ClarisWksDbaseContent::readFormula(MWAWVec2i const &cPos, long endPos, std::vector<MWAWCellContent::FormulaInstruction> &formula, std::string &error)
1304
6.67M
{
1305
6.67M
  MWAWInputStreamPtr input=m_parserState->m_input;
1306
6.67M
  libmwaw::DebugStream f;
1307
6.67M
  bool ok=true;
1308
6.67M
  long pos=input->tell();
1309
6.67M
  if (input->isEnd() || pos >= endPos)
1310
71.6k
    return false;
1311
6.60M
  int arity=0, type=static_cast<int>(input->readULong(1));
1312
6.60M
  bool isFunction=false, isOperator=false;
1313
6.60M
  MWAWCellContent::FormulaInstruction instr;
1314
6.60M
  switch (type) {
1315
24.9k
  case 0x10:
1316
24.9k
    if (pos+1+2>endPos) {
1317
887
      ok=false;
1318
887
      break;
1319
887
    }
1320
24.1k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Long;
1321
24.1k
    instr.m_longValue=double(input->readLong(2));
1322
24.1k
    break;
1323
28.5k
  case 0x11:
1324
28.5k
    if (pos+1+4>endPos) {
1325
5.29k
      ok=false;
1326
5.29k
      break;
1327
5.29k
    }
1328
23.2k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Long;
1329
23.2k
    instr.m_longValue=double(input->readLong(4));
1330
23.2k
    break;
1331
28.3k
  case 0x12: {
1332
28.3k
    double value;
1333
28.3k
    bool isNan;
1334
28.3k
    ok=readNumber(endPos, value, isNan);
1335
28.3k
    if (!ok) break;
1336
20.8k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Double;
1337
20.8k
    instr.m_doubleValue=value;
1338
20.8k
    break;
1339
28.3k
  }
1340
32.3k
  case 0x13: {
1341
32.3k
    ok=readCellInFormula(cPos,instr);
1342
32.3k
    break;
1343
28.3k
  }
1344
9.74k
  case 0x1b:
1345
9.74k
    if (pos+1+8 > endPos) {
1346
2.10k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readFormula: find instruction 0x1b, unknown size\n"));
1347
2.10k
      f << "##[code=1b,short],";
1348
2.10k
      ok = false;
1349
2.10k
      break;
1350
2.10k
    }
1351
    /* found in some web files followed by a bad cell list */
1352
7.63k
    MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readFormula: find instruction 0x1b\n"));
1353
7.63k
    f << "##[code=1b],";
1354
7.63k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_CellList;
1355
7.63k
    input->seek(8, librevenge::RVNG_SEEK_SET);
1356
7.63k
    break;
1357
38.1k
  case 0x14: {
1358
38.1k
    if (pos+1+8 > endPos || !readCellInFormula(cPos, instr)) {
1359
4.10k
      f << "###list cell short";
1360
4.10k
      ok = false;
1361
4.10k
      break;
1362
4.10k
    }
1363
33.9k
    MWAWCellContent::FormulaInstruction instr2;
1364
33.9k
    if (!readCellInFormula(cPos, instr2)) {
1365
9.72k
      f << "###list cell short2";
1366
9.72k
      ok = false;
1367
9.72k
      break;
1368
9.72k
    }
1369
24.2k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_CellList;
1370
24.2k
    instr.m_position[1]=instr2.m_position[0];
1371
24.2k
    instr.m_positionRelative[1]=instr2.m_positionRelative[0];
1372
24.2k
    break;
1373
33.9k
  }
1374
34.5k
  case 0x15: {
1375
34.5k
    std::string text;
1376
34.5k
    ok=readString(endPos, text);
1377
34.5k
    if (!ok) break;
1378
30.9k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Text;
1379
30.9k
    instr.m_content=text;
1380
30.9k
    break;
1381
34.5k
  }
1382
771k
  case 0x16: {
1383
771k
    if (pos+1+2>endPos) {
1384
1.93k
      ok=false;
1385
1.93k
      break;
1386
1.93k
    }
1387
769k
    isFunction=true;
1388
769k
    auto val=static_cast<int>(input->readULong(1));
1389
769k
    arity=static_cast<int>(input->readULong(1));
1390
769k
    std::string name("");
1391
769k
    if (val<0x70) {
1392
764k
      static char const* const wh[] = {
1393
764k
        "Abs", "Acos", "Alert", "And", "Code", "Asin", "Atan", "Atan2",
1394
764k
        "Average", "Choose", "Char", "Concatenate", "Cos", "Count", "Date", "DateToText",
1395
1396
764k
        "DateValue", "Day", "DayName", "DayOfYear", "Degrees", "NA"/* error*/, "Exact", "Exp",
1397
764k
        "Frac", "FV", "HLookup", "Hour", "If", "Index", "Int", "IRR",
1398
1399
764k
        "IsBlank", "IsError", "IsNA", "IsNumber", "IsText", "Left", "Ln", "Log",
1400
764k
        "Log10", "LookUp", "Lower", "Match", "Max", "Mid", "Min", "Minute",
1401
1402
764k
        "MIRR", "Mod", "MonthName", "NA", "Not", "Now", "NPER", "NPV",
1403
764k
        "N" /*NumToText*/, "Or", "Pi", "PMT", "Product", "Proper", "PV", "Radians",
1404
1405
764k
        "Rand", "Rate", "Replace", "Right", "Round", "Second", "Sign", "Sqrt",
1406
764k
        "StDev", "Sum", "Tan", "Rept", "Value"/*TextToNum*/, "Time", "TimeToText", "TimeValue",
1407
1408
764k
        "", "Trim", "Type", "Upper", "Var", "VLookUp", "WeekDay", "WeekOfYear",
1409
764k
        "Year", "Find", "Column", "Row", "Fact", "Len", "Sin", "Month",
1410
1411
764k
        "Trunc", "Count2", "Macro", "Beep", "", "", "", "",
1412
764k
        "", "", "", "", "", "", "", "",
1413
764k
      };
1414
764k
      name=wh[val];
1415
764k
    }
1416
769k
    if (name.empty()) {
1417
5.80k
      f << "###";
1418
5.80k
      MWAW_DEBUG_MSG(("ClarisWksDbaseContent::readFormula: find unknown function\n"));
1419
5.80k
      std::stringstream s;
1420
5.80k
      s << "Funct" << std::hex << val << std::dec;
1421
5.80k
      name=s.str();
1422
5.80k
    }
1423
769k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Function;
1424
769k
    instr.m_content=name;
1425
769k
    formula.push_back(instr);
1426
769k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
1427
769k
    instr.m_content="(";
1428
769k
    break;
1429
771k
  }
1430
24.2k
  case 0x18: // bool
1431
24.2k
    if (pos+1+1>endPos) {
1432
1.45k
      ok=false;
1433
1.45k
      break;
1434
1.45k
    }
1435
22.8k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Long;
1436
22.8k
    instr.m_longValue=static_cast<int>(input->readLong(1));
1437
22.8k
    break;
1438
28.0k
  case 0x19: // database, cell
1439
28.0k
    if (pos+1+1>endPos) {
1440
2.98k
      ok = false;
1441
2.98k
      break;
1442
2.98k
    }
1443
25.0k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Cell;
1444
25.0k
    instr.m_position[0]=MWAWVec2i(int(input->readULong(1)),0);
1445
25.0k
    instr.m_positionRelative[0]=MWAWVec2b(true, false);
1446
25.0k
    break;
1447
515k
  case 0x1f: // final equal sign
1448
515k
    return true;
1449
5.06M
  default: {
1450
5.06M
    std::string op("");
1451
5.06M
    if (type<0x10) {
1452
4.82M
      op=ClarisWksDbaseContentInternal::s_listOperators[type].m_name;
1453
4.82M
      arity=ClarisWksDbaseContentInternal::s_listOperators[type].m_arity;
1454
4.82M
    }
1455
5.06M
    if (!op.empty()&&arity>0) {
1456
4.82M
      instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
1457
4.82M
      instr.m_content=op;
1458
4.82M
      isOperator=true;
1459
4.82M
      break;
1460
4.82M
    }
1461
240k
    f << "##type=" << std::hex << type << std::dec << ",";
1462
240k
    ok=false;
1463
240k
    break;
1464
5.06M
  }
1465
6.60M
  }
1466
6.08M
  error+=f.str();
1467
6.08M
  if (!ok) {
1468
281k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1469
281k
    return false;
1470
281k
  }
1471
5.80M
  if (isOperator && instr.m_content=="%") {
1472
    // special case, percentage %2 => 2%
1473
78.5k
    if (!readFormula(cPos, endPos, formula, error))
1474
73.5k
      return false;
1475
5.03k
    formula.push_back(instr);
1476
5.03k
    arity=0;
1477
5.03k
  }
1478
5.73M
  else if (!isOperator || arity==1)
1479
1.01M
    formula.push_back(instr);
1480
5.73M
  if (isFunction && arity>1) {
1481
743k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
1482
743k
    instr.m_content=";";
1483
743k
  }
1484
6.43M
  for (int i=0; i < arity; ++i) {
1485
6.19M
    if (!readFormula(cPos, endPos, formula, error))
1486
5.31M
      return false;
1487
882k
    if (i+1==arity) break;
1488
703k
    formula.push_back(instr);
1489
703k
  }
1490
417k
  if (isFunction || instr.m_content=="(") {
1491
48.8k
    instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
1492
48.8k
    instr.m_content=")";
1493
48.8k
    formula.push_back(instr);
1494
48.8k
  }
1495
1496
417k
  return true;
1497
5.73M
}
1498
1499
////////////////////////////////////////////////////////////
1500
//
1501
////////////////////////////////////////////////////////////
1502
void ClarisWksDbaseContent::Record::updateFormulaCells(MWAWVec2i const &removeDelta)
1503
312k
{
1504
312k
  if (m_content.m_contentType!=MWAWCellContent::C_FORMULA)
1505
296k
    return;
1506
15.9k
  for (auto &instr : m_content.m_formula) {
1507
15.6k
    int numCell=instr.m_type==MWAWCellContent::FormulaInstruction::F_Cell ? 1 :
1508
15.6k
                instr.m_type==MWAWCellContent::FormulaInstruction::F_CellList ? 2 : 0;
1509
22.8k
    for (int c=0; c<numCell; ++c) {
1510
9.33k
      instr.m_position[c]-=removeDelta;
1511
9.33k
      if (instr.m_position[c][0]<0 || instr.m_position[c][1]<0) {
1512
2.12k
        static bool first=true;
1513
2.12k
        if (first) {
1514
8
          MWAW_DEBUG_MSG(("ClarisWksDbaseContent::Record::updateFormulaCells: some cell's positions are bad, remove formula\n"));
1515
8
          first=false;
1516
8
        }
1517
        // revert to the basic cell type
1518
2.12k
        m_content.m_contentType=m_valueType;
1519
2.12k
        return;
1520
2.12k
      }
1521
9.33k
    }
1522
15.6k
  }
1523
15.9k
}
1524
1525
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: