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 : int 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 : int 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 at line %d, "
1441 : "column %d",
1442 : XML_ErrorString(XML_GetErrorCode(oParser)),
1443 0 : static_cast<int>(XML_GetCurrentLineNumber(oParser)),
1444 0 : static_cast<int>(XML_GetCurrentColumnNumber(oParser)));
1445 0 : bStopParsing = true;
1446 : }
1447 71 : nWithoutEventCounter++;
1448 71 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1449 :
1450 40 : XML_ParserFree(oParser);
1451 40 : oParser = nullptr;
1452 :
1453 40 : if (nWithoutEventCounter == 10)
1454 : {
1455 0 : CPLError(CE_Failure, CPLE_AppDefined,
1456 : "Too much data inside one element. File probably corrupted");
1457 0 : bStopParsing = true;
1458 : }
1459 :
1460 40 : VSIFCloseL(fpContent);
1461 40 : fpContent = nullptr;
1462 :
1463 40 : bUpdated = false;
1464 : }
1465 :
1466 : /************************************************************************/
1467 : /* startElementStylesCbk() */
1468 : /************************************************************************/
1469 :
1470 3016 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
1471 : const char **ppszAttr)
1472 : {
1473 3016 : static_cast<OGRODSDataSource *>(pUserData)->startElementStylesCbk(pszName,
1474 : ppszAttr);
1475 3016 : }
1476 :
1477 3016 : void OGRODSDataSource::startElementStylesCbk(const char *pszNameIn,
1478 : const char **ppszAttr)
1479 : {
1480 3016 : if (bStopParsing)
1481 0 : return;
1482 :
1483 3016 : nWithoutEventCounter = 0;
1484 :
1485 7057 : if (nStackDepth == 0 &&
1486 3054 : strcmp(pszNameIn, "config:config-item-map-named") == 0 &&
1487 38 : strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
1488 : {
1489 37 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1490 : }
1491 2979 : else if (nStackDepth == 1 &&
1492 138 : strcmp(pszNameIn, "config:config-item-map-entry") == 0)
1493 : {
1494 : const char *pszTableName =
1495 138 : GetAttributeValue(ppszAttr, "config:name", nullptr);
1496 138 : if (pszTableName)
1497 : {
1498 138 : osCurrentConfigTableName = pszTableName;
1499 138 : nVerticalSplitFlags = 0;
1500 138 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1501 138 : }
1502 : }
1503 2841 : else if (nStackDepth == 2 && strcmp(pszNameIn, "config:config-item") == 0)
1504 : {
1505 : const char *pszConfigName =
1506 1853 : GetAttributeValue(ppszAttr, "config:name", nullptr);
1507 1853 : if (pszConfigName)
1508 : {
1509 1853 : osConfigName = pszConfigName;
1510 1853 : osValue = "";
1511 1853 : stateStack[++nStackDepth].nBeginDepth = nDepth;
1512 : }
1513 : }
1514 :
1515 3016 : nDepth++;
1516 : }
1517 :
1518 : /************************************************************************/
1519 : /* endElementStylesCbk() */
1520 : /************************************************************************/
1521 :
1522 3016 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
1523 : {
1524 3016 : static_cast<OGRODSDataSource *>(pUserData)->endElementStylesCbk(pszName);
1525 3016 : }
1526 :
1527 3016 : void OGRODSDataSource::endElementStylesCbk(const char * /*pszName*/)
1528 : {
1529 3016 : if (bStopParsing)
1530 0 : return;
1531 :
1532 3016 : nWithoutEventCounter = 0;
1533 3016 : nDepth--;
1534 :
1535 3016 : if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
1536 : {
1537 2028 : if (nStackDepth == 2)
1538 : {
1539 138 : if (nVerticalSplitFlags == (1 | 2))
1540 20 : osSetLayerHasSplitter.insert(osCurrentConfigTableName);
1541 : }
1542 2028 : if (nStackDepth == 3)
1543 : {
1544 1853 : if (osConfigName == "VerticalSplitMode" && osValue == "2")
1545 20 : nVerticalSplitFlags |= 1;
1546 1833 : else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
1547 20 : nVerticalSplitFlags |= 2;
1548 : }
1549 2028 : nStackDepth--;
1550 : }
1551 : }
1552 :
1553 : /************************************************************************/
1554 : /* dataHandlerStylesCbk() */
1555 : /************************************************************************/
1556 :
1557 3249 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data,
1558 : int nLen)
1559 : {
1560 3249 : static_cast<OGRODSDataSource *>(pUserData)->dataHandlerStylesCbk(data,
1561 : nLen);
1562 3249 : }
1563 :
1564 3249 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
1565 : {
1566 3249 : if (bStopParsing)
1567 0 : return;
1568 :
1569 3249 : nDataHandlerCounter++;
1570 3249 : if (nDataHandlerCounter >= PARSER_BUF_SIZE)
1571 : {
1572 0 : CPLError(CE_Failure, CPLE_AppDefined,
1573 : "File probably corrupted (million laugh pattern)");
1574 0 : XML_StopParser(oParser, XML_FALSE);
1575 0 : bStopParsing = true;
1576 0 : return;
1577 : }
1578 :
1579 3249 : nWithoutEventCounter = 0;
1580 :
1581 3249 : if (nStackDepth == 3)
1582 : {
1583 1853 : osValue.append(data, nLen);
1584 : }
1585 : }
1586 :
1587 : /************************************************************************/
1588 : /* AnalyseSettings() */
1589 : /* */
1590 : /* We parse settings.xml to see which layers have a vertical splitter */
1591 : /* on the first line, so as to use it as the header line. */
1592 : /************************************************************************/
1593 :
1594 40 : void OGRODSDataSource::AnalyseSettings()
1595 : {
1596 40 : if (fpSettings == nullptr)
1597 3 : return;
1598 :
1599 37 : oParser = OGRCreateExpatXMLParser();
1600 37 : XML_SetElementHandler(oParser, OGRODS::startElementStylesCbk,
1601 : OGRODS::endElementStylesCbk);
1602 37 : XML_SetCharacterDataHandler(oParser, OGRODS::dataHandlerStylesCbk);
1603 37 : XML_SetUserData(oParser, this);
1604 :
1605 37 : nDepth = 0;
1606 37 : nStackDepth = 0;
1607 37 : bStopParsing = false;
1608 37 : nWithoutEventCounter = 0;
1609 :
1610 37 : VSIFSeekL(fpSettings, 0, SEEK_SET);
1611 :
1612 37 : std::vector<char> aBuf(PARSER_BUF_SIZE);
1613 37 : int nDone = 0;
1614 26 : do
1615 : {
1616 63 : nDataHandlerCounter = 0;
1617 : unsigned int nLen =
1618 63 : (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSettings);
1619 63 : nDone = (nLen < aBuf.size());
1620 63 : if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
1621 : {
1622 0 : CPLError(CE_Failure, CPLE_AppDefined,
1623 : "XML parsing of styles.xml file failed : %s at line %d, "
1624 : "column %d",
1625 : XML_ErrorString(XML_GetErrorCode(oParser)),
1626 0 : (int)XML_GetCurrentLineNumber(oParser),
1627 0 : (int)XML_GetCurrentColumnNumber(oParser));
1628 0 : bStopParsing = true;
1629 : }
1630 63 : nWithoutEventCounter++;
1631 63 : } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
1632 :
1633 37 : XML_ParserFree(oParser);
1634 37 : oParser = nullptr;
1635 :
1636 37 : if (nWithoutEventCounter == 10)
1637 : {
1638 0 : CPLError(CE_Failure, CPLE_AppDefined,
1639 : "Too much data inside one element. File probably corrupted");
1640 0 : bStopParsing = true;
1641 : }
1642 :
1643 37 : VSIFCloseL(fpSettings);
1644 37 : fpSettings = nullptr;
1645 : }
1646 :
1647 : /************************************************************************/
1648 : /* ICreateLayer() */
1649 : /************************************************************************/
1650 :
1651 : OGRLayer *
1652 61 : OGRODSDataSource::ICreateLayer(const char *pszLayerName,
1653 : const OGRGeomFieldDefn * /*poGeomFieldDefn*/,
1654 : CSLConstList papszOptions)
1655 : {
1656 : /* -------------------------------------------------------------------- */
1657 : /* Verify we are in update mode. */
1658 : /* -------------------------------------------------------------------- */
1659 61 : if (!bUpdatable)
1660 : {
1661 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1662 : "Data source %s opened read-only.\n"
1663 : "New layer %s cannot be created.\n",
1664 : pszName, pszLayerName);
1665 :
1666 0 : return nullptr;
1667 : }
1668 :
1669 61 : AnalyseFile();
1670 :
1671 : /* -------------------------------------------------------------------- */
1672 : /* Do we already have this layer? If so, should we blow it */
1673 : /* away? */
1674 : /* -------------------------------------------------------------------- */
1675 105 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
1676 : {
1677 44 : if (EQUAL(pszLayerName, papoLayers[iLayer]->GetName()))
1678 : {
1679 0 : if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
1680 0 : !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
1681 : {
1682 0 : DeleteLayer(pszLayerName);
1683 : }
1684 : else
1685 : {
1686 0 : CPLError(CE_Failure, CPLE_AppDefined,
1687 : "Layer %s already exists, CreateLayer failed.\n"
1688 : "Use the layer creation option OVERWRITE=YES to "
1689 : "replace it.",
1690 : pszLayerName);
1691 0 : return nullptr;
1692 : }
1693 : }
1694 : }
1695 :
1696 : /* -------------------------------------------------------------------- */
1697 : /* Create the layer object. */
1698 : /* -------------------------------------------------------------------- */
1699 61 : OGRLayer *poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
1700 :
1701 61 : papoLayers = static_cast<OGRLayer **>(
1702 61 : CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer *)));
1703 61 : papoLayers[nLayers] = poLayer;
1704 61 : nLayers++;
1705 :
1706 61 : bUpdated = true;
1707 :
1708 61 : return poLayer;
1709 : }
1710 :
1711 : /************************************************************************/
1712 : /* DeleteLayer() */
1713 : /************************************************************************/
1714 :
1715 0 : void OGRODSDataSource::DeleteLayer(const char *pszLayerName)
1716 :
1717 : {
1718 : /* -------------------------------------------------------------------- */
1719 : /* Verify we are in update mode. */
1720 : /* -------------------------------------------------------------------- */
1721 0 : if (!bUpdatable)
1722 : {
1723 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
1724 : "Data source %s opened read-only.\n"
1725 : "Layer %s cannot be deleted.\n",
1726 : pszName, pszLayerName);
1727 :
1728 0 : return;
1729 : }
1730 :
1731 : /* -------------------------------------------------------------------- */
1732 : /* Try to find layer. */
1733 : /* -------------------------------------------------------------------- */
1734 0 : int iLayer = 0;
1735 0 : for (; iLayer < nLayers; iLayer++)
1736 : {
1737 0 : if (EQUAL(pszLayerName, papoLayers[iLayer]->GetName()))
1738 0 : break;
1739 : }
1740 :
1741 0 : if (iLayer == nLayers)
1742 : {
1743 0 : CPLError(
1744 : CE_Failure, CPLE_AppDefined,
1745 : "Attempt to delete layer '%s', but this layer is not known to OGR.",
1746 : pszLayerName);
1747 0 : return;
1748 : }
1749 :
1750 0 : DeleteLayer(iLayer);
1751 : }
1752 :
1753 : /************************************************************************/
1754 : /* DeleteLayer() */
1755 : /************************************************************************/
1756 :
1757 16 : OGRErr OGRODSDataSource::DeleteLayer(int iLayer)
1758 : {
1759 16 : AnalyseFile();
1760 :
1761 16 : if (iLayer < 0 || iLayer >= nLayers)
1762 : {
1763 0 : CPLError(CE_Failure, CPLE_AppDefined,
1764 : "Layer %d not in legal range of 0 to %d.", iLayer,
1765 0 : nLayers - 1);
1766 0 : return OGRERR_FAILURE;
1767 : }
1768 :
1769 : /* -------------------------------------------------------------------- */
1770 : /* Blow away our OGR structures related to the layer. This is */
1771 : /* pretty dangerous if anything has a reference to this layer! */
1772 : /* -------------------------------------------------------------------- */
1773 :
1774 16 : delete papoLayers[iLayer];
1775 16 : memmove(papoLayers + iLayer, papoLayers + iLayer + 1,
1776 16 : sizeof(void *) * (nLayers - iLayer - 1));
1777 16 : nLayers--;
1778 :
1779 16 : bUpdated = true;
1780 :
1781 16 : return OGRERR_NONE;
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* HasHeaderLine() */
1786 : /************************************************************************/
1787 :
1788 106 : static bool HasHeaderLine(OGRLayer *poLayer)
1789 : {
1790 106 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
1791 106 : bool bHasHeaders = false;
1792 :
1793 280 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1794 : {
1795 174 : if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
1796 174 : CPLSPrintf("Field%d", j + 1)) != 0)
1797 92 : bHasHeaders = true;
1798 : }
1799 :
1800 106 : return bHasHeaders;
1801 : }
1802 :
1803 : /************************************************************************/
1804 : /* WriteLayer() */
1805 : /************************************************************************/
1806 :
1807 53 : static void WriteLayer(VSILFILE *fp, OGRLayer *poLayer)
1808 : {
1809 53 : const char *pszLayerName = poLayer->GetName();
1810 53 : char *pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
1811 53 : VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
1812 53 : CPLFree(pszXML);
1813 :
1814 53 : poLayer->ResetReading();
1815 :
1816 53 : OGRFeature *poFeature = poLayer->GetNextFeature();
1817 :
1818 53 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
1819 53 : const bool bHasHeaders = HasHeaderLine(poLayer);
1820 :
1821 140 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1822 : {
1823 87 : int nStyleNumber = 1;
1824 87 : if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
1825 9 : nStyleNumber = 2;
1826 87 : VSIFPrintfL(fp,
1827 : "<table:table-column table:style-name=\"co%d\" "
1828 : "table:default-cell-style-name=\"Default\"/>\n",
1829 : nStyleNumber);
1830 : }
1831 :
1832 53 : if (bHasHeaders && poFeature != nullptr)
1833 : {
1834 20 : VSIFPrintfL(fp, "<table:table-row>\n");
1835 66 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
1836 : {
1837 46 : const char *pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
1838 :
1839 46 : VSIFPrintfL(fp,
1840 : "<table:table-cell office:value-type=\"string\">\n");
1841 46 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1842 46 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1843 46 : CPLFree(pszXML);
1844 46 : VSIFPrintfL(fp, "</table:table-cell>\n");
1845 : }
1846 20 : VSIFPrintfL(fp, "</table:table-row>\n");
1847 : }
1848 :
1849 181 : while (poFeature != nullptr)
1850 : {
1851 128 : VSIFPrintfL(fp, "<table:table-row>\n");
1852 636 : for (int j = 0; j < poFeature->GetFieldCount(); j++)
1853 : {
1854 508 : if (poFeature->IsFieldSetAndNotNull(j))
1855 : {
1856 178 : OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(j);
1857 178 : const OGRFieldType eType = poFieldDefn->GetType();
1858 :
1859 178 : if (eType == OFTReal)
1860 : {
1861 36 : VSIFPrintfL(fp,
1862 : "<table:table-cell office:value-type=\"float\" "
1863 : "office:value=\"%.16f\"/>\n",
1864 : poFeature->GetFieldAsDouble(j));
1865 : }
1866 142 : else if (eType == OFTInteger)
1867 : {
1868 24 : const int nVal = poFeature->GetFieldAsInteger(j);
1869 24 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1870 : {
1871 2 : VSIFPrintfL(fp,
1872 : "<table:table-cell "
1873 : "table:formula=\"of:=%s()\" "
1874 : "office:value-type=\"float\" "
1875 : "office:value=\"%d\"/>\n",
1876 : nVal ? "TRUE" : "FALSE", nVal);
1877 : }
1878 : else
1879 : {
1880 22 : VSIFPrintfL(
1881 : fp,
1882 : "<table:table-cell office:value-type=\"float\" "
1883 : "office:value=\"%d\"/>\n",
1884 : nVal);
1885 : }
1886 : }
1887 118 : else if (eType == OFTInteger64)
1888 : {
1889 13 : VSIFPrintfL(fp,
1890 : "<table:table-cell office:value-type=\"float\" "
1891 : "office:value=\"" CPL_FRMT_GIB "\"/>\n",
1892 : poFeature->GetFieldAsInteger64(j));
1893 : }
1894 105 : else if (eType == OFTDateTime)
1895 : {
1896 11 : int nYear = 0;
1897 11 : int nMonth = 0;
1898 11 : int nDay = 0;
1899 11 : int nHour = 0;
1900 11 : int nMinute = 0;
1901 11 : int nTZFlag = 0;
1902 11 : float fSecond = 0.0f;
1903 11 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1904 : &nHour, &nMinute, &fSecond,
1905 : &nTZFlag);
1906 11 : if (OGR_GET_MS(fSecond))
1907 : {
1908 1 : VSIFPrintfL(
1909 : fp,
1910 : "<table:table-cell "
1911 : "table:style-name=\"stDateTimeMilliseconds\" "
1912 : "office:value-type=\"date\" "
1913 : "office:date-value="
1914 : "\"%04d-%02d-%02dT%02d:%02d:%06.3f\">\n",
1915 : nYear, nMonth, nDay, nHour, nMinute, fSecond);
1916 1 : VSIFPrintfL(fp,
1917 : "<text:p>%02d/%02d/%04d "
1918 : "%02d:%02d:%06.3f</text:p>\n",
1919 : nDay, nMonth, nYear, nHour, nMinute,
1920 : fSecond);
1921 : }
1922 : else
1923 : {
1924 10 : VSIFPrintfL(fp,
1925 : "<table:table-cell "
1926 : "table:style-name=\"stDateTime\" "
1927 : "office:value-type=\"date\" "
1928 : "office:date-value="
1929 : "\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
1930 : nYear, nMonth, nDay, nHour, nMinute,
1931 : static_cast<int>(fSecond));
1932 10 : VSIFPrintfL(
1933 : fp,
1934 : "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
1935 : nDay, nMonth, nYear, nHour, nMinute,
1936 : static_cast<int>(fSecond));
1937 : }
1938 11 : VSIFPrintfL(fp, "</table:table-cell>\n");
1939 : }
1940 94 : else if (eType == OFTDate)
1941 : {
1942 2 : int nYear = 0;
1943 2 : int nMonth = 0;
1944 2 : int nDay = 0;
1945 2 : int nHour = 0;
1946 2 : int nMinute = 0;
1947 2 : int nSecond = 0;
1948 2 : int nTZFlag = 0;
1949 2 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1950 : &nHour, &nMinute, &nSecond,
1951 : &nTZFlag);
1952 2 : VSIFPrintfL(fp,
1953 : "<table:table-cell table:style-name=\"stDate\" "
1954 : "office:value-type=\"date\" "
1955 : "office:date-value=\"%04d-%02d-%02d\">\n",
1956 : nYear, nMonth, nDay);
1957 2 : VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d</text:p>\n", nDay,
1958 : nMonth, nYear);
1959 2 : VSIFPrintfL(fp, "</table:table-cell>\n");
1960 : }
1961 92 : else if (eType == OFTTime)
1962 : {
1963 2 : int nYear = 0;
1964 2 : int nMonth = 0;
1965 2 : int nDay = 0;
1966 2 : int nHour = 0;
1967 2 : int nMinute = 0;
1968 2 : int nSecond = 0;
1969 2 : int nTZFlag = 0;
1970 2 : poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
1971 : &nHour, &nMinute, &nSecond,
1972 : &nTZFlag);
1973 2 : VSIFPrintfL(fp,
1974 : "<table:table-cell table:style-name=\"stTime\" "
1975 : "office:value-type=\"time\" "
1976 : "office:time-value=\"PT%02dH%02dM%02dS\">\n",
1977 : nHour, nMinute, nSecond);
1978 2 : VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n", nHour,
1979 : nMinute, nSecond);
1980 2 : VSIFPrintfL(fp, "</table:table-cell>\n");
1981 : }
1982 : else
1983 : {
1984 90 : const char *pszVal = poFeature->GetFieldAsString(j);
1985 90 : pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
1986 90 : if (STARTS_WITH(pszVal, "of:="))
1987 : {
1988 0 : VSIFPrintfL(
1989 : fp, "<table:table-cell table:formula=\"%s\"/>\n",
1990 : pszXML);
1991 : }
1992 : else
1993 : {
1994 90 : VSIFPrintfL(fp, "<table:table-cell "
1995 : "office:value-type=\"string\">\n");
1996 90 : VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
1997 90 : VSIFPrintfL(fp, "</table:table-cell>\n");
1998 : }
1999 90 : CPLFree(pszXML);
2000 : }
2001 : }
2002 : else
2003 : {
2004 330 : VSIFPrintfL(fp, "<table:table-cell/>\n");
2005 : }
2006 : }
2007 128 : VSIFPrintfL(fp, "</table:table-row>\n");
2008 :
2009 128 : delete poFeature;
2010 128 : poFeature = poLayer->GetNextFeature();
2011 : }
2012 :
2013 53 : VSIFPrintfL(fp, "</table:table>\n");
2014 53 : }
2015 :
2016 : /************************************************************************/
2017 : /* FlushCache() */
2018 : /************************************************************************/
2019 :
2020 114 : CPLErr OGRODSDataSource::FlushCache(bool /* bAtClosing */)
2021 : {
2022 114 : if (!bUpdated)
2023 74 : return CE_None;
2024 :
2025 40 : CPLAssert(fpSettings == nullptr);
2026 40 : CPLAssert(fpContent == nullptr);
2027 :
2028 : VSIStatBufL sStat;
2029 40 : if (VSIStatL(pszName, &sStat) == 0)
2030 : {
2031 2 : if (VSIUnlink(pszName) != 0)
2032 : {
2033 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s", pszName);
2034 0 : return CE_Failure;
2035 : }
2036 : }
2037 :
2038 80 : CPLConfigOptionSetter oZip64Disable("CPL_CREATE_ZIP64", "NO", false);
2039 :
2040 : /* Maintain new ZIP files opened */
2041 40 : void *hZIP = CPLCreateZip(pszName, nullptr);
2042 40 : if (!hZIP)
2043 : {
2044 1 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s", pszName,
2045 : VSIGetLastErrorMsg());
2046 1 : return CE_Failure;
2047 : }
2048 :
2049 : /* Write uncompressed mimetype */
2050 39 : char **papszOptions = CSLAddString(nullptr, "COMPRESSED=NO");
2051 39 : if (CPLCreateFileInZip(hZIP, "mimetype", papszOptions) != CE_None)
2052 : {
2053 0 : CSLDestroy(papszOptions);
2054 0 : CPLCloseZip(hZIP);
2055 0 : return CE_Failure;
2056 : }
2057 39 : CSLDestroy(papszOptions);
2058 39 : if (CPLWriteFileInZip(
2059 : hZIP, "application/vnd.oasis.opendocument.spreadsheet",
2060 : static_cast<int>(strlen(
2061 39 : "application/vnd.oasis.opendocument.spreadsheet"))) != CE_None)
2062 : {
2063 0 : CPLCloseZip(hZIP);
2064 0 : return CE_Failure;
2065 : }
2066 39 : CPLCloseFileInZip(hZIP);
2067 :
2068 : /* Now close ZIP file */
2069 39 : CPLCloseZip(hZIP);
2070 39 : hZIP = nullptr;
2071 :
2072 : /* Re-open with VSILFILE */
2073 78 : CPLString osTmpFilename(CPLSPrintf("/vsizip/%s", pszName));
2074 39 : VSILFILE *fpZIP = VSIFOpenL(osTmpFilename, "ab");
2075 39 : if (fpZIP == nullptr)
2076 0 : return CE_Failure;
2077 :
2078 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName);
2079 39 : VSILFILE *fp = VSIFOpenL(osTmpFilename, "wb");
2080 39 : if (!fp)
2081 : {
2082 0 : VSIFCloseL(fpZIP);
2083 0 : return CE_Failure;
2084 : }
2085 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2086 39 : VSIFPrintfL(fp, "<manifest:manifest "
2087 : "xmlns:manifest=\"urn:oasis:names:tc:"
2088 : "opendocument:xmlns:manifest:1.0\">\n");
2089 39 : VSIFPrintfL(fp, "<manifest:file-entry "
2090 : "manifest:media-type=\"application/vnd.oasis."
2091 : "opendocument.spreadsheet\" "
2092 : "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
2093 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2094 : "manifest:full-path=\"content.xml\"/>\n");
2095 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2096 : "manifest:full-path=\"styles.xml\"/>\n");
2097 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2098 : "manifest:full-path=\"meta.xml\"/>\n");
2099 39 : VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
2100 : "manifest:full-path=\"settings.xml\"/>\n");
2101 39 : VSIFPrintfL(fp, "</manifest:manifest>\n");
2102 39 : VSIFCloseL(fp);
2103 :
2104 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/meta.xml", pszName);
2105 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2106 39 : if (!fp)
2107 : {
2108 0 : VSIFCloseL(fpZIP);
2109 0 : return CE_Failure;
2110 : }
2111 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2112 39 : VSIFPrintfL(
2113 : fp, "<office:document-meta "
2114 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2115 : "office:version=\"1.2\">\n");
2116 39 : VSIFPrintfL(fp, "</office:document-meta>\n");
2117 39 : VSIFCloseL(fp);
2118 :
2119 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/settings.xml", pszName);
2120 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2121 39 : if (!fp)
2122 : {
2123 0 : VSIFCloseL(fpZIP);
2124 0 : return CE_Failure;
2125 : }
2126 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2127 39 : VSIFPrintfL(
2128 : fp, "<office:document-settings "
2129 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2130 : "xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" "
2131 : "xmlns:ooo=\"http://openoffice.org/2004/office\" "
2132 : "office:version=\"1.2\">\n");
2133 39 : VSIFPrintfL(fp, "<office:settings>\n");
2134 39 : VSIFPrintfL(fp,
2135 : "<config:config-item-set config:name=\"ooo:view-settings\">\n");
2136 39 : VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
2137 39 : VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
2138 39 : VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
2139 92 : for (int i = 0; i < nLayers; i++)
2140 : {
2141 53 : OGRLayer *poLayer = papoLayers[i];
2142 53 : if (HasHeaderLine(poLayer))
2143 : {
2144 : /* Add vertical splitter */
2145 20 : char *pszXML = OGRGetXML_UTF8_EscapedString(poLayer->GetName());
2146 20 : VSIFPrintfL(fp,
2147 : "<config:config-item-map-entry config:name=\"%s\">\n",
2148 : pszXML);
2149 20 : CPLFree(pszXML);
2150 20 : VSIFPrintfL(fp,
2151 : "<config:config-item config:name=\"VerticalSplitMode\" "
2152 : "config:type=\"short\">2</config:config-item>\n");
2153 20 : VSIFPrintfL(
2154 : fp, "<config:config-item config:name=\"VerticalSplitPosition\" "
2155 : "config:type=\"int\">1</config:config-item>\n");
2156 20 : VSIFPrintfL(fp,
2157 : "<config:config-item config:name=\"ActiveSplitRange\" "
2158 : "config:type=\"short\">2</config:config-item>\n");
2159 20 : VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" "
2160 : "config:type=\"int\">0</config:config-item>\n");
2161 20 : VSIFPrintfL(fp,
2162 : "<config:config-item config:name=\"PositionBottom\" "
2163 : "config:type=\"int\">1</config:config-item>\n");
2164 20 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
2165 : }
2166 : }
2167 39 : VSIFPrintfL(fp, "</config:config-item-map-named>\n");
2168 39 : VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
2169 39 : VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
2170 39 : VSIFPrintfL(fp, "</config:config-item-set>\n");
2171 39 : VSIFPrintfL(fp, "</office:settings>\n");
2172 39 : VSIFPrintfL(fp, "</office:document-settings>\n");
2173 39 : VSIFCloseL(fp);
2174 :
2175 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/styles.xml", pszName);
2176 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2177 39 : if (!fp)
2178 : {
2179 0 : VSIFCloseL(fpZIP);
2180 0 : return CE_Failure;
2181 : }
2182 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2183 39 : VSIFPrintfL(
2184 : fp, "<office:document-styles "
2185 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2186 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
2187 : "office:version=\"1.2\">\n");
2188 39 : VSIFPrintfL(fp, "<office:styles>\n");
2189 39 : VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
2190 : "style:family=\"table-cell\">\n");
2191 39 : VSIFPrintfL(fp, "</style:style>\n");
2192 39 : VSIFPrintfL(fp, "</office:styles>\n");
2193 39 : VSIFPrintfL(fp, "</office:document-styles>\n");
2194 39 : VSIFCloseL(fp);
2195 :
2196 39 : osTmpFilename = CPLSPrintf("/vsizip/%s/content.xml", pszName);
2197 39 : fp = VSIFOpenL(osTmpFilename, "wb");
2198 39 : if (!fp)
2199 : {
2200 0 : VSIFCloseL(fpZIP);
2201 0 : return CE_Failure;
2202 : }
2203 39 : VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2204 39 : VSIFPrintfL(
2205 : fp,
2206 : "<office:document-content "
2207 : "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
2208 : "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
2209 : "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "
2210 : "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" "
2211 : "xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" "
2212 : "xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:"
2213 : "xsl-fo-compatible:1.0\" "
2214 : "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" "
2215 : "office:version=\"1.2\">\n");
2216 39 : VSIFPrintfL(fp, "<office:scripts/>\n");
2217 39 : VSIFPrintfL(fp, "<office:automatic-styles>\n");
2218 39 : VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
2219 : "style:family=\"table-column\">\n");
2220 39 : VSIFPrintfL(fp, "<style:table-column-properties "
2221 : "fo:break-before=\"auto\" "
2222 : "style:column-width=\"2.5cm\"/>\n");
2223 39 : VSIFPrintfL(fp, "</style:style>\n");
2224 39 : VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
2225 : "style:family=\"table-column\">\n");
2226 39 : VSIFPrintfL(fp, "<style:table-column-properties "
2227 : "fo:break-before=\"auto\" "
2228 : "style:column-width=\"5cm\"/>\n");
2229 39 : VSIFPrintfL(fp, "</style:style>\n");
2230 39 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
2231 : "number:automatic-order=\"true\">\n");
2232 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2233 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2234 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2235 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2236 39 : VSIFPrintfL(fp, "<number:year/>\n");
2237 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2238 39 : VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
2239 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2240 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2241 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2242 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2243 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
2244 39 : VSIFPrintfL(fp, "</number:time-style>\n");
2245 39 : VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
2246 : "number:automatic-order=\"true\">\n");
2247 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2248 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2249 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2250 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2251 39 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
2252 39 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
2253 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2254 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2255 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2256 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2257 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
2258 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2259 39 : VSIFPrintfL(fp,
2260 : "<number:date-style style:name=\"nDateTimeMilliseconds\">\n");
2261 39 : VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
2262 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2263 39 : VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
2264 39 : VSIFPrintfL(fp, "<number:text>/</number:text>\n");
2265 39 : VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
2266 39 : VSIFPrintfL(fp, "<number:text> </number:text>\n");
2267 39 : VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
2268 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2269 39 : VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
2270 39 : VSIFPrintfL(fp, "<number:text>:</number:text>\n");
2271 39 : VSIFPrintfL(fp, "<number:seconds number:style=\"long\" "
2272 : "number:decimal-places=\"3\"/>\n");
2273 39 : VSIFPrintfL(fp, "</number:date-style>\n");
2274 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDate\" "
2275 : "style:family=\"table-cell\" "
2276 : "style:parent-style-name=\"Default\" "
2277 : "style:data-style-name=\"nDate\"/>\n");
2278 39 : VSIFPrintfL(fp, "<style:style style:name=\"stTime\" "
2279 : "style:family=\"table-cell\" "
2280 : "style:parent-style-name=\"Default\" "
2281 : "style:data-style-name=\"nTime\"/>\n");
2282 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDateTime\" "
2283 : "style:family=\"table-cell\" "
2284 : "style:parent-style-name=\"Default\" "
2285 : "style:data-style-name=\"nDateTime\"/>\n");
2286 39 : VSIFPrintfL(fp, "<style:style style:name=\"stDateTimeMilliseconds\" "
2287 : "style:family=\"table-cell\" "
2288 : "style:parent-style-name=\"Default\" "
2289 : "style:data-style-name=\"nDateTimeMilliseconds\"/>\n");
2290 39 : VSIFPrintfL(fp, "</office:automatic-styles>\n");
2291 39 : VSIFPrintfL(fp, "<office:body>\n");
2292 39 : VSIFPrintfL(fp, "<office:spreadsheet>\n");
2293 92 : for (int i = 0; i < nLayers; i++)
2294 : {
2295 53 : WriteLayer(fp, papoLayers[i]);
2296 : }
2297 39 : VSIFPrintfL(fp, "</office:spreadsheet>\n");
2298 39 : VSIFPrintfL(fp, "</office:body>\n");
2299 39 : VSIFPrintfL(fp, "</office:document-content>\n");
2300 39 : VSIFCloseL(fp);
2301 :
2302 : /* Now close ZIP file */
2303 39 : VSIFCloseL(fpZIP);
2304 :
2305 : /* Reset updated flag at datasource and layer level */
2306 39 : bUpdated = false;
2307 92 : for (int i = 0; i < nLayers; i++)
2308 : {
2309 53 : reinterpret_cast<OGRODSLayer *>(papoLayers[i])->SetUpdated(false);
2310 : }
2311 :
2312 39 : return CE_None;
2313 : }
2314 :
2315 : /************************************************************************/
2316 : /* EvaluateRange() */
2317 : /************************************************************************/
2318 :
2319 25 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
2320 : std::vector<ods_formula_node> &aoOutValues)
2321 : {
2322 50 : if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) || nCol1 < 0 ||
2323 25 : nCol1 >= poLayer->GetLayerDefn()->GetFieldCount())
2324 : {
2325 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid cell (row=%d, col=%d)",
2326 : nRow1 + 1, nCol1 + 1);
2327 0 : return FALSE;
2328 : }
2329 :
2330 50 : if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) || nCol2 < 0 ||
2331 25 : nCol2 >= poLayer->GetLayerDefn()->GetFieldCount())
2332 : {
2333 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid cell (row=%d, col=%d)",
2334 : nRow2 + 1, nCol2 + 1);
2335 0 : return FALSE;
2336 : }
2337 :
2338 25 : const int nIndexBackup = static_cast<int>(poLayer->GetNextReadFID());
2339 :
2340 25 : if (poLayer->SetNextByIndex(nRow1) != OGRERR_NONE)
2341 : {
2342 0 : CPLError(CE_Failure, CPLE_AppDefined,
2343 : "Cannot fetch feature for row = %d", nRow1);
2344 0 : return FALSE;
2345 : }
2346 :
2347 50 : for (int nRow = nRow1; nRow <= nRow2; nRow++)
2348 : {
2349 25 : OGRFeature *poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2350 :
2351 25 : if (poFeature == nullptr)
2352 : {
2353 0 : CPLError(CE_Failure, CPLE_AppDefined,
2354 : "Cannot fetch feature for for row = %d", nRow);
2355 0 : poLayer->SetNextByIndex(nIndexBackup);
2356 0 : return FALSE;
2357 : }
2358 :
2359 68 : for (int nCol = nCol1; nCol <= nCol2; nCol++)
2360 : {
2361 43 : if (!poFeature->IsFieldSetAndNotNull(nCol))
2362 : {
2363 6 : aoOutValues.push_back(ods_formula_node());
2364 : }
2365 37 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
2366 : {
2367 0 : aoOutValues.push_back(
2368 0 : ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
2369 : }
2370 37 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
2371 : {
2372 0 : aoOutValues.push_back(
2373 0 : ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
2374 : }
2375 : else
2376 : {
2377 37 : std::string osVal(poFeature->GetFieldAsString(nCol));
2378 37 : if (STARTS_WITH(osVal.c_str(), "of:="))
2379 : {
2380 1 : delete poFeature;
2381 1 : poFeature = nullptr;
2382 :
2383 1 : if (!Evaluate(nRow, nCol))
2384 : {
2385 : #ifdef DEBUG_VERBOSE
2386 : CPLError(CE_Warning, CPLE_AppDefined,
2387 : "Formula at cell (%d, %d) "
2388 : "has not yet been resolved",
2389 : nRow + 1, nCol + 1);
2390 : #endif
2391 0 : poLayer->SetNextByIndex(nIndexBackup);
2392 0 : return FALSE;
2393 : }
2394 :
2395 1 : poLayer->SetNextByIndex(nRow);
2396 1 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2397 :
2398 1 : if (!poFeature->IsFieldSetAndNotNull(nCol))
2399 : {
2400 0 : aoOutValues.push_back(ods_formula_node());
2401 : }
2402 1 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() ==
2403 : OFTInteger)
2404 : {
2405 0 : aoOutValues.push_back(ods_formula_node(
2406 : poFeature->GetFieldAsInteger(nCol)));
2407 : }
2408 1 : else if (poFeature->GetFieldDefnRef(nCol)->GetType() ==
2409 : OFTReal)
2410 : {
2411 0 : aoOutValues.push_back(ods_formula_node(
2412 : poFeature->GetFieldAsDouble(nCol)));
2413 : }
2414 : else
2415 : {
2416 1 : osVal = poFeature->GetFieldAsString(nCol);
2417 1 : if (!STARTS_WITH(osVal.c_str(), "of:="))
2418 : {
2419 1 : CPLValueType eType = CPLGetValueType(osVal.c_str());
2420 : /* Try to convert into numeric value if possible */
2421 1 : if (eType != CPL_VALUE_STRING)
2422 1 : aoOutValues.push_back(
2423 2 : ods_formula_node(CPLAtofM(osVal.c_str())));
2424 : else
2425 0 : aoOutValues.push_back(
2426 0 : ods_formula_node(osVal.c_str()));
2427 : }
2428 : }
2429 : }
2430 : else
2431 : {
2432 36 : CPLValueType eType = CPLGetValueType(osVal.c_str());
2433 : /* Try to convert into numeric value if possible */
2434 36 : if (eType != CPL_VALUE_STRING)
2435 13 : aoOutValues.push_back(
2436 26 : ods_formula_node(CPLAtofM(osVal.c_str())));
2437 : else
2438 23 : aoOutValues.push_back(ods_formula_node(osVal.c_str()));
2439 : }
2440 : }
2441 : }
2442 :
2443 25 : delete poFeature;
2444 : }
2445 :
2446 25 : poLayer->SetNextByIndex(nIndexBackup);
2447 :
2448 25 : return TRUE;
2449 : }
2450 :
2451 : /************************************************************************/
2452 : /* Evaluate() */
2453 : /************************************************************************/
2454 :
2455 111 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
2456 : {
2457 111 : if (oVisisitedCells.find(std::pair(nRow, nCol)) != oVisisitedCells.end())
2458 : {
2459 0 : CPLError(CE_Failure, CPLE_AppDefined,
2460 : "Circular dependency with (row=%d, col=%d)", nRow + 1,
2461 : nCol + 1);
2462 0 : return FALSE;
2463 : }
2464 :
2465 111 : oVisisitedCells.insert(std::pair(nRow, nCol));
2466 :
2467 111 : if (poLayer->SetNextByIndex(nRow) != OGRERR_NONE)
2468 : {
2469 0 : CPLError(CE_Failure, CPLE_AppDefined,
2470 : "Cannot fetch feature for row = %d", nRow);
2471 0 : return FALSE;
2472 : }
2473 :
2474 111 : OGRFeature *poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2475 222 : if (poFeature->IsFieldSetAndNotNull(nCol) &&
2476 111 : poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
2477 : {
2478 111 : const char *pszVal = poFeature->GetFieldAsString(nCol);
2479 111 : if (STARTS_WITH(pszVal, "of:="))
2480 : {
2481 110 : ods_formula_node *expr_out = ods_formula_compile(pszVal + 4);
2482 216 : if (expr_out && expr_out->Evaluate(this) &&
2483 106 : expr_out->eNodeType == SNT_CONSTANT)
2484 : {
2485 : /* Refetch feature in case Evaluate() modified another cell in
2486 : * this row */
2487 106 : delete poFeature;
2488 106 : poLayer->SetNextByIndex(nRow);
2489 106 : poFeature = poLayer->GetNextFeatureWithoutFIDHack();
2490 :
2491 106 : if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
2492 : {
2493 0 : poFeature->UnsetField(nCol);
2494 0 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2495 : }
2496 106 : else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
2497 : {
2498 83 : poFeature->SetField(nCol, expr_out->int_value);
2499 83 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2500 : }
2501 23 : else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
2502 : {
2503 7 : poFeature->SetField(nCol, expr_out->float_value);
2504 7 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2505 : }
2506 16 : else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
2507 : {
2508 16 : poFeature->SetField(nCol, expr_out->string_value);
2509 16 : poLayer->SetFeatureWithoutFIDHack(poFeature);
2510 : }
2511 : }
2512 110 : delete expr_out;
2513 : }
2514 : }
2515 :
2516 111 : delete poFeature;
2517 :
2518 111 : return TRUE;
2519 : }
2520 :
2521 : } // namespace OGRODS
|