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