Coverage Report

Created: 2026-07-20 07:04

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
611M
{
56
611M
}
57
58
std::string MWAWCell::Format::getValueType() const
59
4.93M
{
60
4.93M
  switch (m_format) {
61
4.57M
  case F_NUMBER:
62
4.57M
    if (m_numberFormat==F_NUMBER_CURRENCY) return "currency";
63
4.08M
    if (m_numberFormat==F_NUMBER_PERCENT) return "percent";
64
3.85M
    if (m_numberFormat==F_NUMBER_SCIENTIFIC) return "scientific";
65
3.42M
    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
7.05k
  case F_TEXT:
73
357k
  case F_UNKNOWN:
74
#if !defined(__clang__)
75
  default:
76
#endif
77
357k
    break;
78
4.93M
  }
79
357k
  return "float";
80
4.93M
}
81
82
bool MWAWCell::Format::getNumberingProperties(librevenge::RVNGPropertyList &propList) const
83
1.37M
{
84
1.37M
  librevenge::RVNGPropertyListVector pVect;
85
1.37M
  switch (m_format) {
86
26.2k
  case F_BOOLEAN:
87
26.2k
    propList.insert("librevenge:value-type", "boolean");
88
26.2k
    break;
89
784k
  case F_NUMBER:
90
784k
    if (m_digits>-1000)
91
685k
      propList.insert("number:decimal-places", m_digits);
92
784k
    if (m_thousandHasSeparator)
93
11.4k
      propList.insert("number:grouping", true);
94
784k
    switch (m_numberFormat) {
95
291k
    case F_NUMBER_GENERIC:
96
291k
      propList.insert("librevenge:value-type", "number");
97
291k
      propList.remove("number:decimal-places");
98
291k
      break;
99
101k
    case F_NUMBER_SCIENTIFIC:
100
101k
      propList.insert("librevenge:value-type", "scientific");
101
101k
      break;
102
100k
    case F_NUMBER_PERCENT:
103
100k
      propList.insert("librevenge:value-type", "percentage");
104
100k
      break;
105
105k
    case F_NUMBER_DECIMAL:
106
105k
      propList.insert("librevenge:value-type", "number");
107
105k
      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
105k
      break;
112
313
    case F_NUMBER_FRACTION:
113
313
      propList.insert("librevenge:value-type", "fraction");
114
313
      propList.insert("number:min-integer-digits", 0);
115
313
      propList.insert("number:min-numerator-digits", m_numeratorDigits>0 ? m_numeratorDigits : 1);
116
313
      propList.insert("number:min-denominator-digits", m_denominatorDigits>0 ? m_denominatorDigits : 1);
117
313
      propList.remove("number:decimal-places");
118
313
      break;
119
92.9k
    case F_NUMBER_CURRENCY: {
120
92.9k
      propList.clear();
121
92.9k
      propList.insert("librevenge:value-type", "currency");
122
92.9k
      librevenge::RVNGPropertyList list;
123
92.9k
      list.insert("librevenge:value-type", "currency-symbol");
124
92.9k
      list.insert("number:language","en");
125
92.9k
      list.insert("number:country","US");
126
92.9k
      list.insert("librevenge:currency",m_currencySymbol.c_str());
127
92.9k
      pVect.append(list);
128
129
92.9k
      list.clear();
130
92.9k
      list.insert("librevenge:value-type", "number");
131
92.9k
      if (m_digits>-1000)
132
92.1k
        list.insert("number:decimal-places", m_digits);
133
92.9k
      pVect.append(list);
134
92.9k
      break;
135
0
    }
136
92.7k
    case F_NUMBER_UNKNOWN:
137
#if !defined(__clang__)
138
    default:
139
#endif
140
92.7k
      return false;
141
784k
    }
142
691k
    break;
143
691k
  case F_DATE:
144
285k
    propList.insert("librevenge:value-type", "date");
145
285k
    propList.insert("number:automatic-order", "true");
146
285k
    if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%m/%d/%Y" : m_DTFormat, pVect))
147
0
      return false;
148
285k
    break;
149
285k
  case F_TIME:
150
280k
    propList.insert("librevenge:value-type", "time");
151
280k
    propList.insert("number:automatic-order", "true");
152
280k
    if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%H:%M:%S" : m_DTFormat, pVect))
153
0
      return false;
154
280k
    break;
155
280k
  case F_TEXT:
156
0
  case F_UNKNOWN:
157
#if !defined(__clang__)
158
  default:
159
#endif
160
0
    return false;
161
1.37M
  }
162
1.28M
  if (pVect.count())
163
658k
    propList.insert("librevenge:format", pVect);
164
1.28M
  return true;
165
1.37M
}
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
86.7M
{
232
86.7M
  if (m_format<cell.m_format) return 1;
233
80.6M
  if (m_format>cell.m_format) return -1;
234
69.2M
  if (m_numberFormat<cell.m_numberFormat) return 1;
235
63.4M
  if (m_numberFormat>cell.m_numberFormat) return -1;
236
49.2M
  if (m_digits<cell.m_digits) return 1;
237
45.3M
  if (m_digits>cell.m_digits) return -1;
238
38.4M
  if (m_integerDigits<cell.m_integerDigits) return 1;
239
38.4M
  if (m_integerDigits>cell.m_integerDigits) return -1;
240
38.4M
  if (m_numeratorDigits<cell.m_numeratorDigits) return 1;
241
38.4M
  if (m_numeratorDigits>cell.m_numeratorDigits) return -1;
242
38.4M
  if (m_denominatorDigits<cell.m_denominatorDigits) return 1;
243
38.4M
  if (m_denominatorDigits>cell.m_denominatorDigits) return -1;
244
38.4M
  if (m_thousandHasSeparator!=cell.m_thousandHasSeparator) return m_thousandHasSeparator ? -1:1;
245
38.3M
  if (m_parenthesesForNegative!=cell.m_parenthesesForNegative) return m_parenthesesForNegative ? -1:1;
246
38.3M
  if (m_DTFormat<cell.m_DTFormat) return 1;
247
38.0M
  if (m_DTFormat>cell.m_DTFormat) return -1;
248
37.4M
  if (m_currencySymbol<cell.m_currencySymbol) return 1;
249
37.4M
  if (m_currencySymbol>cell.m_currencySymbol) return -1;
250
37.4M
  return 0;
251
37.4M
}
252
////////////////////////////////////////////////////////////
253
// MWAWCell
254
////////////////////////////////////////////////////////////
255
void MWAWCell::addTo(librevenge::RVNGPropertyList &propList, std::shared_ptr<MWAWFontConverter> fontConverter) const
256
19.8M
{
257
19.8M
  propList.insert("librevenge:column", position()[0]);
258
19.8M
  propList.insert("librevenge:row", position()[1]);
259
260
19.8M
  propList.insert("table:number-columns-spanned", numSpannedCells()[0]);
261
19.8M
  propList.insert("table:number-rows-spanned", numSpannedCells()[1]);
262
263
19.8M
  if (m_fontSet)
264
12.1M
    m_font.addTo(propList, fontConverter);
265
26.8M
  for (size_t c = 0; c < m_bordersList.size(); c++) {
266
7.00M
    switch (c) {
267
1.75M
    case libmwaw::Left:
268
1.75M
      m_bordersList[c].addTo(propList, "left");
269
1.75M
      break;
270
1.75M
    case libmwaw::Right:
271
1.75M
      m_bordersList[c].addTo(propList, "right");
272
1.75M
      break;
273
1.75M
    case libmwaw::Top:
274
1.75M
      m_bordersList[c].addTo(propList, "top");
275
1.75M
      break;
276
1.75M
    case libmwaw::Bottom:
277
1.75M
      m_bordersList[c].addTo(propList, "bottom");
278
1.75M
      break;
279
0
    default:
280
0
      MWAW_DEBUG_MSG(("MWAWCell::addTo: can not send %d border\n",int(c)));
281
0
      break;
282
7.00M
    }
283
7.00M
  }
284
19.8M
  if (!backgroundColor().isWhite())
285
128k
    propList.insert("fo:background-color", backgroundColor().str().c_str());
286
19.8M
  if (isProtected())
287
222k
    propList.insert("style:cell-protect","protected");
288
  // alignment
289
19.8M
  switch (hAlignment()) {
290
1.03M
  case HALIGN_LEFT:
291
1.03M
    propList.insert("fo:text-align", "first");
292
1.03M
    propList.insert("style:text-align-source", "fix");
293
1.03M
    break;
294
424k
  case HALIGN_CENTER:
295
424k
    propList.insert("fo:text-align", "center");
296
424k
    propList.insert("style:text-align-source", "fix");
297
424k
    break;
298
689k
  case HALIGN_RIGHT:
299
689k
    propList.insert("fo:text-align", "end");
300
689k
    propList.insert("style:text-align-source", "fix");
301
689k
    break;
302
17.7M
  case HALIGN_DEFAULT:
303
17.7M
    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.8M
  }
310
  // no padding
311
19.8M
  propList.insert("fo:padding", 0, librevenge::RVNG_POINT);
312
  // alignment
313
19.8M
  switch (vAlignment()) {
314
0
  case VALIGN_TOP:
315
0
    propList.insert("style:vertical-align", "top");
316
0
    break;
317
262k
  case VALIGN_CENTER:
318
262k
    propList.insert("style:vertical-align", "middle");
319
262k
    break;
320
5.36M
  case VALIGN_BOTTOM:
321
5.36M
    propList.insert("style:vertical-align", "bottom");
322
5.36M
    break;
323
14.2M
  case VALIGN_DEFAULT:
324
14.2M
    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.8M
  }
330
19.8M
  int rot=int(m_rotation); // int seems better than double
331
19.8M
  if (rot)
332
2.81k
    propList.insert("style:rotation-angle", rot);
333
19.8M
}
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.29k
{
347
2.29k
  std::stringstream f;
348
2.29k
  int col = pos[0];
349
2.29k
  if (col > 26*26) {
350
0
    f << char('A'+col/(26*26));
351
0
    col *= 26*26;
352
0
  }
353
2.29k
  if (col > 26) {
354
0
    f << char('A'+col/26);
355
0
    col %= 26;
356
0
  }
357
2.29k
  f << char('A'+col);
358
2.29k
  f << pos[1]+1;
359
2.29k
  return f.str();
360
2.29k
}
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
5.13M
{
384
5.13M
  int const allBits = libmwaw::LeftBit|libmwaw::RightBit|libmwaw::TopBit|libmwaw::BottomBit|libmwaw::HMiddleBit|libmwaw::VMiddleBit;
385
5.13M
  if (wh & (~allBits)) {
386
0
    MWAW_DEBUG_MSG(("MWAWCell::setBorders: unknown borders\n"));
387
0
    return;
388
0
  }
389
5.13M
  size_t numData = 4;
390
5.13M
  if (wh & (libmwaw::HMiddleBit|libmwaw::VMiddleBit))
391
0
    numData=6;
392
5.13M
  if (m_bordersList.size() < numData) {
393
4.46M
    MWAWBorder emptyBorder;
394
4.46M
    emptyBorder.m_style = MWAWBorder::None;
395
4.46M
    m_bordersList.resize(numData, emptyBorder);
396
4.46M
  }
397
5.13M
  if (wh & libmwaw::LeftBit) m_bordersList[libmwaw::Left] = border;
398
5.13M
  if (wh & libmwaw::RightBit) m_bordersList[libmwaw::Right] = border;
399
5.13M
  if (wh & libmwaw::TopBit) m_bordersList[libmwaw::Top] = border;
400
5.13M
  if (wh & libmwaw::BottomBit) m_bordersList[libmwaw::Bottom] = border;
401
5.13M
  if (wh & libmwaw::HMiddleBit) m_bordersList[libmwaw::HMiddle] = border;
402
5.13M
  if (wh & libmwaw::VMiddleBit) m_bordersList[libmwaw::VMiddle] = border;
403
5.13M
}
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
588k
{
494
588k
  if (!listener) return true;
495
588k
  listener->openTableCell(*this);
496
588k
  bool ok=sendContent(listener, table);
497
588k
  listener->closeTableCell();
498
588k
  return ok;
499
588k
}
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
754k
{
512
  /* first convert the date in long*/
513
754k
  auto numDaysSinceOrigin=long(val+0.4);
514
  // checkme: do we need to check before for isNan(val) ?
515
754k
  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
184k
    MWAW_DEBUG_MSG(("MWAWCellContent::double2Date: using a double to represent the date %ld seems odd\n", numDaysSinceOrigin));
520
184k
    Y=1904;
521
184k
    M=D=1;
522
184k
    return false;
523
184k
  }
524
  // find the century
525
570k
  int century=19;
526
933k
  while (numDaysSinceOrigin>=36500+24) {
527
362k
    long numDaysInCentury=36500+24+((century%4)?0:1);
528
362k
    if (numDaysSinceOrigin<numDaysInCentury) break;
529
362k
    numDaysSinceOrigin-=numDaysInCentury;
530
362k
    ++century;
531
362k
  }
532
664k
  while (numDaysSinceOrigin<0) {
533
94.0k
    --century;
534
94.0k
    numDaysSinceOrigin+=36500+24+((century%4)?0:1);
535
94.0k
  }
536
  // now compute the year
537
570k
  Y=int(numDaysSinceOrigin/365);
538
570k
  long numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0);
539
570k
  if (numDaysToEndY1>numDaysSinceOrigin) {
540
15.3k
    --Y;
541
15.3k
    numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0);
542
15.3k
  }
543
  // finish to compute the date
544
570k
  auto numDaysFrom1Jan=int(numDaysSinceOrigin-numDaysToEndY1);
545
570k
  Y+=century*100;
546
570k
  bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0);
547
548
2.35M
  for (M=0; M<12; ++M) {
549
2.35M
    static const int days[2][12] = {
550
2.35M
      { 0,31,59,90,120,151,181,212,243,273,304,334},
551
2.35M
      { 0,31,60,91,121,152,182,213,244,274,305,335}
552
2.35M
    };
553
2.35M
    if (M<11 && days[isLeap ? 1 : 0][M+1]<=numDaysFrom1Jan) continue;
554
570k
    D=(numDaysFrom1Jan-days[isLeap ? 1 : 0][M++])+1;
555
570k
    break;
556
2.35M
  }
557
570k
  return true;
558
754k
}
559
560
bool MWAWCellContent::date2Double(int Y, int M, int D, double &val)
561
9.50k
{
562
9.50k
  --M;
563
9.50k
  --D;
564
9.50k
  if (M>11) {
565
3.08k
    Y += M/12;
566
3.08k
    M %= 12;
567
3.08k
  }
568
6.41k
  else if (M<0) {
569
2.06k
    int yDiff = (-M + 11)/12;
570
2.06k
    Y -= yDiff;
571
2.06k
    M+=12*yDiff;
572
2.06k
  }
573
  // sanity check
574
9.50k
  if (M<0||M>11) {
575
0
    MWAW_DEBUG_MSG(("MWAWCellContent::date2Double: something is bad\n"));
576
0
    return false;
577
0
  }
578
9.50k
  bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0);
579
9.50k
  int32_t const daysFrom0=365*Y+(Y/400)-(Y/100)+(Y/4);
580
9.50k
  int32_t const daysFrom1900=365*1900+(1900/400)-(1900/100)+(1900/4);
581
9.50k
  static const int32_t days[2][12] = {
582
9.50k
    { 0,31,59,90,120,151,181,212,243,273,304,334},
583
9.50k
    { 0,31,60,91,121,152,182,213,244,274,305,335}
584
9.50k
  };
585
9.50k
  int32_t daysFrom1Jan=days[isLeap ? 1 : 0][M] + D;
586
9.50k
  val=double(daysFrom0-daysFrom1900+daysFrom1Jan);
587
9.50k
  return true;
588
9.50k
}
589
590
bool MWAWCellContent::double2Time(double val, int &H, int &M, int &S)
591
514k
{
592
514k
  if (val < 0.0 || val > 1.0) return false;
593
512k
  double time = 24.*3600.*val+0.5;
594
512k
  H=int(time/3600.);
595
512k
  time -= H*3600.;
596
512k
  M=int(time/60.);
597
512k
  time -= M*60.;
598
512k
  S=int(time);
599
512k
  return true;
600
514k
}
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
532k
{
731
532k
  librevenge::RVNGPropertyList pList;
732
532k
  switch (m_type) {
733
245k
  case F_Operator:
734
245k
    pList.insert("librevenge:type","librevenge-operator");
735
245k
    pList.insert("librevenge:operator",m_content.c_str());
736
245k
    break;
737
84.3k
  case F_Function:
738
84.3k
    pList.insert("librevenge:type","librevenge-function");
739
84.3k
    pList.insert("librevenge:function",m_content.c_str());
740
84.3k
    break;
741
20.4k
  case F_Text: {
742
    // we must use the font converter here to get the final string
743
20.4k
    pList.insert("librevenge:type","librevenge-text");
744
20.4k
    librevenge::RVNGString finalStr("");
745
773k
    for (auto c : m_content) {
746
773k
      int unicode=fontConverter.unicode(fontId,static_cast<unsigned char>(c));
747
773k
      if (unicode==-1) {
748
266k
        if (c < 0x20 && c!=9) {
749
253k
          MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction: Find odd char %x\n", static_cast<unsigned int>(c)));
750
253k
        }
751
13.4k
        else
752
13.4k
          finalStr.append(char(c));
753
266k
      }
754
506k
      else if (unicode != 0xfffd)
755
506k
        libmwaw::appendUnicode(static_cast<uint32_t>(unicode), finalStr);
756
773k
    }
757
20.4k
    pList.insert("librevenge:text",finalStr);
758
20.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
24.0k
  case F_Double:
768
24.0k
    pList.insert("librevenge:type","librevenge-number");
769
24.0k
    pList.insert("librevenge:number",m_doubleValue, librevenge::RVNG_GENERIC);
770
24.0k
    break;
771
49.6k
  case F_Long:
772
49.6k
    pList.insert("librevenge:type","librevenge-number");
773
49.6k
    pList.insert("librevenge:number",m_longValue, librevenge::RVNG_GENERIC);
774
49.6k
    break;
775
74.3k
  case F_Cell:
776
74.3k
    pList.insert("librevenge:type","librevenge-cell");
777
74.3k
    if (m_position[0][0]>=0) {
778
74.2k
      pList.insert("librevenge:column",m_position[0][0]);
779
74.2k
      pList.insert("librevenge:column-absolute", !m_positionRelative[0][0]);
780
74.2k
    }
781
74.3k
    if (m_position[0][1]>=0) {
782
72.2k
      pList.insert("librevenge:row",m_position[0][1]);
783
72.2k
      pList.insert("librevenge:row-absolute", !m_positionRelative[0][1]);
784
72.2k
    }
785
74.3k
    if (!m_sheet[0].empty())
786
533
      pList.insert("librevenge:sheet-name",m_sheet[0]);
787
74.3k
    if (!m_fileName.empty())
788
510
      pList.insert("librevenge:file-name",m_fileName.cstr());
789
74.3k
    break;
790
33.5k
  case F_CellList:
791
33.5k
    pList.insert("librevenge:type","librevenge-cells");
792
33.5k
    if (m_position[0][0]>=0) {
793
26.3k
      pList.insert("librevenge:start-column",m_position[0][0]);
794
26.3k
      pList.insert("librevenge:start-column-absolute", !m_positionRelative[0][0]);
795
26.3k
    }
796
33.5k
    if (m_position[0][1]>=0) {
797
32.8k
      pList.insert("librevenge:start-row",m_position[0][1]);
798
32.8k
      pList.insert("librevenge:start-row-absolute", !m_positionRelative[0][1]);
799
32.8k
    }
800
33.5k
    if (m_position[1][0]>=0) {
801
26.3k
      pList.insert("librevenge:end-column",m_position[1][0]);
802
26.3k
      pList.insert("librevenge:end-column-absolute", !m_positionRelative[1][0]);
803
26.3k
    }
804
33.5k
    if (m_position[1][1]>=0) {
805
33.5k
      pList.insert("librevenge:end-row",m_position[1][1]);
806
33.5k
      pList.insert("librevenge:end-row-absolute", !m_positionRelative[1][1]);
807
33.5k
    }
808
33.5k
    if (!m_sheet[0].empty())
809
596
      pList.insert("librevenge:sheet-name",m_sheet[0]);
810
33.5k
    if (!m_sheet[1].empty())
811
0
      pList.insert("librevenge:end-sheet-name",m_sheet[1]);
812
33.5k
    if (!m_fileName.empty())
813
409
      pList.insert("librevenge:file-name",m_fileName.cstr());
814
33.5k
    break;
815
#if !defined(__clang__)
816
  default:
817
    MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction::getPropertyList: unexpected type\n"));
818
#endif
819
532k
  }
820
532k
  return pList;
821
532k
}
822
823
std::ostream &operator<<(std::ostream &o, MWAWCellContent::FormulaInstruction const &inst)
824
2.22M
{
825
2.22M
  if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Double)
826
22.4k
    o << inst.m_doubleValue;
827
2.19M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Long)
828
23.7k
    o << inst.m_longValue;
829
2.17M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Cell) {
830
441k
    if (!inst.m_sheet[0].empty()) o << "\"" << inst.m_sheet[0].cstr() << "\"";
831
441k
    if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]";
832
441k
    if (!inst.m_positionRelative[0][0]) o << "$";
833
441k
    if (inst.m_position[0][0]<0) o << "C" << inst.m_position[0][0];
834
441k
    else {
835
441k
      if (inst.m_position[0][0]>=26) o << char(inst.m_position[0][0]/26-1 + 'A');
836
441k
      o << char(inst.m_position[0][0]%26+'A');
837
441k
    }
838
441k
    if (!inst.m_positionRelative[0][1]) o << "$";
839
441k
    if (inst.m_position[0][1]<0) o << "R" << inst.m_position[0][1];
840
441k
    else o << inst.m_position[0][1];
841
441k
  }
842
1.73M
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_CellList) {
843
1.22M
    if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]";
844
3.67M
    for (int l=0; l<2; ++l) {
845
2.44M
      if (!inst.m_sheet[l].empty() && (l==0 || inst.m_sheet[0]!=inst.m_sheet[1]))
846
2.97k
        o << "\"" << inst.m_sheet[l].cstr() << "\"";
847
2.44M
      if (!inst.m_positionRelative[l][0]) o << "$";
848
2.44M
      if (inst.m_position[l][0]<0) o << "C" << inst.m_position[l][0];
849
2.44M
      else {
850
2.44M
        if (inst.m_position[l][0]>=26) o << char(inst.m_position[l][0]/26-1 + 'A');
851
2.44M
        o << char(inst.m_position[l][0]%26+'A');
852
2.44M
      }
853
2.44M
      if (!inst.m_positionRelative[l][1]) o << "$";
854
2.44M
      if (inst.m_position[l][1]<0) o << "R" << inst.m_position[l][1];
855
2.44M
      else o << inst.m_position[l][1];
856
2.44M
      if (l==0) o << ":";
857
2.44M
    }
858
1.22M
  }
859
508k
  else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Text ||
860
201k
           inst.m_type==MWAWCellContent::FormulaInstruction::F_Unicode)
861
306k
    o << "\"" << inst.m_content << "\"";
862
201k
  else
863
201k
    o << inst.m_content;
864
2.22M
  return o;
865
2.22M
}
866
867
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: