LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ods - ogrodsdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1009 1187 85.0 %
Date: 2026-05-12 20:58:36 Functions: 62 66 93.9 %

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

Generated by: LCOV version 1.14