Coverage Report

Created: 2026-08-11 08:26

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