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