Coverage Report

Created: 2025-11-15 08:43

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