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