Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ODS Translator
4 : * Purpose: Implements OGRODSDataSource class
5 : * Author: Even Rouault, even dot rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "ogr_ods.h"
14 : #include "memdataset.h"
15 : #include "ogr_p.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_vsi_error.h"
18 : #include "ods_formula.h"
19 :
20 : #include <algorithm>
21 : #include <set>
22 :
23 : namespace OGRODS
24 : {
25 :
26 : constexpr int PARSER_BUF_SIZE = 8192;
27 :
28 : /************************************************************************/
29 : /* ODSCellEvaluator */
30 : /************************************************************************/
31 :
32 : class ODSCellEvaluator : public IODSCellEvaluator
33 : {
34 : private:
35 : OGRODSLayer *poLayer;
36 : std::set<std::pair<int, int>> oVisisitedCells;
37 :
38 : public:
39 110 : explicit ODSCellEvaluator(OGRODSLayer *poLayerIn) : poLayer(poLayerIn)
40 : {
41 110 : }
42 :
43 : int EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
44 : std::vector<ods_formula_node> &aoOutValues) override;
45 :
46 : int Evaluate(int nRow, int nCol);
47 : };
48 :
49 : /************************************************************************/
50 : /* OGRODSLayer() */
51 : /************************************************************************/
52 :
53 218 : OGRODSLayer::OGRODSLayer(OGRODSDataSource *poDSIn, const char *pszName,
54 218 : bool bUpdatedIn)
55 : : OGRMemLayer(pszName, nullptr, wkbNone), poDS(poDSIn),
56 218 : bUpdated(CPL_TO_BOOL(bUpdatedIn)), bHasHeaderLine(false),
57 218 : m_poAttrQueryODS(nullptr)
58 : {
59 218 : SetAdvertizeUTF8(true);
60 218 : }
61 :
62 : /************************************************************************/
63 : /* ~OGRODSLayer() */
64 : /************************************************************************/
65 :
66 436 : OGRODSLayer::~OGRODSLayer()
67 : {
68 218 : delete m_poAttrQueryODS;
69 436 : }
70 :
71 : /************************************************************************/
72 : /* Updated() */
73 : /************************************************************************/
74 :
75 1857 : void OGRODSLayer::SetUpdated(bool bUpdatedIn)
76 : {
77 1857 : if (bUpdatedIn && !bUpdated && poDS->GetUpdatable())
78 : {
79 11 : bUpdated = true;
80 11 : poDS->SetUpdated();
81 : }
82 1846 : else if (bUpdated && !bUpdatedIn)
83 : {
84 55 : bUpdated = false;
85 : }
86 1857 : }
87 :
88 : /************************************************************************/
89 : /* SyncToDisk() */
90 : /************************************************************************/
91 :
92 0 : OGRErr OGRODSLayer::SyncToDisk()
93 : {
94 0 : poDS->FlushCache(false);
95 0 : return OGRERR_NONE;
96 : }
97 :
98 : /************************************************************************/
99 : /* TranslateFIDFromMemLayer() */
100 : /************************************************************************/
101 :
102 : // Translate a FID from MEM convention (0-based) to ODS convention
103 2516 : GIntBig OGRODSLayer::TranslateFIDFromMemLayer(GIntBig nFID) const
104 : {
105 2516 : return nFID + (1 + (bHasHeaderLine ? 1 : 0));
106 : }
107 :
108 : /************************************************************************/
109 : /* TranslateFIDToMemLayer() */
110 : /************************************************************************/
111 :
112 : // Translate a FID from ODS convention to MEM convention (0-based)
113 77 : GIntBig OGRODSLayer::TranslateFIDToMemLayer(GIntBig nFID) const
114 : {
115 77 : if (nFID > 0)
116 59 : return nFID - (1 + (bHasHeaderLine ? 1 : 0));
117 18 : return OGRNullFID;
118 : }
119 :
120 : /************************************************************************/
121 : /* GetNextFeature() */
122 : /************************************************************************/
123 :
124 2004 : OGRFeature *OGRODSLayer::GetNextFeature()
125 : {
126 : while (true)
127 : {
128 2004 : OGRFeature *poFeature = OGRMemLayer::GetNextFeature();
129 2004 : if (poFeature == nullptr)
130 331 : return nullptr;
131 1673 : poFeature->SetFID(TranslateFIDFromMemLayer(poFeature->GetFID()));
132 2127 : if (m_poAttrQueryODS == nullptr ||
133 454 : m_poAttrQueryODS->Evaluate(poFeature))
134 : {
135 1405 : return poFeature;
136 : }
137 268 : delete poFeature;
138 268 : }
139 : }
140 :
141 : /************************************************************************/
142 : /* GetFeature() */
143 : /************************************************************************/
144 :
145 50 : OGRFeature *OGRODSLayer::GetFeature(GIntBig nFeatureId)
146 : {
147 : OGRFeature *poFeature =
148 50 : OGRMemLayer::GetFeature(TranslateFIDToMemLayer(nFeatureId));
149 50 : if (poFeature)
150 22 : poFeature->SetFID(nFeatureId);
151 50 : return poFeature;
152 : }
153 :
154 : /************************************************************************/
155 : /* GetFeatureCount() */
156 : /************************************************************************/
157 :
158 227 : GIntBig OGRODSLayer::GetFeatureCount(int bForce)
159 : {
160 227 : if (m_poAttrQueryODS == nullptr)
161 213 : return OGRMemLayer::GetFeatureCount(bForce);
162 14 : return OGRLayer::GetFeatureCount(bForce);
163 : }
164 :
165 : /************************************************************************/
166 : /* ISetFeature() */
167 : /************************************************************************/
168 :
169 14 : OGRErr OGRODSLayer::ISetFeature(OGRFeature *poFeature)
170 : {
171 14 : const GIntBig nFIDOrigin = poFeature->GetFID();
172 14 : if (nFIDOrigin > 0)
173 : {
174 5 : const GIntBig nFIDMemLayer = TranslateFIDToMemLayer(nFIDOrigin);
175 5 : if (!GetFeatureRef(nFIDMemLayer))
176 0 : return OGRERR_NON_EXISTING_FEATURE;
177 5 : poFeature->SetFID(nFIDMemLayer);
178 : }
179 : else
180 : {
181 9 : return OGRERR_NON_EXISTING_FEATURE;
182 : }
183 5 : SetUpdated();
184 5 : OGRErr eErr = OGRMemLayer::ISetFeature(poFeature);
185 5 : poFeature->SetFID(nFIDOrigin);
186 5 : return eErr;
187 : }
188 :
189 : /************************************************************************/
190 : /* IUpdateFeature() */
191 : /************************************************************************/
192 :
193 2 : OGRErr OGRODSLayer::IUpdateFeature(OGRFeature *poFeature,
194 : int nUpdatedFieldsCount,
195 : const int *panUpdatedFieldsIdx,
196 : int nUpdatedGeomFieldsCount,
197 : const int *panUpdatedGeomFieldsIdx,
198 : bool bUpdateStyleString)
199 : {
200 2 : const GIntBig nFIDOrigin = poFeature->GetFID();
201 2 : if (nFIDOrigin != OGRNullFID)
202 2 : poFeature->SetFID(TranslateFIDToMemLayer(nFIDOrigin));
203 2 : SetUpdated();
204 2 : OGRErr eErr = OGRMemLayer::IUpdateFeature(
205 : poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
206 : nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
207 2 : poFeature->SetFID(nFIDOrigin);
208 2 : return eErr;
209 : }
210 :
211 : /************************************************************************/
212 : /* ICreateFeature() */
213 : /************************************************************************/
214 :
215 843 : OGRErr OGRODSLayer::ICreateFeature(OGRFeature *poFeature)
216 : {
217 843 : const GIntBig nFIDOrigin = poFeature->GetFID();
218 843 : if (nFIDOrigin > 0)
219 : {
220 1 : const GIntBig nFIDModified = TranslateFIDToMemLayer(nFIDOrigin);
221 1 : if (GetFeatureRef(nFIDModified))
222 : {
223 0 : SetUpdated();
224 0 : poFeature->SetFID(nFIDModified);
225 0 : OGRErr eErr = OGRMemLayer::ISetFeature(poFeature);
226 0 : poFeature->SetFID(nFIDOrigin);
227 0 : return eErr;
228 : }
229 : }
230 843 : SetUpdated();
231 843 : poFeature->SetFID(OGRNullFID);
232 843 : OGRErr eErr = OGRMemLayer::ICreateFeature(poFeature);
233 843 : poFeature->SetFID(TranslateFIDFromMemLayer(poFeature->GetFID()));
234 843 : return eErr;
235 : }
236 :
237 : /************************************************************************/
238 : /* DeleteFeature() */
239 : /************************************************************************/
240 :
241 19 : OGRErr OGRODSLayer::DeleteFeature(GIntBig nFID)
242 : {
243 19 : SetUpdated();
244 19 : return OGRMemLayer::DeleteFeature(TranslateFIDToMemLayer(nFID));
245 : }
246 :
247 : /************************************************************************/
248 : /* SetAttributeFilter() */
249 : /************************************************************************/
250 :
251 211 : OGRErr OGRODSLayer::SetAttributeFilter(const char *pszQuery)
252 :
253 : {
254 : // Intercept attribute filter since we mess up with FIDs
255 211 : OGRErr eErr = OGRLayer::SetAttributeFilter(pszQuery);
256 211 : delete m_poAttrQueryODS;
257 211 : m_poAttrQueryODS = m_poAttrQuery;
258 211 : m_poAttrQuery = nullptr;
259 211 : return eErr;
260 : }
261 :
262 : /************************************************************************/
263 : /* TestCapability() */
264 : /************************************************************************/
265 :
266 693 : int OGRODSLayer::TestCapability(const char *pszCap) const
267 :
268 : {
269 693 : if (EQUAL(pszCap, OLCFastFeatureCount))
270 0 : return m_poFilterGeom == nullptr && m_poAttrQueryODS == nullptr;
271 693 : else if (EQUAL(pszCap, OLCUpsertFeature))
272 9 : return false;
273 684 : return OGRMemLayer::TestCapability(pszCap);
274 : }
275 :
276 : /************************************************************************/
277 : /* GetDataset() */
278 : /************************************************************************/
279 :
280 19 : GDALDataset *OGRODSLayer::GetDataset()
281 : {
282 19 : return poDS;
283 : }
284 :
285 : /************************************************************************/
286 : /* OGRODSDataSource() */
287 : /************************************************************************/
288 :
289 110 : OGRODSDataSource::OGRODSDataSource(CSLConstList papszOpenOptionsIn)
290 : : pszName(nullptr), bUpdatable(false), bUpdated(false),
291 : bAnalysedFile(false), nLayers(0), papoLayers(nullptr),
292 : fpSettings(nullptr), nVerticalSplitFlags(0), fpContent(nullptr),
293 : bFirstLineIsHeaders(false),
294 110 : bAutodetectTypes(!EQUAL(
295 : CSLFetchNameValueDef(papszOpenOptionsIn, "FIELD_TYPES",
296 : CPLGetConfigOption("OGR_ODS_FIELD_TYPES", "")),
297 : "STRING")),
298 : oParser(nullptr), bStopParsing(false), nWithoutEventCounter(0),
299 : nDataHandlerCounter(0), nCurLine(0), nEmptyRowsAccumulated(0),
300 : nRowsRepeated(1), nCurCol(0), nCellsRepeated(0), bEndTableParsing(false),
301 220 : poCurLayer(nullptr), nStackDepth(0), nDepth(0)
302 : {
303 110 : stateStack[0].eVal = STATE_DEFAULT;
304 110 : stateStack[0].nBeginDepth = 0;
305 110 : }
306 :
307 : /************************************************************************/
308 : /* ~OGRODSDataSource() */
309 : /************************************************************************/
310 :
311 220 : OGRODSDataSource::~OGRODSDataSource()
312 :
313 : {
314 110 : OGRODSDataSource::Close();
315 220 : }
316 :
317 : /************************************************************************/
318 : /* Close() */
319 : /************************************************************************/
320 :
321 220 : CPLErr OGRODSDataSource::Close()
322 : {
323 220 : CPLErr eErr = CE_None;
324 220 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
325 : {
326 110 : if (OGRODSDataSource::FlushCache(true) != CE_None)
327 1 : eErr = CE_Failure;
328 :
329 110 : CPLFree(pszName);
330 :
331 : // Those are read-only files, so we can ignore VSIFCloseL() return
332 : // value.
333 110 : if (fpContent)
334 33 : VSIFCloseL(fpContent);
335 110 : if (fpSettings)
336 33 : VSIFCloseL(fpSettings);
337 :
338 299 : for (int i = 0; i < nLayers; i++)
339 189 : delete papoLayers[i];
340 110 : CPLFree(papoLayers);
341 :
342 110 : if (GDALDataset::Close() != CE_None)
343 0 : eErr = CE_Failure;
344 : }
345 220 : return eErr;
346 : }
347 :
348 : /************************************************************************/
349 : /* TestCapability() */
350 : /************************************************************************/
351 :
352 133 : int OGRODSDataSource::TestCapability(const char *pszCap) const
353 :
354 : {
355 133 : if (EQUAL(pszCap, ODsCCreateLayer))
356 44 : return bUpdatable;
357 89 : else if (EQUAL(pszCap, ODsCDeleteLayer))
358 18 : return bUpdatable;
359 71 : else if (EQUAL(pszCap, ODsCRandomLayerWrite))
360 0 : return bUpdatable;
361 71 : else if (EQUAL(pszCap, ODsCMeasuredGeometries))
362 18 : return true;
363 53 : else if (EQUAL(pszCap, ODsCZGeometries))
364 18 : return true;
365 35 : else if (EQUAL(pszCap, ODsCCurveGeometries))
366 18 : return true;
367 : else
368 17 : return false;
369 : }
370 :
371 : /************************************************************************/
372 : /* GetLayer() */
373 : /************************************************************************/
374 :
375 943 : const OGRLayer *OGRODSDataSource::GetLayer(int iLayer) const
376 :
377 : {
378 943 : const_cast<OGRODSDataSource *>(this)->AnalyseFile();
379 943 : if (iLayer < 0 || iLayer >= nLayers)
380 4 : return nullptr;
381 :
382 939 : return papoLayers[iLayer];
383 : }
384 :
385 : /************************************************************************/
386 : /* GetLayerCount() */
387 : /************************************************************************/
388 :
389 983 : int OGRODSDataSource::GetLayerCount() const
390 : {
391 983 : const_cast<OGRODSDataSource *>(this)->AnalyseFile();
392 983 : return nLayers;
393 : }
394 :
395 : /************************************************************************/
396 : /* Open() */
397 : /************************************************************************/
398 :
399 72 : int OGRODSDataSource::Open(const char *pszFilename, VSILFILE *fpContentIn,
400 : VSILFILE *fpSettingsIn, int bUpdatableIn)
401 :
402 : {
403 72 : SetDescription(pszFilename);
404 72 : bUpdatable = CPL_TO_BOOL(bUpdatableIn);
405 :
406 72 : pszName = CPLStrdup(pszFilename);
407 72 : fpContent = fpContentIn;
408 72 : fpSettings = fpSettingsIn;
409 :
410 72 : return TRUE;
411 : }
412 :
413 : /************************************************************************/
414 : /* Create() */
415 : /************************************************************************/
416 :
417 38 : int OGRODSDataSource::Create(const char *pszFilename,
418 : char ** /* papszOptions */)
419 : {
420 38 : bUpdated = true;
421 38 : bUpdatable = true;
422 38 : bAnalysedFile = true;
423 :
424 38 : pszName = CPLStrdup(pszFilename);
425 :
426 38 : return TRUE;
427 : }
428 :
429 : /************************************************************************/
430 : /* startElementCbk() */
431 : /************************************************************************/
432 :
433 6094 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
434 : const char **ppszAttr)
435 : {
436 6094 : static_cast<OGRODSDataSource *>(pUserData)->startElementCbk(pszName,
437 : ppszAttr);
438 6094 : }
439 :
440 6094 : void OGRODSDataSource::startElementCbk(const char *pszNameIn,
441 : const char **ppszAttr)
442 : {
443 6094 : if (bStopParsing)
444 0 : return;
445 :
446 6094 : nWithoutEventCounter = 0;
447 6094 : switch (stateStack[nStackDepth].eVal)
448 : {
449 2128 : case STATE_DEFAULT:
450 2128 : startElementDefault(pszNameIn, ppszAttr);
451 2128 : break;
452 902 : case STATE_TABLE:
453 902 : startElementTable(pszNameIn, ppszAttr);
454 902 : break;
455 2009 : case STATE_ROW:
456 2009 : startElementRow(pszNameIn, ppszAttr);
457 2009 : break;
458 1055 : case STATE_CELL:
459 1055 : startElementCell(pszNameIn, ppszAttr);
460 1055 : break;
461 0 : case STATE_TEXTP:
462 0 : break;
463 0 : default:
464 0 : break;
465 : }
466 6094 : nDepth++;
467 : }
468 :
469 : /************************************************************************/
470 : /* endElementCbk() */
471 : /************************************************************************/
472 :
473 6094 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
474 : {
475 6094 : static_cast<OGRODSDataSource *>(pUserData)->endElementCbk(pszName);
476 6094 : }
477 :
478 6094 : void OGRODSDataSource::endElementCbk(const char *pszNameIn)
479 : {
480 6094 : if (bStopParsing)
481 0 : return;
482 :
483 6094 : nWithoutEventCounter = 0;
484 :
485 6094 : nDepth--;
486 6094 : switch (stateStack[nStackDepth].eVal)
487 : {
488 1971 : case STATE_DEFAULT:
489 1971 : break;
490 437 : case STATE_TABLE:
491 437 : endElementTable(pszNameIn);
492 437 : break;
493 662 : case STATE_ROW:
494 662 : endElementRow(pszNameIn);
495 662 : break;
496 2457 : case STATE_CELL:
497 2457 : endElementCell(pszNameIn);
498 2457 : break;
499 567 : case STATE_TEXTP:
500 567 : break;
501 0 : default:
502 0 : break;
503 : }
504 :
505 6094 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
506 3354 : nStackDepth--;
507 : }
508 :
509 : /************************************************************************/
510 : /* dataHandlerCbk() */
511 : /************************************************************************/
512 :
513 5322 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
514 : {
515 5322 : static_cast<OGRODSDataSource *>(pUserData)->dataHandlerCbk(data, nLen);
516 5322 : }
517 :
518 5322 : void OGRODSDataSource::dataHandlerCbk(const char *data, int nLen)
519 : {
520 5322 : if (bStopParsing)
521 0 : return;
522 :
523 5322 : nDataHandlerCounter++;
524 5322 : if (nDataHandlerCounter >= PARSER_BUF_SIZE)
525 : {
526 0 : CPLError(CE_Failure, CPLE_AppDefined,
527 : "File probably corrupted (million laugh pattern)");
528 0 : XML_StopParser(oParser, XML_FALSE);
529 0 : bStopParsing = true;
530 0 : return;
531 : }
532 :
533 5322 : nWithoutEventCounter = 0;
534 :
535 5322 : switch (stateStack[nStackDepth].eVal)
536 : {
537 1950 : case STATE_DEFAULT:
538 1950 : break;
539 413 : case STATE_TABLE:
540 413 : break;
541 1233 : case STATE_ROW:
542 1233 : break;
543 1114 : case STATE_CELL:
544 1114 : break;
545 612 : case STATE_TEXTP:
546 612 : dataHandlerTextP(data, nLen);
547 612 : break;
548 0 : default:
549 0 : break;
550 : }
551 : }
552 :
553 : /************************************************************************/
554 : /* PushState() */
555 : /************************************************************************/
556 :
557 3315 : void OGRODSDataSource::PushState(HandlerStateEnum eVal)
558 : {
559 3315 : if (nStackDepth + 1 == STACK_SIZE)
560 : {
561 0 : bStopParsing = true;
562 0 : return;
563 : }
564 3315 : nStackDepth++;
565 3315 : stateStack[nStackDepth].eVal = eVal;
566 3315 : stateStack[nStackDepth].nBeginDepth = nDepth;
567 : }
568 :
569 : /************************************************************************/
570 : /* GetAttributeValue() */
571 : /************************************************************************/
572 :
573 23380 : static const char *GetAttributeValue(const char **ppszAttr, const char *pszKey,
574 : const char *pszDefaultVal)
575 : {
576 23380 : while (*ppszAttr)
577 : {
578 14084 : if (strcmp(ppszAttr[0], pszKey) == 0)
579 4317 : return ppszAttr[1];
580 9767 : ppszAttr += 2;
581 : }
582 9296 : return pszDefaultVal;
583 : }
584 :
585 : /************************************************************************/
586 : /* GetOGRFieldType() */
587 : /************************************************************************/
588 :
589 1322 : OGRFieldType OGRODSDataSource::GetOGRFieldType(const char *pszValue,
590 : const char *pszValueType,
591 : OGRFieldSubType &eSubType)
592 : {
593 1322 : eSubType = OFSTNone;
594 1322 : if (!bAutodetectTypes || pszValueType == nullptr)
595 60 : return OFTString;
596 1262 : else if (strcmp(pszValueType, "string") == 0)
597 416 : return OFTString;
598 846 : else if (strcmp(pszValueType, "float") == 0 ||
599 388 : strcmp(pszValueType, "currency") == 0)
600 : {
601 476 : if (CPLGetValueType(pszValue) == CPL_VALUE_INTEGER)
602 : {
603 342 : GIntBig nVal = CPLAtoGIntBig(pszValue);
604 342 : if (!CPL_INT64_FITS_ON_INT32(nVal))
605 1 : return OFTInteger64;
606 : else
607 341 : return OFTInteger;
608 : }
609 : else
610 134 : return OFTReal;
611 : }
612 370 : else if (strcmp(pszValueType, "percentage") == 0)
613 42 : return OFTReal;
614 328 : else if (strcmp(pszValueType, "date") == 0)
615 : {
616 131 : if (strlen(pszValue) == 4 + 1 + 2 + 1 + 2)
617 66 : return OFTDate;
618 : else
619 65 : return OFTDateTime;
620 : }
621 197 : else if (strcmp(pszValueType, "time") == 0)
622 : {
623 24 : return OFTTime;
624 : }
625 173 : else if (strcmp(pszValueType, "bool") == 0)
626 : {
627 2 : eSubType = OFSTBoolean;
628 2 : return OFTInteger;
629 : }
630 : else
631 171 : return OFTString;
632 : }
633 :
634 : /************************************************************************/
635 : /* SetField() */
636 : /************************************************************************/
637 :
638 1333 : static void SetField(OGRFeature *poFeature, int i, const char *pszValue)
639 : {
640 1333 : if (pszValue[0] == '\0')
641 272 : return;
642 :
643 1061 : OGRFieldType eType = poFeature->GetFieldDefnRef(i)->GetType();
644 1061 : if (eType == OFTTime)
645 : {
646 : int nHour, nHourRepeated, nMinute, nSecond;
647 11 : char c = '\0';
648 22 : if (STARTS_WITH(pszValue, "PT") &&
649 11 : sscanf(pszValue + 2, "%02d%c%02d%c%02d%c", &nHour, &c, &nMinute, &c,
650 : &nSecond, &c) == 6)
651 : {
652 10 : poFeature->SetField(i, 0, 0, 0, nHour, nMinute,
653 : static_cast<float>(nSecond), 0);
654 : }
655 : /* bug with kspread 2.1.2 ? */
656 : /* ex PT121234M56S */
657 3 : else if (STARTS_WITH(pszValue, "PT") &&
658 1 : sscanf(pszValue + 2, "%02d%02d%02d%c%02d%c", &nHour,
659 2 : &nHourRepeated, &nMinute, &c, &nSecond, &c) == 6 &&
660 1 : nHour == nHourRepeated)
661 : {
662 1 : poFeature->SetField(i, 0, 0, 0, nHour, nMinute,
663 : static_cast<float>(nSecond), 0);
664 : }
665 : }
666 1050 : else if (eType == OFTDate || eType == OFTDateTime)
667 : {
668 : OGRField sField;
669 68 : if (OGRParseXMLDateTime(pszValue, &sField))
670 : {
671 68 : poFeature->SetField(i, &sField);
672 68 : }
673 : }
674 : else
675 982 : poFeature->SetField(i, pszValue);
676 : }
677 :
678 : /************************************************************************/
679 : /* DetectHeaderLine() */
680 : /************************************************************************/
681 :
682 115 : void OGRODSDataSource::DetectHeaderLine()
683 :
684 : {
685 115 : bool bHeaderLineCandidate = true;
686 :
687 388 : for (size_t i = 0; i < apoFirstLineTypes.size(); i++)
688 : {
689 306 : if (apoFirstLineTypes[i] != "string")
690 : {
691 : /* If the values in the first line are not text, then it is */
692 : /* not a header line */
693 33 : bHeaderLineCandidate = false;
694 33 : break;
695 : }
696 : }
697 :
698 115 : size_t nCountTextOnCurLine = 0;
699 115 : size_t nCountNonEmptyOnCurLine = 0;
700 372 : for (size_t i = 0; bHeaderLineCandidate && i < apoCurLineTypes.size(); i++)
701 : {
702 257 : if (apoCurLineTypes[i] == "string")
703 : {
704 : /* If there are only text values on the second line, then we cannot
705 : */
706 : /* know if it is a header line or just a regular line */
707 50 : nCountTextOnCurLine++;
708 : }
709 207 : else if (apoCurLineTypes[i] != "")
710 : {
711 177 : nCountNonEmptyOnCurLine++;
712 : }
713 : }
714 :
715 115 : const char *pszODSHeaders = CSLFetchNameValueDef(
716 115 : papszOpenOptions, "HEADERS", CPLGetConfigOption("OGR_ODS_HEADERS", ""));
717 115 : bFirstLineIsHeaders = false;
718 115 : if (EQUAL(pszODSHeaders, "FORCE"))
719 0 : bFirstLineIsHeaders = true;
720 115 : else if (EQUAL(pszODSHeaders, "DISABLE"))
721 12 : bFirstLineIsHeaders = false;
722 103 : else if (osSetLayerHasSplitter.find(poCurLayer->GetName()) !=
723 206 : osSetLayerHasSplitter.end())
724 : {
725 20 : bFirstLineIsHeaders = true;
726 : }
727 93 : else if (bHeaderLineCandidate && !apoFirstLineTypes.empty() &&
728 52 : apoFirstLineTypes.size() == apoCurLineTypes.size() &&
729 150 : nCountTextOnCurLine != apoFirstLineTypes.size() &&
730 : nCountNonEmptyOnCurLine != 0)
731 : {
732 13 : bFirstLineIsHeaders = true;
733 : }
734 115 : CPLDebug("ODS", "%s %s", poCurLayer->GetName(),
735 115 : bFirstLineIsHeaders ? "has header line" : "has no header line");
736 115 : }
737 :
738 : /************************************************************************/
739 : /* startElementDefault() */
740 : /************************************************************************/
741 :
742 2128 : void OGRODSDataSource::startElementDefault(const char *pszNameIn,
743 : const char **ppszAttr)
744 : {
745 2128 : if (strcmp(pszNameIn, "table:table") == 0)
746 : {
747 : const char *pszTableName =
748 157 : GetAttributeValue(ppszAttr, "table:name", "unnamed");
749 :
750 157 : poCurLayer = new OGRODSLayer(this, pszTableName);
751 314 : papoLayers = (OGRLayer **)CPLRealloc(
752 157 : papoLayers, (nLayers + 1) * sizeof(OGRLayer *));
753 157 : papoLayers[nLayers++] = poCurLayer;
754 :
755 157 : nCurLine = 0;
756 157 : nEmptyRowsAccumulated = 0;
757 157 : apoFirstLineValues.resize(0);
758 157 : apoFirstLineTypes.resize(0);
759 157 : PushState(STATE_TABLE);
760 157 : bEndTableParsing = false;
761 : }
762 2128 : }
763 :
764 : /************************************************************************/
765 : /* startElementTable() */
766 : /************************************************************************/
767 :
768 902 : void OGRODSDataSource::startElementTable(const char *pszNameIn,
769 : const char **ppszAttr)
770 : {
771 902 : if (strcmp(pszNameIn, "table:table-row") == 0 && !bEndTableParsing)
772 : {
773 623 : nRowsRepeated = atoi(
774 : GetAttributeValue(ppszAttr, "table:number-rows-repeated", "1"));
775 623 : if (static_cast<GIntBig>(nCurLine) + nRowsRepeated + 2 >= 1048576)
776 : {
777 : // Typical of a XLSX converted to ODS
778 1 : bEndTableParsing = true;
779 1 : return;
780 : }
781 622 : if (nRowsRepeated <= 0 || nRowsRepeated > 10000)
782 : {
783 0 : CPLError(CE_Failure, CPLE_NotSupported,
784 : "Invalid value for number-rows-repeated = %d",
785 : nRowsRepeated);
786 0 : bEndTableParsing = true;
787 0 : nRowsRepeated = 1;
788 0 : return;
789 : }
790 : const int nFields = std::max(
791 1866 : static_cast<int>(apoFirstLineValues.size()),
792 622 : poCurLayer != nullptr ? poCurLayer->GetLayerDefn()->GetFieldCount()
793 622 : : 0);
794 622 : if (nFields > 0 && nRowsRepeated > 100000 / nFields)
795 : {
796 0 : CPLError(CE_Failure, CPLE_AppDefined,
797 : "Too big gap with previous valid row");
798 0 : bEndTableParsing = true;
799 0 : return;
800 : }
801 :
802 622 : nCurCol = 0;
803 :
804 622 : apoCurLineValues.resize(0);
805 622 : apoCurLineTypes.resize(0);
806 :
807 622 : PushState(STATE_ROW);
808 : }
809 : }
810 :
811 : /************************************************************************/
812 : /* ReserveAndLimitFieldCount() */
813 : /************************************************************************/
814 :
815 208 : static void ReserveAndLimitFieldCount(OGRLayer *poLayer,
816 : std::vector<std::string> &aosValues)
817 : {
818 208 : int nMaxCols = atoi(CPLGetConfigOption("OGR_ODS_MAX_FIELD_COUNT", "2000"));
819 208 : if (nMaxCols < 0)
820 0 : nMaxCols = 0;
821 208 : constexpr int MAXCOLS_LIMIT = 1000000;
822 208 : if (nMaxCols > MAXCOLS_LIMIT)
823 0 : nMaxCols = MAXCOLS_LIMIT;
824 208 : if (static_cast<int>(aosValues.size()) > nMaxCols)
825 : {
826 0 : CPLError(CE_Warning, CPLE_AppDefined,
827 : "%d columns detected. Limiting to %d. "
828 : "Set OGR_ODS_MAX_FIELD_COUNT configuration option "
829 : "to allow more fields.",
830 0 : static_cast<int>(aosValues.size()), nMaxCols);
831 : // coverity[tainted_data]
832 0 : aosValues.resize(nMaxCols);
833 : }
834 :
835 416 : poLayer->GetLayerDefn()->ReserveSpaceForFields(
836 208 : static_cast<int>(aosValues.size()));
837 208 : }
838 :
839 : /************************************************************************/
840 : /* endElementTable() */
841 : /************************************************************************/
842 :
843 437 : void OGRODSDataSource::endElementTable(
844 : CPL_UNUSED /* in non-DEBUG*/ const char *pszNameIn)
845 : {
846 437 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
847 : {
848 : // Only use of pszNameIn.
849 157 : CPLAssert(strcmp(pszNameIn, "table:table") == 0);
850 :
851 157 : if (nCurLine == 0 || (nCurLine == 1 && apoFirstLineValues.empty()))
852 : {
853 : /* Remove empty sheet */
854 13 : delete poCurLayer;
855 13 : nLayers--;
856 13 : poCurLayer = nullptr;
857 : }
858 144 : else if (nCurLine == 1)
859 : {
860 : /* If we have only one single line in the sheet */
861 :
862 16 : ReserveAndLimitFieldCount(poCurLayer, apoFirstLineValues);
863 :
864 49 : for (size_t i = 0; i < apoFirstLineValues.size(); i++)
865 : {
866 33 : const char *pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
867 33 : OGRFieldSubType eSubType = OFSTNone;
868 : OGRFieldType eType =
869 33 : GetOGRFieldType(apoFirstLineValues[i].c_str(),
870 33 : apoFirstLineTypes[i].c_str(), eSubType);
871 66 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
872 33 : oFieldDefn.SetSubType(eSubType);
873 33 : poCurLayer->CreateField(&oFieldDefn);
874 : }
875 :
876 16 : OGRFeature *poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
877 49 : for (size_t i = 0; i < apoFirstLineValues.size(); i++)
878 : {
879 33 : SetField(poFeature, static_cast<int>(i),
880 33 : apoFirstLineValues[i].c_str());
881 : }
882 16 : CPL_IGNORE_RET_VAL(poCurLayer->CreateFeature(poFeature));
883 16 : delete poFeature;
884 : }
885 :
886 157 : if (poCurLayer)
887 : {
888 144 : if (CPLTestBool(CPLGetConfigOption("ODS_RESOLVE_FORMULAS", "YES")))
889 : {
890 144 : poCurLayer->ResetReading();
891 :
892 144 : int nRow = 0;
893 144 : OGRFeature *poFeature = poCurLayer->GetNextFeature();
894 847 : while (poFeature)
895 : {
896 4333 : for (int i = 0; i < poFeature->GetFieldCount(); i++)
897 : {
898 4691 : if (poFeature->IsFieldSetAndNotNull(i) &&
899 1061 : poFeature->GetFieldDefnRef(i)->GetType() ==
900 : OFTString)
901 : {
902 769 : const char *pszVal = poFeature->GetFieldAsString(i);
903 769 : if (STARTS_WITH(pszVal, "of:="))
904 : {
905 220 : ODSCellEvaluator oCellEvaluator(poCurLayer);
906 110 : oCellEvaluator.Evaluate(nRow, i);
907 : }
908 : }
909 : }
910 703 : delete poFeature;
911 :
912 703 : poFeature = poCurLayer->GetNextFeature();
913 703 : nRow++;
914 : }
915 : }
916 :
917 144 : poCurLayer->ResetReading();
918 :
919 144 : reinterpret_cast<OGRMemLayer *>(poCurLayer)
920 144 : ->SetUpdatable(bUpdatable);
921 144 : reinterpret_cast<OGRODSLayer *>(poCurLayer)->SetUpdated(false);
922 : }
923 :
924 157 : poCurLayer = nullptr;
925 : }
926 437 : }
927 :
928 : /************************************************************************/
929 : /* FillRepeatedCells() */
930 : /************************************************************************/
931 :
932 2631 : void OGRODSDataSource::FillRepeatedCells(bool wasLastCell)
933 : {
934 2631 : if (wasLastCell && osValue.empty() && osFormula.empty())
935 : {
936 389 : nCellsRepeated = 0;
937 389 : return;
938 : }
939 :
940 2242 : if (nCellsRepeated < 0 || nCellsRepeated > 10000)
941 : {
942 0 : CPLError(CE_Failure, CPLE_NotSupported,
943 : "Invalid value for number-columns-repeated = %d",
944 : nCellsRepeated);
945 0 : bEndTableParsing = true;
946 0 : nCellsRepeated = 0;
947 0 : return;
948 : }
949 : const int nFields =
950 2242 : nCellsRepeated + (poCurLayer != nullptr
951 2242 : ? poCurLayer->GetLayerDefn()->GetFieldCount()
952 2242 : : 0);
953 2242 : if (nFields > 0 && nRowsRepeated > 100000 / nFields)
954 : {
955 0 : CPLError(CE_Failure, CPLE_AppDefined,
956 : "Too big gap with previous valid row");
957 0 : bEndTableParsing = true;
958 0 : nCellsRepeated = 0;
959 0 : return;
960 : }
961 :
962 : // Use 16 as minimum cost for each allocation.
963 : const size_t nCellMemSize = std::max<size_t>(
964 2242 : 16, (!osValue.empty()) ? osValue.size() : osFormula.size());
965 2242 : if (nCellMemSize > static_cast<size_t>(10 * 1024 * 1024) /
966 2242 : (std::max(nCellsRepeated, 1) * nRowsRepeated))
967 : {
968 0 : CPLError(CE_Failure, CPLE_NotSupported,
969 : "Too much memory for row/cell repetition");
970 0 : bEndTableParsing = true;
971 0 : nCellsRepeated = 0;
972 0 : return;
973 : }
974 :
975 2242 : m_nAccRepeatedMemory +=
976 2242 : nCellMemSize * std::max(nCellsRepeated, 1) * nRowsRepeated;
977 2242 : if (m_nAccRepeatedMemory > static_cast<size_t>(10 * 1024 * 1024))
978 : {
979 0 : CPLError(CE_Failure, CPLE_NotSupported,
980 : "Too much accumulated memory for row/cell repetition. "
981 : "Parsing stopped");
982 0 : bEndTableParsing = true;
983 0 : nCellsRepeated = 0;
984 0 : bStopParsing = true;
985 0 : return;
986 : }
987 :
988 3926 : for (int i = 0; i < nCellsRepeated; i++)
989 : {
990 1684 : if (!osValue.empty())
991 1130 : apoCurLineValues.push_back(osValue);
992 : else
993 554 : apoCurLineValues.push_back(osFormula);
994 1684 : apoCurLineTypes.push_back(osValueType);
995 : }
996 :
997 2242 : nCurCol += nCellsRepeated;
998 2242 : nCellsRepeated = 0;
999 : }
1000 :
1001 : /************************************************************************/
1002 : /* startElementRow() */
1003 : /************************************************************************/
1004 :
1005 2009 : void OGRODSDataSource::startElementRow(const char *pszNameIn,
1006 : const char **ppszAttr)
1007 : {
1008 2009 : FillRepeatedCells(false);
1009 :
1010 2009 : if (strcmp(pszNameIn, "table:table-cell") == 0)
1011 : {
1012 1969 : PushState(STATE_CELL);
1013 :
1014 1969 : osValueType = GetAttributeValue(ppszAttr, "office:value-type", "");
1015 : const char *pszValue =
1016 1969 : GetAttributeValue(ppszAttr, "office:value", nullptr);
1017 1969 : if (pszValue)
1018 461 : osValue = pszValue;
1019 : else
1020 : {
1021 : const char *pszDateValue =
1022 1508 : GetAttributeValue(ppszAttr, "office:date-value", nullptr);
1023 1508 : if (pszDateValue)
1024 88 : osValue = pszDateValue;
1025 : else
1026 1420 : osValue = GetAttributeValue(ppszAttr, "office:time-value", "");
1027 : }
1028 :
1029 : const char *pszFormula =
1030 1969 : GetAttributeValue(ppszAttr, "table:formula", nullptr);
1031 1969 : if (pszFormula && STARTS_WITH(pszFormula, "of:="))
1032 : {
1033 148 : osFormula = pszFormula;
1034 148 : if (osFormula == "of:=TRUE()")
1035 : {
1036 1 : osValue = "1";
1037 1 : osValueType = "bool";
1038 1 : osFormula.clear();
1039 : }
1040 147 : else if (osFormula == "of:=FALSE()")
1041 : {
1042 1 : osValue = "0";
1043 1 : osValueType = "bool";
1044 1 : osFormula.clear();
1045 : }
1046 146 : else if (osValueType.empty())
1047 : {
1048 110 : osValueType = "formula";
1049 : }
1050 : }
1051 : else
1052 1821 : osFormula = "";
1053 1969 : m_bValueFromTableCellAttribute = !osValue.empty();
1054 :
1055 1969 : nCellsRepeated = atoi(
1056 : GetAttributeValue(ppszAttr, "table:number-columns-repeated", "1"));
1057 : }
1058 40 : else if (strcmp(pszNameIn, "table:covered-table-cell") == 0)
1059 : {
1060 : /* Merged cell */
1061 40 : apoCurLineValues.push_back("");
1062 40 : apoCurLineTypes.push_back("");
1063 :
1064 40 : nCurCol += 1;
1065 : }
1066 2009 : }
1067 :
1068 : /************************************************************************/
1069 : /* endElementRow() */
1070 : /************************************************************************/
1071 :
1072 662 : void OGRODSDataSource::endElementRow(
1073 : CPL_UNUSED /*in non-DEBUG*/ const char *pszNameIn)
1074 : {
1075 662 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
1076 : {
1077 622 : CPLAssert(strcmp(pszNameIn, "table:table-row") == 0);
1078 :
1079 622 : FillRepeatedCells(true);
1080 :
1081 : /* Remove blank columns at the right to defer type evaluation */
1082 : /* until necessary */
1083 622 : size_t i = apoCurLineTypes.size();
1084 834 : while (i > 0)
1085 : {
1086 727 : i--;
1087 727 : if (apoCurLineTypes[i] == "")
1088 : {
1089 212 : apoCurLineValues.resize(i);
1090 212 : apoCurLineTypes.resize(i);
1091 : }
1092 : else
1093 : {
1094 515 : break;
1095 : }
1096 : }
1097 :
1098 : /* Do not add immediately empty rows. Wait until there is another non */
1099 : /* empty row */
1100 622 : OGRFeature *poFeature = nullptr;
1101 :
1102 622 : if (nCurLine >= 2 && apoCurLineTypes.empty())
1103 : {
1104 31 : nEmptyRowsAccumulated += nRowsRepeated;
1105 31 : return;
1106 : }
1107 591 : else if (nEmptyRowsAccumulated > 0)
1108 : {
1109 150 : for (i = 0; i < (size_t)nEmptyRowsAccumulated; i++)
1110 : {
1111 135 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
1112 135 : CPL_IGNORE_RET_VAL(poCurLayer->CreateFeature(poFeature));
1113 135 : delete poFeature;
1114 : }
1115 15 : nCurLine += nEmptyRowsAccumulated;
1116 15 : nEmptyRowsAccumulated = 0;
1117 : }
1118 :
1119 : /* Backup first line values and types in special arrays */
1120 591 : if (nCurLine == 0)
1121 : {
1122 157 : apoFirstLineTypes = apoCurLineTypes;
1123 157 : apoFirstLineValues = apoCurLineValues;
1124 :
1125 : #if skip_leading_empty_rows
1126 : if (apoFirstLineTypes.empty())
1127 : {
1128 : /* Skip leading empty rows */
1129 : apoFirstLineTypes.resize(0);
1130 : apoFirstLineValues.resize(0);
1131 : return;
1132 : }
1133 : #endif
1134 : }
1135 :
1136 591 : if (nCurLine == 1)
1137 : {
1138 115 : DetectHeaderLine();
1139 :
1140 115 : poCurLayer->SetHasHeaderLine(bFirstLineIsHeaders);
1141 :
1142 115 : ReserveAndLimitFieldCount(poCurLayer, apoFirstLineValues);
1143 :
1144 115 : if (bFirstLineIsHeaders)
1145 : {
1146 222 : for (i = 0; i < apoFirstLineValues.size(); i++)
1147 : {
1148 189 : const char *pszFieldName = apoFirstLineValues[i].c_str();
1149 189 : if (pszFieldName[0] == '\0')
1150 0 : pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
1151 189 : OGRFieldType eType = OFTString;
1152 189 : OGRFieldSubType eSubType = OFSTNone;
1153 189 : if (i < apoCurLineValues.size())
1154 : {
1155 173 : eType = GetOGRFieldType(apoCurLineValues[i].c_str(),
1156 173 : apoCurLineTypes[i].c_str(),
1157 : eSubType);
1158 : }
1159 378 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
1160 189 : oFieldDefn.SetSubType(eSubType);
1161 189 : poCurLayer->CreateField(&oFieldDefn);
1162 : }
1163 : }
1164 : else
1165 : {
1166 216 : for (i = 0; i < apoFirstLineValues.size(); i++)
1167 : {
1168 : const char *pszFieldName =
1169 134 : CPLSPrintf("Field%d", (int)i + 1);
1170 134 : OGRFieldSubType eSubType = OFSTNone;
1171 : OGRFieldType eType =
1172 134 : GetOGRFieldType(apoFirstLineValues[i].c_str(),
1173 134 : apoFirstLineTypes[i].c_str(), eSubType);
1174 268 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
1175 134 : oFieldDefn.SetSubType(eSubType);
1176 134 : poCurLayer->CreateField(&oFieldDefn);
1177 : }
1178 :
1179 82 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
1180 216 : for (i = 0; i < apoFirstLineValues.size(); i++)
1181 : {
1182 134 : SetField(poFeature, static_cast<int>(i),
1183 134 : apoFirstLineValues[i].c_str());
1184 : }
1185 82 : CPL_IGNORE_RET_VAL(poCurLayer->CreateFeature(poFeature));
1186 82 : delete poFeature;
1187 : }
1188 : }
1189 :
1190 591 : if (nCurLine >= 1 || (nCurLine == 0 && nRowsRepeated > 1))
1191 : {
1192 : /* Add new fields found on following lines. */
1193 447 : if (apoCurLineValues.size() >
1194 447 : (size_t)poCurLayer->GetLayerDefn()->GetFieldCount())
1195 : {
1196 77 : GIntBig nFeatureCount = poCurLayer->GetFeatureCount(false);
1197 154 : if (nFeatureCount > 0 &&
1198 : static_cast<size_t>(
1199 77 : apoCurLineValues.size() -
1200 77 : poCurLayer->GetLayerDefn()->GetFieldCount()) >
1201 77 : static_cast<size_t>(100000 / nFeatureCount))
1202 : {
1203 0 : CPLError(CE_Failure, CPLE_NotSupported,
1204 : "Adding too many columns to too many "
1205 : "existing features");
1206 0 : bEndTableParsing = true;
1207 0 : return;
1208 : }
1209 :
1210 77 : ReserveAndLimitFieldCount(poCurLayer, apoCurLineValues);
1211 :
1212 164 : for (i = static_cast<size_t>(
1213 77 : poCurLayer->GetLayerDefn()->GetFieldCount());
1214 241 : i < apoCurLineValues.size(); i++)
1215 : {
1216 : const char *pszFieldName =
1217 164 : CPLSPrintf("Field%d", static_cast<int>(i) + 1);
1218 164 : OGRFieldSubType eSubType = OFSTNone;
1219 : const OGRFieldType eType =
1220 164 : GetOGRFieldType(apoCurLineValues[i].c_str(),
1221 164 : apoCurLineTypes[i].c_str(), eSubType);
1222 328 : OGRFieldDefn oFieldDefn(pszFieldName, eType);
1223 164 : oFieldDefn.SetSubType(eSubType);
1224 164 : poCurLayer->CreateField(&oFieldDefn);
1225 : }
1226 : }
1227 :
1228 : /* Update field type if necessary */
1229 447 : if (bAutodetectTypes)
1230 : {
1231 1421 : for (i = 0; i < apoCurLineValues.size(); i++)
1232 : {
1233 1028 : if (!apoCurLineValues[i].empty())
1234 : {
1235 818 : OGRFieldSubType eValSubType = OFSTNone;
1236 1636 : const OGRFieldType eValType = GetOGRFieldType(
1237 818 : apoCurLineValues[i].c_str(),
1238 818 : apoCurLineTypes[i].c_str(), eValSubType);
1239 818 : OGRLayer *poCurLayerAsLayer = poCurLayer;
1240 : OGRFieldDefn *poFieldDefn =
1241 818 : poCurLayerAsLayer->GetLayerDefn()->GetFieldDefn(
1242 818 : static_cast<int>(i));
1243 818 : const OGRFieldType eFieldType = poFieldDefn->GetType();
1244 818 : if (eFieldType == OFTDateTime &&
1245 26 : (eValType == OFTDate || eValType == OFTTime))
1246 : {
1247 : /* ok */
1248 : }
1249 818 : else if (eFieldType == OFTReal &&
1250 85 : (eValType == OFTInteger ||
1251 : eValType == OFTInteger64))
1252 : {
1253 : /* ok */;
1254 : }
1255 809 : else if (eFieldType == OFTInteger64 &&
1256 : eValType == OFTInteger)
1257 : {
1258 : /* ok */;
1259 : }
1260 808 : else if (eFieldType != OFTString &&
1261 : eValType != eFieldType)
1262 : {
1263 : OGRFieldDefn oNewFieldDefn(
1264 31 : poCurLayer->GetLayerDefn()->GetFieldDefn(
1265 62 : static_cast<int>(i)));
1266 31 : oNewFieldDefn.SetSubType(OFSTNone);
1267 31 : if ((eFieldType == OFTDate ||
1268 20 : eFieldType == OFTTime) &&
1269 : eValType == OFTDateTime)
1270 8 : oNewFieldDefn.SetType(OFTDateTime);
1271 23 : else if ((eFieldType == OFTInteger ||
1272 10 : eFieldType == OFTInteger64) &&
1273 : eValType == OFTReal)
1274 9 : oNewFieldDefn.SetType(OFTReal);
1275 14 : else if (eFieldType == OFTInteger &&
1276 : eValType == OFTInteger64)
1277 1 : oNewFieldDefn.SetType(OFTInteger64);
1278 : else
1279 13 : oNewFieldDefn.SetType(OFTString);
1280 31 : poCurLayer->AlterFieldDefn(static_cast<int>(i),
1281 : &oNewFieldDefn,
1282 31 : ALTER_TYPE_FLAG);
1283 : }
1284 107 : else if (eFieldType == OFTInteger &&
1285 108 : poFieldDefn->GetSubType() == OFSTBoolean &&
1286 884 : eValType == OFTInteger &&
1287 1 : eValSubType != OFSTBoolean)
1288 : {
1289 0 : whileUnsealing(poFieldDefn)->SetSubType(OFSTNone);
1290 : }
1291 : }
1292 : }
1293 : }
1294 :
1295 : /* Add feature for current line */
1296 917 : for (int j = 0; j < nRowsRepeated; j++)
1297 : {
1298 470 : poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
1299 1636 : for (i = 0; i < apoCurLineValues.size(); i++)
1300 : {
1301 1166 : SetField(poFeature, static_cast<int>(i),
1302 1166 : apoCurLineValues[i].c_str());
1303 : }
1304 470 : CPL_IGNORE_RET_VAL(poCurLayer->CreateFeature(poFeature));
1305 470 : delete poFeature;
1306 : }
1307 : }
1308 :
1309 591 : nCurLine += nRowsRepeated;
1310 : }
1311 : }
1312 :
1313 : /************************************************************************/
1314 : /* startElementCell() */
1315 : /************************************************************************/
1316 :
1317 1055 : void OGRODSDataSource::startElementCell(const char *pszNameIn,
1318 : const char ** /*ppszAttr*/)
1319 : {
1320 1055 : if (!m_bValueFromTableCellAttribute && strcmp(pszNameIn, "text:p") == 0)
1321 : {
1322 567 : if (!osValue.empty())
1323 1 : osValue += '\n';
1324 567 : PushState(STATE_TEXTP);
1325 : }
1326 1055 : }
1327 :
1328 : /************************************************************************/
1329 : /* endElementCell() */
1330 : /************************************************************************/
1331 :
1332 2457 : void OGRODSDataSource::endElementCell(
1333 : CPL_UNUSED /*in non-DEBUG*/ const char *pszNameIn)
1334 : {
1335 2457 : if (stateStack[nStackDepth].nBeginDepth == nDepth)
1336 : {
1337 1969 : CPLAssert(strcmp(pszNameIn, "table:table-cell") == 0);
1338 : }
1339 2457 : }
1340 :
1341 : /************************************************************************/
1342 : /* dataHandlerTextP() */
1343 : /************************************************************************/
1344 :
1345 612 : void OGRODSDataSource::dataHandlerTextP(const char *data, int nLen)
1346 : {
1347 612 : osValue.append(data, nLen);
1348 612 : }
1349 :
1350 : /************************************************************************/
1351 : /* AnalyseFile() */
1352 : /************************************************************************/
1353 :
1354 2003 : void OGRODSDataSource::AnalyseFile()
1355 : {
1356 2003 : if (bAnalysedFile)
1357 1964 : return;
1358 :
1359 39 : bAnalysedFile = true;
1360 :
1361 39 : AnalyseSettings();
1362 :
1363 39 : oParser = OGRCreateExpatXMLParser();
1364 39 : XML_SetElementHandler(oParser, OGRODS::startElementCbk,
1365 : OGRODS::endElementCbk);
1366 39 : XML_SetCharacterDataHandler(oParser, OGRODS::dataHandlerCbk);
1367 39 : XML_SetUserData(oParser, this);
1368 :
1369 39 : nDepth = 0;
1370 39 : nStackDepth = 0;
1371 39 : stateStack[0].nBeginDepth = 0;
1372 39 : bStopParsing = false;
1373 39 : nWithoutEventCounter = 0;
1374 :
1375 39 : VSIFSeekL(fpContent, 0, SEEK_SET);
1376 :
1377 39 : std::vector<char> aBuf(PARSER_BUF_SIZE);
1378 39 : int nDone = 0;
1379 31 : do
1380 : {
1381 70 : nDataHandlerCounter = 0;
1382 : unsigned int nLen = static_cast<unsigned int>(
1383 70 : VSIFReadL(aBuf.data(), 1, aBuf.size(), fpContent));
1384 70 : nDone = (nLen < aBuf.size());
1385 70 : if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
1386 : {
1387 0 : CPLError(CE_Failure, CPLE_AppDefined,
1388 : "XML parsing of ODS file failed : %s at line %d, "
1389 : "column %d",
1390 : XML_ErrorString(XML_GetErrorCode(oParser)),
1391 0 : static_cast<int>(XML_GetCurrentLineNumber(oParser)),
1392 0 : static_cast<int>(XML_GetCurrentColumnNumber(oParser)));
1393 0 : bStopParsing = true;
1394 : }
1395 70 : nWithoutEventCounter++;
1396 70 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1397 :
1398 39 : XML_ParserFree(oParser);
1399 39 : oParser = nullptr;
1400 :
1401 39 : if (nWithoutEventCounter == 10)
1402 : {
1403 0 : CPLError(CE_Failure, CPLE_AppDefined,
1404 : "Too much data inside one element. File probably corrupted");
1405 0 : bStopParsing = true;
1406 : }
1407 :
1408 39 : VSIFCloseL(fpContent);
1409 39 : fpContent = nullptr;
1410 :
1411 39 : bUpdated = false;
1412 : }
1413 :
1414 : /************************************************************************/
1415 : /* startElementStylesCbk() */
1416 : /************************************************************************/
1417 :
1418 3016 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
1419 : const char **ppszAttr)
1420 : {
1421 3016 : static_cast<OGRODSDataSource *>(pUserData)->startElementStylesCbk(pszName,
1422 : ppszAttr);
1423 3016 : }
1424 :
1425 3016 : void OGRODSDataSource::startElementStylesCbk(const char *pszNameIn,
1426 : const char **ppszAttr)
1427 : {
1428 3016 : if (bStopParsing)
1429 0 : return;
1430 :
1431 3016 : nWithoutEventCounter = 0;
1432 :
1433 7057 : if (nStackDepth == 0 &&
1434 3054 : strcmp(pszNameIn, "config:config-item-map-named") == 0 &&
1435 38 : strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
1436 : {
1437 37 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1438 : }
1439 2979 : else if (nStackDepth == 1 &&
1440 138 : strcmp(pszNameIn, "config:config-item-map-entry") == 0)
1441 : {
1442 : const char *pszTableName =
1443 138 : GetAttributeValue(ppszAttr, "config:name", nullptr);
1444 138 : if (pszTableName)
1445 : {
1446 138 : osCurrentConfigTableName = pszTableName;
1447 138 : nVerticalSplitFlags = 0;
1448 138 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1449 138 : }
1450 : }
1451 2841 : else if (nStackDepth == 2 && strcmp(pszNameIn, "config:config-item") == 0)
1452 : {
1453 : const char *pszConfigName =
1454 1853 : GetAttributeValue(ppszAttr, "config:name", nullptr);
1455 1853 : if (pszConfigName)
1456 : {
1457 1853 : osConfigName = pszConfigName;
1458 1853 : osValue = "";
1459 1853 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1460 : }
1461 : }
1462 :
1463 3016 : nDepth++;
1464 : }
1465 :
1466 : /************************************************************************/
1467 : /* endElementStylesCbk() */
1468 : /************************************************************************/
1469 :
1470 3016 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
1471 : {
1472 3016 : static_cast<OGRODSDataSource *>(pUserData)->endElementStylesCbk(pszName);
1473 3016 : }
1474 :
1475 3016 : void OGRODSDataSource::endElementStylesCbk(const char * /*pszName*/)
1476 : {
1477 3016 : if (bStopParsing)
1478 0 : return;
1479 :
1480 3016 : nWithoutEventCounter = 0;
1481 3016 : nDepth--;
1482 :
1483 3016 : if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
1484 : {
1485 2028 : if (nStackDepth == 2)
1486 : {
1487 138 : if (nVerticalSplitFlags == (1 | 2))
1488 20 : osSetLayerHasSplitter.insert(osCurrentConfigTableName);
1489 : }
1490 2028 : if (nStackDepth == 3)
1491 : {
1492 1853 : if (osConfigName == "VerticalSplitMode" && osValue == "2")
1493 20 : nVerticalSplitFlags |= 1;
1494 1833 : else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
1495 20 : nVerticalSplitFlags |= 2;
1496 : }
1497 2028 : nStackDepth--;
1498 : }
1499 : }
1500 :
1501 : /************************************************************************/
1502 : /* dataHandlerStylesCbk() */
1503 : /************************************************************************/
1504 :
1505 3249 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data,
1506 : int nLen)
1507 : {
1508 3249 : static_cast<OGRODSDataSource *>(pUserData)->dataHandlerStylesCbk(data,
1509 : nLen);
1510 3249 : }
1511 :
1512 3249 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
1513 : {
1514 3249 : if (bStopParsing)
1515 0 : return;
1516 :
1517 3249 : nDataHandlerCounter++;
1518 3249 : if (nDataHandlerCounter >= PARSER_BUF_SIZE)
1519 : {
1520 0 : CPLError(CE_Failure, CPLE_AppDefined,
1521 : "File probably corrupted (million laugh pattern)");
1522 0 : XML_StopParser(oParser, XML_FALSE);
1523 0 : bStopParsing = true;
1524 0 : return;
1525 : }
1526 :
1527 3249 : nWithoutEventCounter = 0;
1528 :
1529 3249 : if (nStackDepth == 3)
1530 : {
1531 1853 : osValue.append(data, nLen);
1532 : }
1533 : }
1534 :
1535 : /************************************************************************/
1536 : /* AnalyseSettings() */
1537 : /* */
1538 : /* We parse settings.xml to see which layers have a vertical splitter */
1539 : /* on the first line, so as to use it as the header line. */
1540 : /************************************************************************/
1541 :
1542 39 : void OGRODSDataSource::AnalyseSettings()
1543 : {
1544 39 : if (fpSettings == nullptr)
1545 2 : return;
1546 :
1547 37 : oParser = OGRCreateExpatXMLParser();
1548 37 : XML_SetElementHandler(oParser, OGRODS::startElementStylesCbk,
1549 : OGRODS::endElementStylesCbk);
1550 37 : XML_SetCharacterDataHandler(oParser, OGRODS::dataHandlerStylesCbk);
1551 37 : XML_SetUserData(oParser, this);
1552 :
1553 37 : nDepth = 0;
1554 37 : nStackDepth = 0;
1555 37 : bStopParsing = false;
1556 37 : nWithoutEventCounter = 0;
1557 :
1558 37 : VSIFSeekL(fpSettings, 0, SEEK_SET);
1559 :
1560 37 : std::vector<char> aBuf(PARSER_BUF_SIZE);
1561 37 : int nDone = 0;
1562 26 : do
1563 : {
1564 63 : nDataHandlerCounter = 0;
1565 : unsigned int nLen =
1566 63 : (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSettings);
1567 63 : nDone = (nLen < aBuf.size());
1568 63 : if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
1569 : {
1570 0 : CPLError(CE_Failure, CPLE_AppDefined,
1571 : "XML parsing of styles.xml file failed : %s at line %d, "
1572 : "column %d",
1573 : XML_ErrorString(XML_GetErrorCode(oParser)),
1574 0 : (int)XML_GetCurrentLineNumber(oParser),
1575 0 : (int)XML_GetCurrentColumnNumber(oParser));
1576 0 : bStopParsing = true;
1577 : }
1578 63 : nWithoutEventCounter++;
1579 63 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1580 :
1581 37 : XML_ParserFree(oParser);
1582 37 : oParser = nullptr;
1583 :
1584 37 : if (nWithoutEventCounter == 10)
1585 : {
1586 0 : CPLError(CE_Failure, CPLE_AppDefined,
1587 : "Too much data inside one element. File probably corrupted");
1588 0 : bStopParsing = true;
1589 : }
1590 :
1591 37 : VSIFCloseL(fpSettings);
1592 37 : fpSettings = nullptr;
1593 : }
1594 :
1595 : /************************************************************************/
1596 : /* ICreateLayer() */
1597 : /************************************************************************/
1598 :
1599 : OGRLayer *
1600 61 : OGRODSDataSource::ICreateLayer(const char *pszLayerName,
1601 : const OGRGeomFieldDefn * /*poGeomFieldDefn*/,
1602 : CSLConstList papszOptions)
1603 : {
1604 : /* -------------------------------------------------------------------- */
1605 : /* Verify we are in update mode. */
1606 : /* -------------------------------------------------------------------- */
1607 61 : if (!bUpdatable)
1608 : {
1609 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1610 : "Data source %s opened read-only.\n"
1611 : "New layer %s cannot be created.\n",
1612 : pszName, pszLayerName);
1613 :
1614 0 : return nullptr;
1615 : }
1616 :
1617 61 : AnalyseFile();
1618 :
1619 : /* -------------------------------------------------------------------- */
1620 : /* Do we already have this layer? If so, should we blow it */
1621 : /* away? */
1622 : /* -------------------------------------------------------------------- */
1623 105 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1624 : {
1625 44 : if (EQUAL(pszLayerName, papoLayers[iLayer]->GetName()))
1626 : {
1627 0 : if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
1628 0 : !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
1629 : {
1630 0 : DeleteLayer(pszLayerName);
1631 : }
1632 : else
1633 : {
1634 0 : CPLError(CE_Failure, CPLE_AppDefined,
1635 : "Layer %s already exists, CreateLayer failed.\n"
1636 : "Use the layer creation option OVERWRITE=YES to "
1637 : "replace it.",
1638 : pszLayerName);
1639 0 : return nullptr;
1640 : }
1641 : }
1642 : }
1643 :
1644 : /* -------------------------------------------------------------------- */
1645 : /* Create the layer object. */
1646 : /* -------------------------------------------------------------------- */
1647 61 : OGRLayer *poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
1648 :
1649 61 : papoLayers = static_cast<OGRLayer **>(
1650 61 : CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer *)));
1651 61 : papoLayers[nLayers] = poLayer;
1652 61 : nLayers++;
1653 :
1654 61 : bUpdated = true;
1655 :
1656 61 : return poLayer;
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* DeleteLayer() */
1661 : /************************************************************************/
1662 :
1663 0 : void OGRODSDataSource::DeleteLayer(const char *pszLayerName)
1664 :
1665 : {
1666 : /* -------------------------------------------------------------------- */
1667 : /* Verify we are in update mode. */
1668 : /* -------------------------------------------------------------------- */
1669 0 : if (!bUpdatable)
1670 : {
1671 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1672 : "Data source %s opened read-only.\n"
1673 : "Layer %s cannot be deleted.\n",
1674 : pszName, pszLayerName);
1675 :
1676 0 : return;
1677 : }
1678 :
1679 : /* -------------------------------------------------------------------- */
1680 : /* Try to find layer. */
1681 : /* -------------------------------------------------------------------- */
1682 0 : int iLayer = 0;
1683 0 : for (; iLayer < nLayers; iLayer++)
1684 : {
1685 0 : if (EQUAL(pszLayerName, papoLayers[iLayer]->GetName()))
1686 0 : break;
1687 : }
1688 :
1689 0 : if (iLayer == nLayers)
1690 : {
1691 0 : CPLError(
1692 : CE_Failure, CPLE_AppDefined,
1693 : "Attempt to delete layer '%s', but this layer is not known to OGR.",
1694 : pszLayerName);
1695 0 : return;
1696 : }
1697 :
1698 0 : DeleteLayer(iLayer);
1699 : }
1700 :
1701 : /************************************************************************/
1702 : /* DeleteLayer() */
1703 : /************************************************************************/
1704 :
1705 16 : OGRErr OGRODSDataSource::DeleteLayer(int iLayer)
1706 : {
1707 16 : AnalyseFile();
1708 :
1709 16 : if (iLayer < 0 || iLayer >= nLayers)
1710 : {
1711 0 : CPLError(CE_Failure, CPLE_AppDefined,
1712 : "Layer %d not in legal range of 0 to %d.", iLayer,
1713 0 : nLayers - 1);
1714 0 : return OGRERR_FAILURE;
1715 : }
1716 :
1717 : /* -------------------------------------------------------------------- */
1718 : /* Blow away our OGR structures related to the layer. This is */
1719 : /* pretty dangerous if anything has a reference to this layer! */
1720 : /* -------------------------------------------------------------------- */
1721 :
1722 16 : delete papoLayers[iLayer];
1723 16 : memmove(papoLayers + iLayer, papoLayers + iLayer + 1,
1724 16 : sizeof(void *) * (nLayers - iLayer - 1));
1725 16 : nLayers--;
1726 :
1727 16 : bUpdated = true;
1728 :
1729 16 : return OGRERR_NONE;
1730 : }
1731 :
1732 : /************************************************************************/
1733 : /* HasHeaderLine() */
1734 : /************************************************************************/
1735 :
1736 106 : static bool HasHeaderLine(OGRLayer *poLayer)
1737 : {
1738 106 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
1739 106 : bool bHasHeaders = false;
1740 :
1741 280 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1742 : {
1743 174 : if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
1744 174 : CPLSPrintf("Field%d", j + 1)) != 0)
1745 92 : bHasHeaders = true;
1746 : }
1747 :
1748 106 : return bHasHeaders;
1749 : }
1750 :
1751 : /************************************************************************/
1752 : /* WriteLayer() */
1753 : /************************************************************************/
1754 :
1755 53 : static void WriteLayer(VSILFILE *fp, OGRLayer *poLayer)
1756 : {
1757 53 : const char *pszLayerName = poLayer->GetName();
1758 53 : char *pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
1759 53 : VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
1760 53 : CPLFree(pszXML);
1761 :
1762 53 : poLayer->ResetReading();
1763 :
1764 53 : OGRFeature *poFeature = poLayer->GetNextFeature();
1765 :
1766 53 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
1767 53 : const bool bHasHeaders = HasHeaderLine(poLayer);
1768 :
1769 140 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1770 : {
1771 87 : int nStyleNumber = 1;
1772 87 : if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
1773 9 : nStyleNumber = 2;
1774 87 : VSIFPrintfL(fp,
1775 : "<table:table-column table:style-name=\"co%d\" "
1776 : "table:default-cell-style-name=\"Default\"/>\n",
1777 : nStyleNumber);
1778 : }
1779 :
1780 53 : if (bHasHeaders && poFeature != nullptr)
1781 : {
1782 20 : VSIFPrintfL(fp, "<table:table-row>\n");
1783 66 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1784 : {
1785 46 : const char *pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
1786 :
1787 46 : VSIFPrintfL(fp,
1788 : "<table:table-cell office:value-type=\"string\">\n");
1789 46 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1790 46 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1791 46 : CPLFree(pszXML);
1792 46 : VSIFPrintfL(fp, "</table:table-cell>\n");
1793 : }
1794 20 : VSIFPrintfL(fp, "</table:table-row>\n");
1795 : }
1796 :
1797 181 : while (poFeature != nullptr)
1798 : {
1799 128 : VSIFPrintfL(fp, "<table:table-row>\n");
1800 636 : for (int j = 0; j < poFeature->GetFieldCount(); j++)
1801 : {
1802 508 : if (poFeature->IsFieldSetAndNotNull(j))
1803 : {
1804 178 : OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(j);
1805 178 : const OGRFieldType eType = poFieldDefn->GetType();
1806 :
1807 178 : if (eType == OFTReal)
1808 : {
1809 36 : VSIFPrintfL(fp,
1810 : "<table:table-cell office:value-type=\"float\" "
1811 : "office:value=\"%.16f\"/>\n",
1812 : poFeature->GetFieldAsDouble(j));
1813 : }
1814 142 : else if (eType == OFTInteger)
1815 : {
1816 24 : const int nVal = poFeature->GetFieldAsInteger(j);
1817 24 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1818 : {
1819 2 : VSIFPrintfL(fp,
1820 : "<table:table-cell "
1821 : "table:formula=\"of:=%s()\" "
1822 : "office:value-type=\"float\" "
1823 : "office:value=\"%d\"/>\n",
1824 : nVal ? "TRUE" : "FALSE", nVal);
1825 : }
1826 : else
1827 : {
1828 22 : VSIFPrintfL(
1829 : fp,
1830 : "<table:table-cell office:value-type=\"float\" "
1831 : "office:value=\"%d\"/>\n",
1832 : nVal);
1833 : }
1834 : }
1835 118 : else if (eType == OFTInteger64)
1836 : {
1837 13 : VSIFPrintfL(fp,
1838 : "<table:table-cell office:value-type=\"float\" "
1839 : "office:value=\"" CPL_FRMT_GIB "\"/>\n",
1840 : poFeature->GetFieldAsInteger64(j));
1841 : }
1842 105 : else if (eType == OFTDateTime)
1843 : {
1844 11 : int nYear = 0;
1845 11 : int nMonth = 0;
1846 11 : int nDay = 0;
1847 11 : int nHour = 0;
1848 11 : int nMinute = 0;
1849 11 : int nTZFlag = 0;
1850 11 : float fSecond = 0.0f;
1851 11 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1852 : &nHour, &nMinute, &fSecond,
1853 : &nTZFlag);
1854 11 : if (OGR_GET_MS(fSecond))
1855 : {
1856 1 : VSIFPrintfL(
1857 : fp,
1858 : "<table:table-cell "
1859 : "table:style-name=\"stDateTimeMilliseconds\" "
1860 : "office:value-type=\"date\" "
1861 : "office:date-value="
1862 : "\"%04d-%02d-%02dT%02d:%02d:%06.3f\">\n",
1863 : nYear, nMonth, nDay, nHour, nMinute, fSecond);
1864 1 : VSIFPrintfL(fp,
1865 : "<text:p>%02d/%02d/%04d "
1866 : "%02d:%02d:%06.3f</text:p>\n",
1867 : nDay, nMonth, nYear, nHour, nMinute,
1868 : fSecond);
1869 : }
1870 : else
1871 : {
1872 10 : VSIFPrintfL(fp,
1873 : "<table:table-cell "
1874 : "table:style-name=\"stDateTime\" "
1875 : "office:value-type=\"date\" "
1876 : "office:date-value="
1877 : "\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
1878 : nYear, nMonth, nDay, nHour, nMinute,
1879 : static_cast<int>(fSecond));
1880 10 : VSIFPrintfL(
1881 : fp,
1882 : "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
1883 : nDay, nMonth, nYear, nHour, nMinute,
1884 : static_cast<int>(fSecond));
1885 : }
1886 11 : VSIFPrintfL(fp, "</table:table-cell>\n");
1887 : }
1888 94 : else if (eType == OFTDate)
1889 : {
1890 2 : int nYear = 0;
1891 2 : int nMonth = 0;
1892 2 : int nDay = 0;
1893 2 : int nHour = 0;
1894 2 : int nMinute = 0;
1895 2 : int nSecond = 0;
1896 2 : int nTZFlag = 0;
1897 2 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1898 : &nHour, &nMinute, &nSecond,
1899 : &nTZFlag);
1900 2 : VSIFPrintfL(fp,
1901 : "<table:table-cell table:style-name=\"stDate\" "
1902 : "office:value-type=\"date\" "
1903 : "office:date-value=\"%04d-%02d-%02d\">\n",
1904 : nYear, nMonth, nDay);
1905 2 : VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d</text:p>\n", nDay,
1906 : nMonth, nYear);
1907 2 : VSIFPrintfL(fp, "</table:table-cell>\n");
1908 : }
1909 92 : else if (eType == OFTTime)
1910 : {
1911 2 : int nYear = 0;
1912 2 : int nMonth = 0;
1913 2 : int nDay = 0;
1914 2 : int nHour = 0;
1915 2 : int nMinute = 0;
1916 2 : int nSecond = 0;
1917 2 : int nTZFlag = 0;
1918 2 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1919 : &nHour, &nMinute, &nSecond,
1920 : &nTZFlag);
1921 2 : VSIFPrintfL(fp,
1922 : "<table:table-cell table:style-name=\"stTime\" "
1923 : "office:value-type=\"time\" "
1924 : "office:time-value=\"PT%02dH%02dM%02dS\">\n",
1925 : nHour, nMinute, nSecond);
1926 2 : VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n", nHour,
1927 : nMinute, nSecond);
1928 2 : VSIFPrintfL(fp, "</table:table-cell>\n");
1929 : }
1930 : else
1931 : {
1932 90 : const char *pszVal = poFeature->GetFieldAsString(j);
1933 90 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1934 90 : if (STARTS_WITH(pszVal, "of:="))
1935 : {
1936 0 : VSIFPrintfL(
1937 : fp, "<table:table-cell table:formula=\"%s\"/>\n",
1938 : pszXML);
1939 : }
1940 : else
1941 : {
1942 90 : VSIFPrintfL(fp, "<table:table-cell "
1943 : "office:value-type=\"string\">\n");
1944 90 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1945 90 : VSIFPrintfL(fp, "</table:table-cell>\n");
1946 : }
1947 90 : CPLFree(pszXML);
1948 : }
1949 : }
1950 : else
1951 : {
1952 330 : VSIFPrintfL(fp, "<table:table-cell/>\n");
1953 : }
1954 : }
1955 128 : VSIFPrintfL(fp, "</table:table-row>\n");
1956 :
1957 128 : delete poFeature;
1958 128 : poFeature = poLayer->GetNextFeature();
1959 : }
1960 :
1961 53 : VSIFPrintfL(fp, "</table:table>\n");
1962 53 : }
1963 :
1964 : /************************************************************************/
1965 : /* FlushCache() */
1966 : /************************************************************************/
1967 :
1968 113 : CPLErr OGRODSDataSource::FlushCache(bool /* bAtClosing */)
1969 : {
1970 113 : if (!bUpdated)
1971 73 : return CE_None;
1972 :
1973 40 : CPLAssert(fpSettings == nullptr);
1974 40 : CPLAssert(fpContent == nullptr);
1975 :
1976 : VSIStatBufL sStat;
1977 40 : if (VSIStatL(pszName, &sStat) == 0)
1978 : {
1979 2 : if (VSIUnlink(pszName) != 0)
1980 : {
1981 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s", pszName);
1982 0 : return CE_Failure;
1983 : }
1984 : }
1985 :
1986 80 : CPLConfigOptionSetter oZip64Disable("CPL_CREATE_ZIP64", "NO", false);
1987 :
1988 : /* Maintain new ZIP files opened */
1989 40 : void *hZIP = CPLCreateZip(pszName, nullptr);
1990 40 : if (!hZIP)
1991 : {
1992 1 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s", pszName,
1993 : VSIGetLastErrorMsg());
1994 1 : return CE_Failure;
1995 : }
1996 :
1997 : /* Write uncompressed mimetype */
1998 39 : char **papszOptions = CSLAddString(nullptr, "COMPRESSED=NO");
1999 39 : if (CPLCreateFileInZip(hZIP, "mimetype", papszOptions) != CE_None)
2000 : {
2001 0 : CSLDestroy(papszOptions);
2002 0 : CPLCloseZip(hZIP);
2003 0 : return CE_Failure;
2004 : }
2005 39 : CSLDestroy(papszOptions);
2006 39 : if (CPLWriteFileInZip(
2007 : hZIP, "application/vnd.oasis.opendocument.spreadsheet",
2008 : static_cast<int>(strlen(
2009 39 : "application/vnd.oasis.opendocument.spreadsheet"))) != CE_None)
2010 : {
2011 0 : CPLCloseZip(hZIP);
2012 0 : return CE_Failure;
2013 : }
2014 39 : CPLCloseFileInZip(hZIP);
2015 :
2016 : /* Now close ZIP file */
2017 39 : CPLCloseZip(hZIP);
2018 39 : hZIP = nullptr;
2019 :
2020 : /* Re-open with VSILFILE */
2021 78 : CPLString osTmpFilename(CPLSPrintf("/vsizip/%s", pszName));
2022 39 : VSILFILE *fpZIP = VSIFOpenL(osTmpFilename, "ab");
2023 39 : if (fpZIP == nullptr)
2024 0 : return CE_Failure;
2025 :
2026 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName);
2027 39 : VSILFILE *fp = VSIFOpenL(osTmpFilename, "wb");
2028 39 : if (!fp)
2029 : {
2030 0 : VSIFCloseL(fpZIP);
2031 0 : return CE_Failure;
2032 : }
2033 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2034 39 : VSIFPrintfL(fp, "<manifest:manifest "
2035 : "xmlns:manifest=\"urn:oasis:names:tc:"
2036 : "opendocument:xmlns:manifest:1.0\">\n");
2037 39 : VSIFPrintfL(fp, "<manifest:file-entry "
2038 : "manifest:media-type=\"application/vnd.oasis."
2039 : "opendocument.spreadsheet\" "
2040 : "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
2041 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2042 : "manifest:full-path=\"content.xml\"/>\n");
2043 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2044 : "manifest:full-path=\"styles.xml\"/>\n");
2045 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2046 : "manifest:full-path=\"meta.xml\"/>\n");
2047 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2048 : "manifest:full-path=\"settings.xml\"/>\n");
2049 39 : VSIFPrintfL(fp, "</manifest:manifest>\n");
2050 39 : VSIFCloseL(fp);
2051 :
2052 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/meta.xml", pszName);
2053 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2054 39 : if (!fp)
2055 : {
2056 0 : VSIFCloseL(fpZIP);
2057 0 : return CE_Failure;
2058 : }
2059 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2060 39 : VSIFPrintfL(
2061 : fp, "<office:document-meta "
2062 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2063 : "office:version=\"1.2\">\n");
2064 39 : VSIFPrintfL(fp, "</office:document-meta>\n");
2065 39 : VSIFCloseL(fp);
2066 :
2067 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/settings.xml", pszName);
2068 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2069 39 : if (!fp)
2070 : {
2071 0 : VSIFCloseL(fpZIP);
2072 0 : return CE_Failure;
2073 : }
2074 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2075 39 : VSIFPrintfL(
2076 : fp, "<office:document-settings "
2077 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2078 : "xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" "
2079 : "xmlns:ooo=\"http://openoffice.org/2004/office\" "
2080 : "office:version=\"1.2\">\n");
2081 39 : VSIFPrintfL(fp, "<office:settings>\n");
2082 39 : VSIFPrintfL(fp,
2083 : "<config:config-item-set config:name=\"ooo:view-settings\">\n");
2084 39 : VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
2085 39 : VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
2086 39 : VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
2087 92 : for (int i = 0; i < nLayers; i++)
2088 : {
2089 53 : OGRLayer *poLayer = papoLayers[i];
2090 53 : if (HasHeaderLine(poLayer))
2091 : {
2092 : /* Add vertical splitter */
2093 20 : char *pszXML = OGRGetXML_UTF8_EscapedString(poLayer->GetName());
2094 20 : VSIFPrintfL(fp,
2095 : "<config:config-item-map-entry config:name=\"%s\">\n",
2096 : pszXML);
2097 20 : CPLFree(pszXML);
2098 20 : VSIFPrintfL(fp,
2099 : "<config:config-item config:name=\"VerticalSplitMode\" "
2100 : "config:type=\"short\">2</config:config-item>\n");
2101 20 : VSIFPrintfL(
2102 : fp, "<config:config-item config:name=\"VerticalSplitPosition\" "
2103 : "config:type=\"int\">1</config:config-item>\n");
2104 20 : VSIFPrintfL(fp,
2105 : "<config:config-item config:name=\"ActiveSplitRange\" "
2106 : "config:type=\"short\">2</config:config-item>\n");
2107 20 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" "
2108 : "config:type=\"int\">0</config:config-item>\n");
2109 20 : VSIFPrintfL(fp,
2110 : "<config:config-item config:name=\"PositionBottom\" "
2111 : "config:type=\"int\">1</config:config-item>\n");
2112 20 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
2113 : }
2114 : }
2115 39 : VSIFPrintfL(fp, "</config:config-item-map-named>\n");
2116 39 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
2117 39 : VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
2118 39 : VSIFPrintfL(fp, "</config:config-item-set>\n");
2119 39 : VSIFPrintfL(fp, "</office:settings>\n");
2120 39 : VSIFPrintfL(fp, "</office:document-settings>\n");
2121 39 : VSIFCloseL(fp);
2122 :
2123 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/styles.xml", pszName);
2124 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2125 39 : if (!fp)
2126 : {
2127 0 : VSIFCloseL(fpZIP);
2128 0 : return CE_Failure;
2129 : }
2130 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2131 39 : VSIFPrintfL(
2132 : fp, "<office:document-styles "
2133 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2134 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
2135 : "office:version=\"1.2\">\n");
2136 39 : VSIFPrintfL(fp, "<office:styles>\n");
2137 39 : VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
2138 : "style:family=\"table-cell\">\n");
2139 39 : VSIFPrintfL(fp, "</style:style>\n");
2140 39 : VSIFPrintfL(fp, "</office:styles>\n");
2141 39 : VSIFPrintfL(fp, "</office:document-styles>\n");
2142 39 : VSIFCloseL(fp);
2143 :
2144 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/content.xml", pszName);
2145 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2146 39 : if (!fp)
2147 : {
2148 0 : VSIFCloseL(fpZIP);
2149 0 : return CE_Failure;
2150 : }
2151 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2152 39 : VSIFPrintfL(
2153 : fp,
2154 : "<office:document-content "
2155 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2156 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
2157 : "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "
2158 : "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" "
2159 : "xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" "
2160 : "xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:"
2161 : "xsl-fo-compatible:1.0\" "
2162 : "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" "
2163 : "office:version=\"1.2\">\n");
2164 39 : VSIFPrintfL(fp, "<office:scripts/>\n");
2165 39 : VSIFPrintfL(fp, "<office:automatic-styles>\n");
2166 39 : VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
2167 : "style:family=\"table-column\">\n");
2168 39 : VSIFPrintfL(fp, "<style:table-column-properties "
2169 : "fo:break-before=\"auto\" "
2170 : "style:column-width=\"2.5cm\"/>\n");
2171 39 : VSIFPrintfL(fp, "</style:style>\n");
2172 39 : VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
2173 : "style:family=\"table-column\">\n");
2174 39 : VSIFPrintfL(fp, "<style:table-column-properties "
2175 : "fo:break-before=\"auto\" "
2176 : "style:column-width=\"5cm\"/>\n");
2177 39 : VSIFPrintfL(fp, "</style:style>\n");
2178 39 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
2179 : "number:automatic-order=\"true\">\n");
2180 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2181 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2182 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2183 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2184 39 : VSIFPrintfL(fp, "<number:year/>\n");
2185 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2186 39 : VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
2187 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2188 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2189 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2190 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2191 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
2192 39 : VSIFPrintfL(fp, "</number:time-style>\n");
2193 39 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
2194 : "number:automatic-order=\"true\">\n");
2195 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2196 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2197 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2198 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2199 39 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
2200 39 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
2201 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2202 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2203 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2204 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2205 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
2206 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2207 39 : VSIFPrintfL(fp,
2208 : "<number:date-style style:name=\"nDateTimeMilliseconds\">\n");
2209 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2210 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2211 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2212 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2213 39 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
2214 39 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
2215 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2216 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2217 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2218 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2219 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\" "
2220 : "number:decimal-places=\"3\"/>\n");
2221 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2222 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDate\" "
2223 : "style:family=\"table-cell\" "
2224 : "style:parent-style-name=\"Default\" "
2225 : "style:data-style-name=\"nDate\"/>\n");
2226 39 : VSIFPrintfL(fp, "<style:style style:name=\"stTime\" "
2227 : "style:family=\"table-cell\" "
2228 : "style:parent-style-name=\"Default\" "
2229 : "style:data-style-name=\"nTime\"/>\n");
2230 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDateTime\" "
2231 : "style:family=\"table-cell\" "
2232 : "style:parent-style-name=\"Default\" "
2233 : "style:data-style-name=\"nDateTime\"/>\n");
2234 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDateTimeMilliseconds\" "
2235 : "style:family=\"table-cell\" "
2236 : "style:parent-style-name=\"Default\" "
2237 : "style:data-style-name=\"nDateTimeMilliseconds\"/>\n");
2238 39 : VSIFPrintfL(fp, "</office:automatic-styles>\n");
2239 39 : VSIFPrintfL(fp, "<office:body>\n");
2240 39 : VSIFPrintfL(fp, "<office:spreadsheet>\n");
2241 92 : for (int i = 0; i < nLayers; i++)
2242 : {
2243 53 : WriteLayer(fp, papoLayers[i]);
2244 : }
2245 39 : VSIFPrintfL(fp, "</office:spreadsheet>\n");
2246 39 : VSIFPrintfL(fp, "</office:body>\n");
2247 39 : VSIFPrintfL(fp, "</office:document-content>\n");
2248 39 : VSIFCloseL(fp);
2249 :
2250 : /* Now close ZIP file */
2251 39 : VSIFCloseL(fpZIP);
2252 :
2253 : /* Reset updated flag at datasource and layer level */
2254 39 : bUpdated = false;
2255 92 : for (int i = 0; i < nLayers; i++)
2256 : {
2257 53 : reinterpret_cast<OGRODSLayer *>(papoLayers[i])->SetUpdated(false);
2258 : }
2259 :
2260 39 : return CE_None;
2261 : }
2262 :
2263 : /************************************************************************/
2264 : /* EvaluateRange() */
2265 : /************************************************************************/
2266 :
2267 25 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
2268 : std::vector<ods_formula_node> &aoOutValues)
2269 : {
2270 50 : if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) || nCol1 < 0 ||
2271 25 : nCol1 >= poLayer->GetLayerDefn()->GetFieldCount())
2272 : {
2273 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid cell (row=%d, col=%d)",
2274 : nRow1 + 1, nCol1 + 1);
2275 0 : return FALSE;
2276 : }
2277 :
2278 50 : if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) || nCol2 < 0 ||
2279 25 : nCol2 >= poLayer->GetLayerDefn()->GetFieldCount())
2280 : {
2281 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid cell (row=%d, col=%d)",
2282 : nRow2 + 1, nCol2 + 1);
2283 0 : return FALSE;
2284 : }
2285 :
2286 25 : const int nIndexBackup = static_cast<int>(poLayer->GetNextReadFID());
2287 :
2288 25 : if (poLayer->SetNextByIndex(nRow1) != OGRERR_NONE)
2289 : {
2290 0 : CPLError(CE_Failure, CPLE_AppDefined,
2291 : "Cannot fetch feature for row = %d", nRow1);
2292 0 : return FALSE;
2293 : }
2294 :
2295 50 : for (int nRow = nRow1; nRow <= nRow2; nRow++)
2296 : {
2297 25 : OGRFeature *poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2298 :
2299 25 : if (poFeature == nullptr)
2300 : {
2301 0 : CPLError(CE_Failure, CPLE_AppDefined,
2302 : "Cannot fetch feature for for row = %d", nRow);
2303 0 : poLayer->SetNextByIndex(nIndexBackup);
2304 0 : return FALSE;
2305 : }
2306 :
2307 68 : for (int nCol = nCol1; nCol <= nCol2; nCol++)
2308 : {
2309 43 : if (!poFeature->IsFieldSetAndNotNull(nCol))
2310 : {
2311 6 : aoOutValues.push_back(ods_formula_node());
2312 : }
2313 37 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
2314 : {
2315 0 : aoOutValues.push_back(
2316 0 : ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
2317 : }
2318 37 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
2319 : {
2320 0 : aoOutValues.push_back(
2321 0 : ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
2322 : }
2323 : else
2324 : {
2325 37 : std::string osVal(poFeature->GetFieldAsString(nCol));
2326 37 : if (STARTS_WITH(osVal.c_str(), "of:="))
2327 : {
2328 1 : delete poFeature;
2329 1 : poFeature = nullptr;
2330 :
2331 1 : if (!Evaluate(nRow, nCol))
2332 : {
2333 : #ifdef DEBUG_VERBOSE
2334 : CPLError(CE_Warning, CPLE_AppDefined,
2335 : "Formula at cell (%d, %d) "
2336 : "has not yet been resolved",
2337 : nRow + 1, nCol + 1);
2338 : #endif
2339 0 : poLayer->SetNextByIndex(nIndexBackup);
2340 0 : return FALSE;
2341 : }
2342 :
2343 1 : poLayer->SetNextByIndex(nRow);
2344 1 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2345 :
2346 1 : if (!poFeature->IsFieldSetAndNotNull(nCol))
2347 : {
2348 0 : aoOutValues.push_back(ods_formula_node());
2349 : }
2350 1 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() ==
2351 : OFTInteger)
2352 : {
2353 0 : aoOutValues.push_back(ods_formula_node(
2354 : poFeature->GetFieldAsInteger(nCol)));
2355 : }
2356 1 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() ==
2357 : OFTReal)
2358 : {
2359 0 : aoOutValues.push_back(ods_formula_node(
2360 : poFeature->GetFieldAsDouble(nCol)));
2361 : }
2362 : else
2363 : {
2364 1 : osVal = poFeature->GetFieldAsString(nCol);
2365 1 : if (!STARTS_WITH(osVal.c_str(), "of:="))
2366 : {
2367 1 : CPLValueType eType = CPLGetValueType(osVal.c_str());
2368 : /* Try to convert into numeric value if possible */
2369 1 : if (eType != CPL_VALUE_STRING)
2370 1 : aoOutValues.push_back(
2371 2 : ods_formula_node(CPLAtofM(osVal.c_str())));
2372 : else
2373 0 : aoOutValues.push_back(
2374 0 : ods_formula_node(osVal.c_str()));
2375 : }
2376 : }
2377 : }
2378 : else
2379 : {
2380 36 : CPLValueType eType = CPLGetValueType(osVal.c_str());
2381 : /* Try to convert into numeric value if possible */
2382 36 : if (eType != CPL_VALUE_STRING)
2383 13 : aoOutValues.push_back(
2384 26 : ods_formula_node(CPLAtofM(osVal.c_str())));
2385 : else
2386 23 : aoOutValues.push_back(ods_formula_node(osVal.c_str()));
2387 : }
2388 : }
2389 : }
2390 :
2391 25 : delete poFeature;
2392 : }
2393 :
2394 25 : poLayer->SetNextByIndex(nIndexBackup);
2395 :
2396 25 : return TRUE;
2397 : }
2398 :
2399 : /************************************************************************/
2400 : /* Evaluate() */
2401 : /************************************************************************/
2402 :
2403 111 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
2404 : {
2405 111 : if (oVisisitedCells.find(std::pair(nRow, nCol)) != oVisisitedCells.end())
2406 : {
2407 0 : CPLError(CE_Failure, CPLE_AppDefined,
2408 : "Circular dependency with (row=%d, col=%d)", nRow + 1,
2409 : nCol + 1);
2410 0 : return FALSE;
2411 : }
2412 :
2413 111 : oVisisitedCells.insert(std::pair(nRow, nCol));
2414 :
2415 111 : if (poLayer->SetNextByIndex(nRow) != OGRERR_NONE)
2416 : {
2417 0 : CPLError(CE_Failure, CPLE_AppDefined,
2418 : "Cannot fetch feature for row = %d", nRow);
2419 0 : return FALSE;
2420 : }
2421 :
2422 111 : OGRFeature *poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2423 222 : if (poFeature->IsFieldSetAndNotNull(nCol) &&
2424 111 : poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
2425 : {
2426 111 : const char *pszVal = poFeature->GetFieldAsString(nCol);
2427 111 : if (STARTS_WITH(pszVal, "of:="))
2428 : {
2429 110 : ods_formula_node *expr_out = ods_formula_compile(pszVal + 4);
2430 216 : if (expr_out && expr_out->Evaluate(this) &&
2431 106 : expr_out->eNodeType == SNT_CONSTANT)
2432 : {
2433 : /* Refetch feature in case Evaluate() modified another cell in
2434 : * this row */
2435 106 : delete poFeature;
2436 106 : poLayer->SetNextByIndex(nRow);
2437 106 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2438 :
2439 106 : if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
2440 : {
2441 0 : poFeature->UnsetField(nCol);
2442 0 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2443 : }
2444 106 : else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
2445 : {
2446 83 : poFeature->SetField(nCol, expr_out->int_value);
2447 83 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2448 : }
2449 23 : else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
2450 : {
2451 7 : poFeature->SetField(nCol, expr_out->float_value);
2452 7 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2453 : }
2454 16 : else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
2455 : {
2456 16 : poFeature->SetField(nCol, expr_out->string_value);
2457 16 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2458 : }
2459 : }
2460 110 : delete expr_out;
2461 : }
2462 : }
2463 :
2464 111 : delete poFeature;
2465 :
2466 111 : return TRUE;
2467 : }
2468 :
2469 : } // namespace OGRODS
|