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

Generated by: LCOV version 1.14