LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ods - ogrodsdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1009 1185 85.1 %
Date: 2026-11-08 16:45:52 Functions: 62 66 93.9 %

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

Generated by: LCOV version 1.14