Coverage Report

Created: 2026-04-29 07:28

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