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

Generated by: LCOV version 1.14