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

Generated by: LCOV version 1.14