Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MWAWCell.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
/** \file MWAWCell.cxx
35
 * Implements MWAWCell (cell content and format)
36
 */
37
#include <time.h>
38
39
#include <cmath>
40
#include <iomanip>
41
#include <iostream>
42
#include <sstream>
43
44
#include <librevenge/librevenge.h>
45
46
#include "MWAWFontConverter.hxx"
47
#include "MWAWListener.hxx"
48
49
#include "MWAWCell.hxx"
50
51
////////////////////////////////////////////////////////////
52
// MWAWCell::Format
53
////////////////////////////////////////////////////////////
54
MWAWCell::Format::~Format()
55
439M
{
56
439M
}
57
58
std::string MWAWCell::Format::getValueType() const
59
4.78M
{
60
4.78M
  switch (m_format) {
61
4.39M
  case F_NUMBER:
62
4.39M
    if (m_numberFormat==F_NUMBER_CURRENCY) return "currency";
63
3.91M
    if (m_numberFormat==F_NUMBER_PERCENT) return "percent";
64
3.70M
    if (m_numberFormat==F_NUMBER_SCIENTIFIC) return "scientific";
65
3.31M
    return "float";
66
0
  case F_BOOLEAN:
67
0
    return "boolean";
68
0
  case F_DATE:
69
0
    return "date";
70
0
  case F_TIME:
71
0
    return "time";
72
6.22k
  case F_TEXT:
73
390k
  case F_UNKNOWN:
74
#if !defined(__clang__)
75
  default:
76
#endif
77
390k
    break;
78
4.78M
  }
79
390k
  return "float";
80
4.78M
}
81
82
bool MWAWCell::Format::getNumberingProperties(librevenge::RVNGPropertyList &propList) const
83
1.28M
{
84
1.28M
  librevenge::RVNGPropertyListVector pVect;
85
1.28M
  switch (m_format) {
86
23.4k
  case F_BOOLEAN:
87
23.4k
    propList.insert("librevenge:value-type", "boolean");
88
23.4k
    break;
89
729k
  case F_NUMBER:
90
729k
    if (m_digits>-1000)
91
635k
      propList.insert("number:decimal-places", m_digits);
92
729k
    if (m_thousandHasSeparator)
93
9.84k
      propList.insert("number:grouping", true);
94
729k
    switch (m_numberFormat) {
95
274k
    case F_NUMBER_GENERIC:
96
274k
      propList.insert("librevenge:value-type", "number");
97
274k
      propList.remove("number:decimal-places");
98
274k
      break;
99
88.8k
    case F_NUMBER_SCIENTIFIC:
100
88.8k
      propList.insert("librevenge:value-type", "scientific");
101
88.8k
      break;
102
91.5k
    case F_NUMBER_PERCENT:
103
91.5k
      propList.insert("librevenge:value-type", "percentage");
104
91.5k
      break;
105
99.3k
    case F_NUMBER_DECIMAL:
106
99.3k
      propList.insert("librevenge:value-type", "number");
107
99.3k
      if (m_integerDigits>=0) {
108
0
        propList.insert("number:min-integer-digits", m_integerDigits+1);
109
0
        propList.insert("number:decimal-places", 0);
110
0
      }
111
99.3k
      break;
112
306
    case F_NUMBER_FRACTION:
113
306
      propList.insert("librevenge:value-type", "fraction");
114
306
      propList.insert("number:min-integer-digits", 0);
115
306
      propList.insert("number:min-numerator-digits", m_numeratorDigits>0 ? m_numeratorDigits : 1);
116
306
      propList.insert("number:min-denominator-digits", m_denominatorDigits>0 ? m_denominatorDigits : 1);
117
306
      propList.remove("number:decimal-places");
118
306
      break;
119
87.1k
    case F_NUMBER_CURRENCY: {
120
87.1k
      propList.clear();
121
87.1k
      propList.insert("librevenge:value-type", "currency");
122
87.1k
      librevenge::RVNGPropertyList list;
123
87.1k
      list.insert("librevenge:value-type", "currency-symbol");
124
87.1k
      list.insert("number:language","en");
125
87.1k
      list.insert("number:country","US");
126
87.1k
      list.insert("librevenge:currency",m_currencySymbol.c_str());
127
87.1k
      pVect.append(list);
128
129
87.1k
      list.clear();
130
87.1k
      list.insert("librevenge:value-type", "number");
131
87.1k
      if (m_digits>-1000)
132
86.4k
        list.insert("number:decimal-places", m_digits);
133
87.1k
      pVect.append(list);
134
87.1k
      break;
135
0
    }
136
88.2k
    case F_NUMBER_UNKNOWN:
137
#if !defined(__clang__)
138
    default:
139
#endif
140
88.2k
      return false;
141
729k
    }
142
641k
    break;
143
641k
  case F_DATE:
144
270k
    propList.insert("librevenge:value-type", "date");
145
270k
    propList.insert("number:automatic-order", "true");
146
270k
    if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%m/%d/%Y" : m_DTFormat, pVect))
147
0
      return false;
148
270k
    break;
149
270k
  case F_TIME:
150
263k
    propList.insert("librevenge:value-type", "time");
151
263k
    propList.insert("number:automatic-order", "true");
152
263k
    if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%H:%M:%S" : m_DTFormat, pVect))
153
0
      return false;
154
263k
    break;
155
263k
  case F_TEXT:
156
0
  case F_UNKNOWN:
157
#if !defined(__clang__)
158
  default:
159
#endif
160
0
    return false;
161
1.28M
  }
162
1.19M
  if (pVect.count())
163
620k
    propList.insert("librevenge:format", pVect);
164
1.19M
  return true;
165
1.28M
}
166
167
std::ostream &operator<<(std::ostream &o, MWAWCell::Format const &format)
168
0
{
169
0
  switch (format.m_format) {
170
0
  case MWAWCell::F_BOOLEAN:
171
0
    o << "boolean";
172
0
    break;
173
0
  case MWAWCell::F_TEXT:
174
0
    o << "text";
175
0
    break;
176
0
  case MWAWCell::F_NUMBER:
177
0
    o << "number";
178
0
    switch (format.m_numberFormat) {
179
0
    case MWAWCell::F_NUMBER_GENERIC:
180
0
      break;
181
0
    case MWAWCell::F_NUMBER_DECIMAL:
182
0
      o << "[decimal]";
183
0
      break;
184
0
    case MWAWCell::F_NUMBER_SCIENTIFIC:
185
0
      o << "[exp]";
186
0
      break;
187
0
    case MWAWCell::F_NUMBER_PERCENT:
188
0
      o << "[percent]";
189
0
      break;
190
0
    case MWAWCell::F_NUMBER_CURRENCY:
191
0
      o << "[money=" << format.m_currencySymbol << "]";
192
0
      break;
193
0
    case MWAWCell::F_NUMBER_FRACTION:
194
0
      o << "[fraction]";
195
0
      break;
196
0
    case MWAWCell::F_NUMBER_UNKNOWN:
197
#if !defined(__clang__)
198
    default:
199
#endif
200
0
      MWAW_DEBUG_MSG(("MWAWCell::operator<<(Format): find unexpected type\n"));
201
0
      o << "###format,";
202
0
      break;
203
0
    }
204
0
    if (format.m_thousandHasSeparator)
205
0
      o << "[thousandSep]";
206
0
    if (format.m_parenthesesForNegative)
207
0
      o << "[parenthesis<0]";
208
0
    break;
209
0
  case MWAWCell::F_DATE:
210
0
    o << "date[" << format.m_DTFormat << "]";
211
0
    break;
212
0
  case MWAWCell::F_TIME:
213
0
    o << "time[" << format.m_DTFormat << "]";
214
0
    break;
215
0
  case MWAWCell::F_UNKNOWN:
216
#if !defined(__clang__)
217
  default:
218
#endif
219
0
    break; // default
220
0
  }
221
0
  o << ",";
222
223
0
  if (format.m_digits > -1000) o << "digits=" << format.m_digits << ",";
224
0
  if (format.m_integerDigits != -1) o << "digits[min]=" << format.m_integerDigits << ",";
225
0
  if (format.m_numeratorDigits != -1) o << "digits[num]=" << format.m_numeratorDigits << ",";
226
0
  if (format.m_denominatorDigits != -1) o << "digits[den]=" << format.m_denominatorDigits << ",";
227
0
  return o;
228
0
}
229
230
int MWAWCell::Format::compare(MWAWCell::Format const &cell) const
231
82.4M
{
232
82.4M
  if (m_format<cell.m_format) return 1;
233
76.5M
  if (m_format>cell.m_format) return -1;
234
65.7M
  if (m_numberFormat<cell.m_numberFormat) return 1;
235
60.3M
  if (m_numberFormat>cell.m_numberFormat) return -1;
236
47.0M
  if (m_digits<cell.m_digits) return 1;
237
43.3M
  if (m_digits>cell.m_digits) return -1;
238
36.6M
  if (m_integerDigits<cell.m_integerDigits) return 1;
239
36.6M
  if (m_integerDigits>cell.m_integerDigits) return -1;
240
36.6M
  if (m_numeratorDigits<cell.m_numeratorDigits) return 1;
241
36.6M
  if (m_numeratorDigits>cell.m_numeratorDigits) return -1;
242
36.6M
  if (m_denominatorDigits<cell.m_denominatorDigits) return 1;
243
36.6M
  if (m_denominatorDigits>cell.m_denominatorDigits) return -1;
244
36.6M
  if (m_thousandHasSeparator!=cell.m_thousandHasSeparator) return m_thousandHasSeparator ? -1:1;
245
36.5M
  if (m_parenthesesForNegative!=cell.m_parenthesesForNegative) return m_parenthesesForNegative ? -1:1;
246
36.5M
  if (m_DTFormat<cell.m_DTFormat) return 1;
247
36.2M
  if (m_DTFormat>cell.m_DTFormat) return -1;
248
35.6M
  if (m_currencySymbol<cell.m_currencySymbol) return 1;
249
35.6M
  if (m_currencySymbol>cell.m_currencySymbol) return -1;
250
35.6M
  return 0;
251
35.6M
}
252
////////////////////////////////////////////////////////////
253
// MWAWCell
254
////////////////////////////////////////////////////////////
255
void MWAWCell::addTo(librevenge::RVNGPropertyList &propList, std::shared_ptr<MWAWFontConverter> fontConverter) const
256
19.2M
{
257
19.2M
  propList.insert("librevenge:column", position()[0]);
258
19.2M
  propList.insert("librevenge:row", position()[1]);
259
260
19.2M
  propList.insert("table:number-columns-spanned", numSpannedCells()[0]);
261
19.2M
  propList.insert("table:number-rows-spanned", numSpannedCells()[1]);
262
263
19.2M
  if (m_fontSet)
264
11.6M
    m_font.addTo(propList, fontConverter);
265
25.8M
  for (size_t c = 0; c < m_bordersList.size(); c++) {
266
6.62M
    switch (c) {
267
1.65M
    case libmwaw::Left:
268
1.65M
      m_bordersList[c].addTo(propList, "left");
269
1.65M
      break;
270
1.65M
    case libmwaw::Right:
271
1.65M
      m_bordersList[c].addTo(propList, "right");
272
1.65M
      break;
273
1.65M
    case libmwaw::Top:
274
1.65M
      m_bordersList[c].addTo(propList, "top");
275
1.65M
      break;
276
1.65M
    case libmwaw::Bottom:
277
1.65M
      m_bordersList[c].addTo(propList, "bottom");
278
1.65M
      break;
279
0
    default:
280
0
      MWAW_DEBUG_MSG(("MWAWCell::addTo: can not send %d border\n",int(c)));
281
0
      break;
282
6.62M
    }
283
6.62M
  }
284
19.2M
  if (!backgroundColor().isWhite())
285
119k
    propList.insert("fo:background-color", backgroundColor().str().c_str());
286
19.2M
  if (isProtected())
287
212k
    propList.insert("style:cell-protect","protected");
288
  // alignment
289
19.2M
  switch (hAlignment()) {
290
1.01M
  case HALIGN_LEFT:
291
1.01M
    propList.insert("fo:text-align", "first");
292
1.01M
    propList.insert("style:text-align-source", "fix");
293
1.01M
    break;
294
417k
  case HALIGN_CENTER:
295
417k
    propList.insert("fo:text-align", "center");
296
417k
    propList.insert("style:text-align-source", "fix");
297
417k
    break;
298
645k
  case HALIGN_RIGHT:
299
645k
    propList.insert("fo:text-align", "end");
300
645k
    propList.insert("style:text-align-source", "fix");
301
645k
    break;
302
17.1M
  case HALIGN_DEFAULT:
303
17.1M
    break; // default
304
0
  case HALIGN_FULL:
305
#if !defined(__clang__)
306
  default:
307
#endif
308
0
    MWAW_DEBUG_MSG(("MWAWCell::addTo: called with unknown halign=%d\n", hAlignment()));
309
19.2M
  }
310
  // no padding
311
19.2M
  propList.insert("fo:padding", 0, librevenge::RVNG_POINT);
312
  // alignment
313
19.2M
  switch (vAlignment()) {
314
0
  case VALIGN_TOP:
315
0
    propList.insert("style:vertical-align", "top");
316
0
    break;
317
251k
  case VALIGN_CENTER:
318
251k
    propList.insert("style:vertical-align", "middle");
319
251k
    break;
320
5.32M
  case VALIGN_BOTTOM:
321
5.32M
    propList.insert("style:vertical-align", "bottom");
322
5.32M
    break;
323
13.6M
  case VALIGN_DEFAULT:
324
13.6M
    break; // default
325
#if !defined(__clang__)
326
  default:
327
#endif
328
0
    MWAW_DEBUG_MSG(("MWAWCell::addTo: called with unknown valign=%d\n", vAlignment()));
329
19.2M
  }
330
19.2M
  int rot=int(m_rotation); // int seems better than double
331
19.2M
  if (rot)
332
2.72k
    propList.insert("style:rotation-angle", rot);
333
19.2M
}
334
335
std::string MWAWCell::getColumnName(int col)
336
0
{
337
0
  std::stringstream f;
338
0
  f << "[.";
339
0
  if (col > 26) f << char('A'+col/26);
340
0
  f << char('A'+(col%26));
341
0
  f << "]";
342
0
  return f.str();
343
0
}
344
345
std::string MWAWCell::getBasicCellName(MWAWVec2i const &pos)
346
2.11k
{
347
2.11k
  std::stringstream f;
348
2.11k
  int col = pos[0];
349
2.11k
  if (col > 26*26) {
350
0
    f << char('A'+col/(26*26));
351
0
    col *= 26*26;
352
0
  }
353
2.11k
  if (col > 26) {
354
0
    f << char('A'+col/26);
355
0
    col %= 26;
356
0
  }
357
2.11k
  f << char('A'+col);
358
2.11k
  f << pos[1]+1;
359
2.11k
  return f.str();
360
2.11k
}
361
362
std::string MWAWCell::getCellName(MWAWVec2i const &pos, MWAWVec2b const &absolute)
363
0
{
364
0
  std::stringstream f;
365
0
  f << "[.";
366
0
  if (absolute[1]) f << "$";
367
0
  int col = pos[0];
368
0
  if (col > 26*26) {
369
0
    f << char('A'+col/(26*26));
370
0
    col *= 26*26;
371
0
  }
372
0
  if (col > 26) {
373
0
    f << char('A'+col/26);
374
0
    col %= 26;
375
0
  }
376
0
  f << char('A'+col);
377
0
  if (absolute[0]) f << "$";
378
0
  f << pos[1]+1 << ']';
379
0
  return f.str();
380
0
}
381
382
void MWAWCell::setBorders(int wh, MWAWBorder const &border)
383
4.91M
{
384
4.91M
  int const allBits = libmwaw::LeftBit|libmwaw::RightBit|libmwaw::TopBit|libmwaw::BottomBit|libmwaw::HMiddleBit|libmwaw::VMiddleBit;
385
4.91M
  if (wh & (~allBits)) {
386
0
    MWAW_DEBUG_MSG(("MWAWCell::setBorders: unknown borders\n"));
387
0
    return;
388
0
  }
389
4.91M
  size_t numData = 4;
390
4.91M
  if (wh & (libmwaw::HMiddleBit|libmwaw::VMiddleBit))
391
0
    numData=6;
392
4.91M
  if (m_bordersList.size() < numData) {
393
4.24M
    MWAWBorder emptyBorder;
394
4.24M
    emptyBorder.m_style = MWAWBorder::None;
395
4.24M
    m_bordersList.resize(numData, emptyBorder);
396
4.24M
  }
397
4.91M
  if (wh & libmwaw::LeftBit) m_bordersList[libmwaw::Left] = border;
398
4.91M
  if (wh & libmwaw::RightBit) m_bordersList[libmwaw::Right] = border;
399
4.91M
  if (wh & libmwaw::TopBit) m_bordersList[libmwaw::Top] = border;
400
4.91M
  if (wh & libmwaw::BottomBit) m_bordersList[libmwaw::Bottom] = border;
401
4.91M
  if (wh & libmwaw::HMiddleBit) m_bordersList[libmwaw::HMiddle] = border;
402
4.91M
  if (wh & libmwaw::VMiddleBit) m_bordersList[libmwaw::VMiddle] = border;
403
4.91M
}
404
405
std::ostream &operator<<(std::ostream &o, MWAWCell const &cell)
406
0
{
407
0
  o << MWAWCell::getCellName(cell.m_position, MWAWVec2b(false,false)) << ":";
408
0
  if (cell.numSpannedCells()[0] != 1 || cell.numSpannedCells()[1] != 1)
409
0
    o << "span=[" << cell.numSpannedCells()[0] << "," << cell.numSpannedCells()[1] << "],";
410
411
0
  if (cell.m_protected) o << "protected,";
412
0
  if (cell.m_bdBox.size()[0]>0 || cell.m_bdBox.size()[1]>0)
413
0
    o << "bdBox=" << cell.m_bdBox << ",";
414
0
  if (cell.m_bdSize[0]>0 || cell.m_bdSize[1]>0)
415
0
    o << "bdSize=" << cell.m_bdSize << ",";
416
0
  o << cell.m_format;
417
0
  if (cell.m_fontSet) o << "hasFont,";
418
0
  switch (cell.m_hAlign) {
419
0
  case MWAWCell::HALIGN_LEFT:
420
0
    o << "left,";
421
0
    break;
422
0
  case MWAWCell::HALIGN_CENTER:
423
0
    o << "centered,";
424
0
    break;
425
0
  case MWAWCell::HALIGN_RIGHT:
426
0
    o << "right,";
427
0
    break;
428
0
  case MWAWCell::HALIGN_FULL:
429
0
    o << "full,";
430
0
    break;
431
0
  case MWAWCell::HALIGN_DEFAULT:
432
#if !defined(__clang__)
433
  default:
434
#endif
435
0
    break; // default
436
0
  }
437
0
  switch (cell.m_vAlign) {
438
0
  case MWAWCell::VALIGN_TOP:
439
0
    o << "top,";
440
0
    break;
441
0
  case MWAWCell::VALIGN_CENTER:
442
0
    o << "centered[y],";
443
0
    break;
444
0
  case MWAWCell::VALIGN_BOTTOM:
445
0
    o << "bottom,";
446
0
    break;
447
0
  case MWAWCell::VALIGN_DEFAULT:
448
#if !defined(__clang__)
449
  default:
450
#endif
451
0
    break; // default
452
0
  }
453
454
0
  if (!cell.m_backgroundColor.isWhite())
455
0
    o << "backColor=" << cell.m_backgroundColor << ",";
456
0
  for (size_t i = 0; i < cell.m_bordersList.size(); i++) {
457
0
    if (cell.m_bordersList[i].m_style == MWAWBorder::None)
458
0
      continue;
459
0
    o << "bord";
460
0
    if (i < 6) {
461
0
      static char const* const wh[] = { "L", "R", "T", "B", "MiddleH", "MiddleV" };
462
0
      o << wh[i];
463
0
    }
464
0
    else o << "[#wh=" << i << "]";
465
0
    o << "=" << cell.m_bordersList[i] << ",";
466
0
  }
467
0
  switch (cell.m_extraLine) {
468
0
  case MWAWCell::E_None:
469
0
    break;
470
0
  case MWAWCell::E_Line1:
471
0
    o << "line[TL->RB],";
472
0
    break;
473
0
  case MWAWCell::E_Line2:
474
0
    o << "line[BL->RT],";
475
0
    break;
476
0
  case MWAWCell::E_Cross:
477
0
    o << "line[cross],";
478
0
    break;
479
#if !defined(__clang__)
480
  default:
481
    break;
482
#endif
483
0
  }
484
0
  if (cell.m_rotation<0 || cell.m_rotation>0)
485
0
    o << "rot=" << cell.m_rotation << ",";
486
0
  if (cell.m_extraLine!=MWAWCell::E_None)
487
0
    o << cell.m_extraLineType << ",";
488
0
  return o;
489
0
}
490
491
// send data to listener
492
bool MWAWCell::send(MWAWListenerPtr listener, MWAWTable &table)
493
729k
{
494
729k
  if (!listener) return true;
495
729k
  listener->openTableCell(*this);
496
729k
  bool ok=sendContent(listener, table);
497
729k
  listener->closeTableCell();
498
729k
  return ok;
499
729k
}
500
501
bool MWAWCell::sendContent(MWAWListenerPtr, MWAWTable &)
502
0
{
503
0
  MWAW_DEBUG_MSG(("MWAWCell::sendContent: must not be called!!!\n"));
504
0
  return false;
505
0
}
506
507
////////////////////////////////////////////////////////////
508
// MWAWCellContent
509
////////////////////////////////////////////////////////////
510
bool MWAWCellContent::double2Date(double val, int &Y, int &M, int &D)
511
761k
{
512
  /* first convert the date in long*/
513
761k
  auto numDaysSinceOrigin=long(val+0.4);
514
  // checkme: do we need to check before for isNan(val) ?
515
761k
  if (numDaysSinceOrigin<-10000*365 || numDaysSinceOrigin>10000*365) {
516
    /* normally, we can expect documents to contain date between 1904
517
       and 2004. So even if such a date can make sense, storing it as
518
       a number of days is clearly abnormal */
519
194k
    MWAW_DEBUG_MSG(("MWAWCellContent::double2Date: using a double to represent the date %ld seems odd\n", numDaysSinceOrigin));
520
194k
    Y=1904;
521
194k
    M=D=1;
522
194k
    return false;
523
194k
  }
524
  // find the century
525
567k
  int century=19;
526
932k
  while (numDaysSinceOrigin>=36500+24) {
527
365k
    long numDaysInCentury=36500+24+((century%4)?0:1);
528
365k
    if (numDaysSinceOrigin<numDaysInCentury) break;
529
365k
    numDaysSinceOrigin-=numDaysInCentury;
530
365k
    ++century;
531
365k
  }
532
666k
  while (numDaysSinceOrigin<0) {
533
99.3k
    --century;
534
99.3k
    numDaysSinceOrigin+=36500+24+((century%4)?0:1);
535
99.3k
  }
536
  // now compute the year
537
567k
  Y=int(numDaysSinceOrigin/365);
538
567k
  long numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0);
539
567k
  if (numDaysToEndY1>numDaysSinceOrigin) {
540
14.7k
    --Y;
541
14.7k
    numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0);
542
14.7k
  }
543
  // finish to compute the date
544
567k
  auto numDaysFrom1Jan=int(numDaysSinceOrigin-numDaysToEndY1);
545
567k
  Y+=century*100;
546
567k
  bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0);
547
548
2.38M
  for (M=0; M<12; ++M) {
549
2.38M
    static const int days[2][12] = {
550
2.38M
      { 0,31,59,90,120,151,181,212,243,273,304,334},
551
2.38M
      { 0,31,60,91,121,152,182,213,244,274,305,335}
552
2.38M
    };
553
2.38M
    if (M<11 && days[isLeap ? 1 : 0][M+1]<=numDaysFrom1Jan) continue;
554
567k
    D=(numDaysFrom1Jan-days[isLeap ? 1 : 0][M++])+1;
555
567k
    break;
556
2.38M
  }
557
567k
  return true;
558
761k
}
559
560
bool MWAWCellContent::date2Double(int Y, int M, int D, double &val)
561
9.14k
{
562
9.14k
  --M;
563
9.14k
  --D;
564
9.14k
  if (M>11) {
565
2.81k
    Y += M/12;
566
2.81k
    M %= 12;
567
2.81k
  }
568
6.33k
  else if (M<0) {
569
1.99k
    int yDiff = (-M + 11)/12;
570
1.99k
    Y -= yDiff;
571
1.99k
    M+=12*yDiff;
572
1.99k
  }
573
  // sanity check
574
9.14k
  if (M<0||M>11) {
575
0
    MWAW_DEBUG_MSG(("MWAWCellContent::date2Double: something is bad\n"));
576
0
    return false;
577
0
  }
578
9.14k
  bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0);
579
9.14k
  int32_t const daysFrom0=365*Y+(Y/400)-(Y/100)+(Y/4);
580
9.14k
  int32_t const daysFrom1900=365*1900+(1900/400)-(1900/100)+(1900/4);
581
9.14k
  static const int32_t days[2][12] = {
582
9.14k
    { 0,31,59,90,120,151,181,212,243,273,304,334},
583
9.14k
    { 0,31,60,91,121,152,182,213,244,274,305,335}
584
9.14k
  };
585
9.14k
  int32_t daysFrom1Jan=days[isLeap ? 1 : 0][M] + D;
586
9.14k
  val=double(daysFrom0-daysFrom1900+daysFrom1Jan);
587
9.14k
  return true;
588
9.14k
}
589
590
bool MWAWCellContent::double2Time(double val, int &H, int &M, int &S)
591
510k
{
592
510k
  if (val < 0.0 || val > 1.0) return false;
593
508k
  double time = 24.*3600.*val+0.5;
594
508k
  H=int(time/3600.);
595
508k
  time -= H*3600.;
596
508k
  M=int(time/60.);
597
508k
  time -= M*60.;
598
508k
  S=int(time);
599
508k
  return true;
600
510k
}
601
602
bool MWAWCellContent::double2String(double val, MWAWCell::Format const &format, std::string &str)
603
0
{
604
0
  std::stringstream s;
605
0
  switch (format.m_format) {
606
0
  case MWAWCell::F_BOOLEAN:
607
0
    if (val<0 || val >0) s << "true";
608
0
    else s << "false";
609
0
    break;
610
0
  case MWAWCell::F_NUMBER:
611
0
    if (format.m_digits>-1000 && format.m_numberFormat!=MWAWCell::F_NUMBER_GENERIC)
612
0
      s << std::setprecision(format.m_digits);
613
0
    switch (format.m_numberFormat) {
614
0
    case MWAWCell::F_NUMBER_CURRENCY:
615
0
      s << std::fixed << val << "$";
616
0
      break;
617
0
    case MWAWCell::F_NUMBER_DECIMAL:
618
0
      s << val;
619
0
      break;
620
0
    case MWAWCell::F_NUMBER_SCIENTIFIC:
621
0
      s << std::scientific << val;
622
0
      break;
623
0
    case MWAWCell::F_NUMBER_PERCENT:
624
0
      s << std::fixed << 100*val << "%";
625
0
      break;
626
0
    case MWAWCell::F_NUMBER_FRACTION:
627
0
    case MWAWCell::F_NUMBER_GENERIC:
628
0
    case MWAWCell::F_NUMBER_UNKNOWN:
629
#if !defined(__clang__)
630
    default:
631
#endif
632
0
      s << val;
633
0
      break;
634
0
    }
635
0
    break;
636
0
  case MWAWCell::F_DATE: {
637
0
    int Y, M, D;
638
0
    if (!double2Date(val, Y, M, D)) return false;
639
0
    struct tm time;
640
0
    time.tm_sec=time.tm_min=time.tm_hour=0;
641
0
    time.tm_mday=D;
642
0
    time.tm_mon=M;
643
0
    time.tm_year=Y;
644
0
    time.tm_wday=time.tm_yday=time.tm_isdst=-1;
645
0
#if HAVE_STRUCT_TM_TM_ZONE
646
0
    time.tm_zone=nullptr;
647
0
#endif
648
0
    char buf[256];
649
0
#pragma GCC diagnostic ignored "-Wformat-y2k"
650
0
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
651
0
    if (mktime(&time)==-1 ||
652
0
        !strftime(buf, 256, format.m_DTFormat.empty() ? "%m/%d/%y" : format.m_DTFormat.c_str(), &time))
653
0
      return false;
654
0
    s << buf;
655
0
    break;
656
0
  }
657
0
  case MWAWCell::F_TIME: {
658
0
    if (val<0 || val>=1)
659
0
      val=std::fmod(val,1.);
660
0
    int H, M, S;
661
0
    if (!double2Time(val, H, M, S)) return false;
662
0
    struct tm time;
663
0
    time.tm_sec=S;
664
0
    time.tm_min=M;
665
0
    time.tm_hour=H;
666
0
    time.tm_mday=time.tm_mon=1;
667
0
    time.tm_year=100;
668
0
    time.tm_wday=time.tm_yday=time.tm_isdst=-1;
669
0
#if HAVE_STRUCT_TM_TM_ZONE
670
0
    time.tm_zone=nullptr;
671
0
#endif
672
0
    char buf[256];
673
0
    if (mktime(&time)==-1 ||
674
0
        !strftime(buf, 256, format.m_DTFormat.empty() ? "%H:%M:%S" : format.m_DTFormat.c_str(), &time))
675
0
      return false;
676
0
    s << buf;
677
0
    break;
678
0
  }
679
0
  case MWAWCell::F_TEXT:
680
0
  case MWAWCell::F_UNKNOWN:
681
#if !defined(__clang__)
682
  default:
683
#endif
684
0
    MWAW_DEBUG_MSG(("MWAWCellContent::double2String: called with bad format\n"));
685
0
    return false;
686
0
  }
687
0
  str=s.str();
688
0
  return true;
689
0
}
690
691
std::ostream &operator<<(std::ostream &o, MWAWCellContent const &content)
692
0
{
693
0
  switch (content.m_contentType) {
694
0
  case MWAWCellContent::C_NONE:
695
0
    break;
696
0
  case MWAWCellContent::C_TEXT:
697
0
    o << ",text=\"" << content.m_textEntry << "\"";
698
0
    break;
699
0
  case MWAWCellContent::C_NUMBER: {
700
0
    o << ",val=";
701
0
    bool textAndVal = false;
702
0
    if (content.hasText()) {
703
0
      o << "entry=" << content.m_textEntry;
704
0
      textAndVal = content.isValueSet();
705
0
    }
706
0
    if (textAndVal) o << "[";
707
0
    if (content.isValueSet()) o << content.m_value;
708
0
    if (textAndVal) o << "]";
709
0
  }
710
0
  break;
711
0
  case MWAWCellContent::C_FORMULA:
712
0
    o << ",formula=";
713
0
    for (auto const &form : content.m_formula)
714
0
      o << form;
715
0
    if (content.isValueSet()) o << "[" << content.m_value << "]";
716
0
    break;
717
0
  case MWAWCellContent::C_UNKNOWN:
718
0
    break;
719
#if !defined(__clang__)
720
  default:
721
    o << "###unknown type,";
722
    break;
723
#endif
724
0
  }
725
0
  return o;
726
0
}
727
728
// ---------- WKSContentListener::FormulaInstruction ------------------
729
librevenge::RVNGPropertyList MWAWCellContent::FormulaInstruction::getPropertyList(MWAWFontConverter &fontConverter, int fontId) const
730
467k
{
731
467k
  librevenge::RVNGPropertyList pList;
732
467k
  switch (m_type) {
733
198k
  case F_Operator:
734
198k
    pList.insert("librevenge:type","librevenge-operator");
735
198k
    pList.insert("librevenge:operator",m_content.c_str());
736
198k
    break;
737
78.3k
  case F_Function:
738
78.3k
    pList.insert("librevenge:type","librevenge-function");
739
78.3k
    pList.insert("librevenge:function",m_content.c_str());
740
78.3k
    break;
741
19.4k
  case F_Text: {
742
    // we must use the font converter here to get the final string
743
19.4k
    pList.insert("librevenge:type","librevenge-text");
744
19.4k
    librevenge::RVNGString finalStr("");
745
799k
    for (auto c : m_content) {
746
799k
      int unicode=fontConverter.unicode(fontId,static_cast<unsigned char>(c));
747
799k
      if (unicode==-1) {
748
295k
        if (c < 0x20 && c!=9) {
749
280k
          MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction: Find odd char %x\n", static_cast<unsigned int>(c)));
750
280k
        }
751
15.2k
        else
752
15.2k
          finalStr.append(char(c));
753
295k
      }
754
503k
      else if (unicode != 0xfffd)
755
503k
        libmwaw::appendUnicode(static_cast<uint32_t>(unicode), finalStr);
756
799k
    }
757
19.4k
    pList.insert("librevenge:text",finalStr);
758
19.4k
    break;
759
0
  }
760
0
  case F_Unicode:
761
0
    pList.insert("librevenge:type","librevenge-text");
762
0
    if (m_content.c_str())
763
0
      pList.insert("librevenge:text",librevenge::RVNGString(m_content.c_str()));
764
0
    else
765
0
      pList.insert("librevenge:text","");
766
0
    break;
767
22.4k
  case F_Double:
768
22.4k
    pList.insert("librevenge:type","librevenge-number");
769
22.4k
    pList.insert("librevenge:number",m_doubleValue, librevenge::RVNG_GENERIC);
770
22.4k
    break;
771
47.0k
  case F_Long:
772
47.0k
    pList.insert("librevenge:type","librevenge-number");
773
47.0k
    pList.insert("librevenge:number",m_longValue, librevenge::RVNG_GENERIC);
774
47.0k
    break;
775
72.2k
  case F_Cell:
776
72.2k
    pList.insert("librevenge:type","librevenge-cell");
777
72.2k
    if (m_position[0][0]>=0) {
778
72.1k
      pList.insert("librevenge:column",m_position[0][0]);
779
72.1k
      pList.insert("librevenge:column-absolute", !m_positionRelative[0][0]);
780
72.1k
    }
781
72.2k
    if (m_position[0][1]>=0) {
782
70.2k
      pList.insert("librevenge:row",m_position[0][1]);
783
70.2k
      pList.insert("librevenge:row-absolute", !m_positionRelative[0][1]);
784
70.2k
    }
785
72.2k
    if (!m_sheet[0].empty())
786
192
      pList.insert("librevenge:sheet-name",m_sheet[0]);
787
72.2k
    if (!m_fileName.empty())
788
169
      pList.insert("librevenge:file-name",m_fileName.cstr());
789
72.2k
    break;
790
29.0k
  case F_CellList:
791
29.0k
    pList.insert("librevenge:type","librevenge-cells");
792
29.0k
    if (m_position[0][0]>=0) {
793
22.6k
      pList.insert("librevenge:start-column",m_position[0][0]);
794
22.6k
      pList.insert("librevenge:start-column-absolute", !m_positionRelative[0][0]);
795
22.6k
    }
796
29.0k
    if (m_position[0][1]>=0) {
797
28.9k
      pList.insert("librevenge:start-row",m_position[0][1]);
798
28.9k
      pList.insert("librevenge:start-row-absolute", !m_positionRelative[0][1]);
799
28.9k
    }
800
29.0k
    if (m_position[1][0]>=0) {
801
22.6k
      pList.insert("librevenge:end-column",m_position[1][0]);
802
22.6k
      pList.insert("librevenge:end-column-absolute", !m_positionRelative[1][0]);
803
22.6k
    }
804
29.0k
    if (m_position[1][1]>=0) {
805
29.0k
      pList.insert("librevenge:end-row",m_position[1][1]);
806
29.0k
      pList.insert("librevenge:end-row-absolute", !m_positionRelative[1][1]);
807
29.0k
    }
808
29.0k
    if (!m_sheet[0].empty())
809
491
      pList.insert("librevenge:sheet-name",m_sheet[0]);
810
29.0k
    if (!m_sheet[1].empty())
811
0
      pList.insert("librevenge:end-sheet-name",m_sheet[1]);
812
29.0k
    if (!m_fileName.empty())
813
306
      pList.insert("librevenge:file-name",m_fileName.cstr());
814
29.0k
    break;
815
#if !defined(__clang__)
816
  default:
817
    MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction::getPropertyList: unexpected type\n"));
818
#endif
819
467k
  }
820
467k
  return pList;
821
467k
}
822
823
std::ostream &operator<<(std::ostream &o, MWAWCellContent::FormulaInstruction const &inst)
824
2.03M
{
825
2.03M
  if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Double)
826
15.9k
    o << inst.m_doubleValue;
827
2.01M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Long)
828
31.0k
    o << inst.m_longValue;
829
1.98M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Cell) {
830
364k
    if (!inst.m_sheet[0].empty()) o << "\"" << inst.m_sheet[0].cstr() << "\"";
831
364k
    if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]";
832
364k
    if (!inst.m_positionRelative[0][0]) o << "$";
833
364k
    if (inst.m_position[0][0]<0) o << "C" << inst.m_position[0][0];
834
364k
    else {
835
364k
      if (inst.m_position[0][0]>=26) o << char(inst.m_position[0][0]/26-1 + 'A');
836
364k
      o << char(inst.m_position[0][0]%26+'A');
837
364k
    }
838
364k
    if (!inst.m_positionRelative[0][1]) o << "$";
839
364k
    if (inst.m_position[0][1]<0) o << "R" << inst.m_position[0][1];
840
364k
    else o << inst.m_position[0][1];
841
364k
  }
842
1.62M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_CellList) {
843
1.14M
    if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]";
844
3.44M
    for (int l=0; l<2; ++l) {
845
2.29M
      if (!inst.m_sheet[l].empty() && (l==0 || inst.m_sheet[0]!=inst.m_sheet[1]))
846
2.14k
        o << "\"" << inst.m_sheet[l].cstr() << "\"";
847
2.29M
      if (!inst.m_positionRelative[l][0]) o << "$";
848
2.29M
      if (inst.m_position[l][0]<0) o << "C" << inst.m_position[l][0];
849
2.29M
      else {
850
2.29M
        if (inst.m_position[l][0]>=26) o << char(inst.m_position[l][0]/26-1 + 'A');
851
2.29M
        o << char(inst.m_position[l][0]%26+'A');
852
2.29M
      }
853
2.29M
      if (!inst.m_positionRelative[l][1]) o << "$";
854
2.29M
      if (inst.m_position[l][1]<0) o << "R" << inst.m_position[l][1];
855
2.29M
      else o << inst.m_position[l][1];
856
2.29M
      if (l==0) o << ":";
857
2.29M
    }
858
1.14M
  }
859
472k
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Text ||
860
154k
           inst.m_type==MWAWCellContent::FormulaInstruction::F_Unicode)
861
317k
    o << "\"" << inst.m_content << "\"";
862
154k
  else
863
154k
    o << inst.m_content;
864
2.03M
  return o;
865
2.03M
}
866
867
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: