LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/ods - ogrodsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 828 740 89.4 %
Date: 2012-12-26 Functions: 55 47 85.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrodsdatasource.cpp 24173 2012-03-29 21:09:52Z rouault $
       3                 :  *
       4                 :  * Project:  ODS Translator
       5                 :  * Purpose:  Implements OGRODSDataSource class
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_ods.h"
      31                 : #include "ogr_mem.h"
      32                 : #include "ogr_p.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "ods_formula.h"
      35                 : #include <set>
      36                 : 
      37                 : CPL_CVSID("$Id: ogrodsdatasource.cpp 24173 2012-03-29 21:09:52Z rouault $");
      38                 : 
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                          ODSCellEvaluator                            */
      42                 : /************************************************************************/
      43                 : 
      44                 : class ODSCellEvaluator : public IODSCellEvaluator
      45             110 : {
      46                 : private:
      47                 :         OGRODSLayer* poLayer;
      48                 :         std::set<std::pair<int,int> > oVisisitedCells;
      49                 : 
      50                 : public:
      51             110 :         ODSCellEvaluator(OGRODSLayer* poLayerIn) : poLayer(poLayerIn) {}
      52                 : 
      53                 :         int EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
      54                 :                           std::vector<ods_formula_node>& aoOutValues);
      55                 : 
      56                 :         int Evaluate(int nRow, int nCol);
      57                 : };
      58                 : 
      59                 : /************************************************************************/
      60                 : /*                            OGRODSLayer()                            */
      61                 : /************************************************************************/
      62                 : 
      63             115 : OGRODSLayer::OGRODSLayer( OGRODSDataSource* poDSIn,
      64                 :                             const char * pszName,
      65                 :                             int bUpdatedIn) :
      66             115 :                                 OGRMemLayer(pszName, NULL, wkbNone)
      67                 : {
      68             115 :     poDS = poDSIn;
      69             115 :     bUpdated = bUpdatedIn;
      70             115 :     bHasHeaderLine = FALSE;
      71             115 : }
      72                 : 
      73                 : /************************************************************************/
      74                 : /*                             Updated()                                */
      75                 : /************************************************************************/
      76                 : 
      77            1808 : void OGRODSLayer::SetUpdated(int bUpdatedIn)
      78                 : {
      79            1808 :     if (bUpdatedIn && !bUpdated && poDS->GetUpdatable())
      80                 :     {
      81               9 :         bUpdated = TRUE;
      82               9 :         poDS->SetUpdated();
      83                 :     }
      84            1799 :     else if (bUpdated && !bUpdatedIn)
      85                 :     {
      86              17 :         bUpdated = FALSE;
      87                 :     }
      88            1808 : }
      89                 : 
      90                 : /************************************************************************/
      91                 : /*                           SyncToDisk()                               */
      92                 : /************************************************************************/
      93                 : 
      94               0 : OGRErr OGRODSLayer::SyncToDisk()
      95                 : {
      96               0 :     return poDS->SyncToDisk();
      97                 : }
      98                 : 
      99                 : /************************************************************************/
     100                 : /*                          GetNextFeature()                            */
     101                 : /************************************************************************/
     102                 : 
     103            1012 : OGRFeature* OGRODSLayer::GetNextFeature()
     104                 : {
     105            1012 :     OGRFeature* poFeature = OGRMemLayer::GetNextFeature();
     106            1012 :     if (poFeature)
     107             848 :         poFeature->SetFID(poFeature->GetFID() + 1 + bHasHeaderLine);
     108            1012 :     return poFeature;
     109                 : }
     110                 : 
     111                 : /************************************************************************/
     112                 : /*                           GetFeature()                               */
     113                 : /************************************************************************/
     114                 : 
     115              18 : OGRFeature* OGRODSLayer::GetFeature( long nFeatureId )
     116                 : {
     117              18 :     OGRFeature* poFeature = OGRMemLayer::GetFeature(nFeatureId - (1 + bHasHeaderLine));
     118              18 :     if (poFeature)
     119               2 :         poFeature->SetFID(nFeatureId);
     120              18 :     return poFeature;
     121                 : }
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                           SetFeature()                               */
     125                 : /************************************************************************/
     126                 : 
     127             571 : OGRErr OGRODSLayer::SetFeature( OGRFeature *poFeature )
     128                 : {
     129             571 :     if (poFeature == NULL)
     130               0 :         return OGRMemLayer::SetFeature(poFeature);
     131                 : 
     132             571 :     long nFID = poFeature->GetFID();
     133             571 :     if (nFID != OGRNullFID)
     134               1 :         poFeature->SetFID(nFID - (1 + bHasHeaderLine));
     135             571 :     SetUpdated(); 
     136             571 :     OGRErr eErr = OGRMemLayer::SetFeature(poFeature);
     137             571 :     poFeature->SetFID(nFID);
     138             571 :     return eErr;
     139                 : }
     140                 : 
     141                 : /************************************************************************/
     142                 : /*                          DeleteFeature()                             */
     143                 : /************************************************************************/
     144                 : 
     145               0 : OGRErr OGRODSLayer::DeleteFeature( long nFID )
     146                 : {
     147               0 :     SetUpdated();
     148               0 :     return OGRMemLayer::DeleteFeature(nFID - (1 + bHasHeaderLine));
     149                 : }
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                          OGRODSDataSource()                          */
     153                 : /************************************************************************/
     154                 : 
     155              14 : OGRODSDataSource::OGRODSDataSource()
     156                 : 
     157                 : {
     158              14 :     pszName = NULL;
     159              14 :     fpContent = NULL;
     160              14 :     fpSettings = NULL;
     161              14 :     bUpdatable = FALSE;
     162              14 :     bUpdated = FALSE;
     163              14 :     bAnalysedFile = FALSE;
     164                 : 
     165              14 :     nLayers = 0;
     166              14 :     papoLayers = NULL;
     167                 : 
     168              14 :     bFirstLineIsHeaders = FALSE;
     169                 : 
     170              14 :     oParser = NULL;
     171              14 :     bStopParsing = FALSE;
     172              14 :     nWithoutEventCounter = 0;
     173              14 :     nDataHandlerCounter = 0;
     174              14 :     nStackDepth = 0;
     175              14 :     nDepth = 0;
     176              14 :     nCurLine = 0;
     177              14 :     nEmptyRowsAccumulated = 0;
     178              14 :     nCurCol = 0;
     179              14 :     nRowsRepeated = 0;
     180              14 :     nCellsRepeated = 0;
     181              14 :     stateStack[0].eVal = STATE_DEFAULT;
     182              14 :     stateStack[0].nBeginDepth = 0;
     183              14 :     bEndTableParsing = FALSE;
     184                 : 
     185              14 :     poCurLayer = NULL;
     186                 : 
     187                 :     const char* pszODSFieldTypes =
     188              14 :                 CPLGetConfigOption("OGR_ODS_FIELD_TYPES", "");
     189              14 :     bAutodetectTypes = !EQUAL(pszODSFieldTypes, "STRING");
     190              14 : }
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                         ~OGRODSDataSource()                          */
     194                 : /************************************************************************/
     195                 : 
     196              14 : OGRODSDataSource::~OGRODSDataSource()
     197                 : 
     198                 : {
     199              14 :     SyncToDisk();
     200                 : 
     201              14 :     CPLFree( pszName );
     202                 : 
     203              14 :     if (fpContent)
     204               0 :         VSIFCloseL(fpContent);
     205              14 :     if (fpSettings)
     206               0 :         VSIFCloseL(fpSettings);
     207                 : 
     208             119 :     for(int i=0;i<nLayers;i++)
     209             105 :         delete papoLayers[i];
     210              14 :     CPLFree( papoLayers );
     211              14 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                           TestCapability()                           */
     215                 : /************************************************************************/
     216                 : 
     217              12 : int OGRODSDataSource::TestCapability( const char * pszCap )
     218                 : 
     219                 : {
     220              12 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     221               8 :         return bUpdatable;
     222               4 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     223               0 :         return bUpdatable;
     224                 :     else
     225               4 :         return FALSE;
     226                 : }
     227                 : 
     228                 : 
     229                 : /************************************************************************/
     230                 : /*                              GetLayer()                              */
     231                 : /************************************************************************/
     232                 : 
     233             381 : OGRLayer *OGRODSDataSource::GetLayer( int iLayer )
     234                 : 
     235                 : {
     236             381 :     AnalyseFile();
     237             381 :     if (iLayer < 0 || iLayer >= nLayers)
     238               2 :         return NULL;
     239                 : 
     240             379 :     return papoLayers[iLayer];
     241                 : }
     242                 : 
     243                 : /************************************************************************/
     244                 : /*                            GetLayerCount()                           */
     245                 : /************************************************************************/
     246                 : 
     247             351 : int OGRODSDataSource::GetLayerCount()
     248                 : {
     249             351 :     AnalyseFile();
     250             351 :     return nLayers;
     251                 : }
     252                 : 
     253                 : /************************************************************************/
     254                 : /*                                Open()                                */
     255                 : /************************************************************************/
     256                 : 
     257              13 : int OGRODSDataSource::Open( const char * pszFilename,
     258                 :                             VSILFILE* fpContentIn,
     259                 :                             VSILFILE* fpSettingsIn,
     260                 :                             int bUpdatableIn)
     261                 : 
     262                 : {
     263              13 :     bUpdatable = bUpdatableIn;
     264                 : 
     265              13 :     pszName = CPLStrdup( pszFilename );
     266              13 :     fpContent = fpContentIn;
     267              13 :     fpSettings = fpSettingsIn;
     268                 : 
     269              13 :     return TRUE;
     270                 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                             Create()                                 */
     274                 : /************************************************************************/
     275                 : 
     276               1 : int OGRODSDataSource::Create( const char * pszFilename, char **papszOptions )
     277                 : {
     278               1 :     bUpdated = TRUE;
     279               1 :     bUpdatable = TRUE;
     280               1 :     bAnalysedFile = TRUE;
     281                 : 
     282               1 :     pszName = CPLStrdup( pszFilename );
     283                 : 
     284               1 :     return TRUE;
     285                 : }
     286                 : 
     287                 : /************************************************************************/
     288                 : /*                           startElementCbk()                          */
     289                 : /************************************************************************/
     290                 : 
     291            3783 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
     292                 :                                     const char **ppszAttr)
     293                 : {
     294            3783 :     ((OGRODSDataSource*)pUserData)->startElementCbk(pszName, ppszAttr);
     295            3783 : }
     296                 : 
     297            3783 : void OGRODSDataSource::startElementCbk(const char *pszName,
     298                 :                                        const char **ppszAttr)
     299                 : {
     300            3783 :     if (bStopParsing) return;
     301                 : 
     302            3783 :     nWithoutEventCounter = 0;
     303            3783 :     switch(stateStack[nStackDepth].eVal)
     304                 :     {
     305             795 :         case STATE_DEFAULT: startElementDefault(pszName, ppszAttr); break;
     306             652 :         case STATE_TABLE:   startElementTable(pszName, ppszAttr); break;
     307            1561 :         case STATE_ROW:     startElementRow(pszName, ppszAttr); break;
     308             775 :         case STATE_CELL:    startElementCell(pszName, ppszAttr); break;
     309                 :         case STATE_TEXTP:   break;
     310                 :         default:            break;
     311                 :     }
     312            3783 :     nDepth++;
     313                 : }
     314                 : 
     315                 : /************************************************************************/
     316                 : /*                            endElementCbk()                           */
     317                 : /************************************************************************/
     318                 : 
     319            3783 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
     320                 : {
     321            3783 :     ((OGRODSDataSource*)pUserData)->endElementCbk(pszName);
     322            3783 : }
     323                 : 
     324            3783 : void OGRODSDataSource::endElementCbk(const char *pszName)
     325                 : {
     326            3783 :     if (bStopParsing) return;
     327                 : 
     328            3783 :     nWithoutEventCounter = 0;
     329                 : 
     330            3783 :     nDepth--;
     331            3783 :     switch(stateStack[nStackDepth].eVal)
     332                 :     {
     333             688 :         case STATE_DEFAULT: break;
     334             311 :         case STATE_TABLE:   endElementTable(pszName); break;
     335             479 :         case STATE_ROW:     endElementRow(pszName); break;
     336            1887 :         case STATE_CELL:    endElementCell(pszName); break;
     337                 :         case STATE_TEXTP:   break;
     338                 :         default:            break;
     339                 :     }
     340                 : 
     341            3783 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     342            2516 :         nStackDepth --;
     343                 : }
     344                 : 
     345                 : /************************************************************************/
     346                 : /*                            dataHandlerCbk()                          */
     347                 : /************************************************************************/
     348                 : 
     349            2853 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
     350                 : {
     351            2853 :     ((OGRODSDataSource*)pUserData)->dataHandlerCbk(data, nLen);
     352            2853 : }
     353                 : 
     354            2853 : void OGRODSDataSource::dataHandlerCbk(const char *data, int nLen)
     355                 : {
     356            2853 :     if (bStopParsing) return;
     357                 : 
     358            2853 :     nDataHandlerCounter ++;
     359            2853 :     if (nDataHandlerCounter >= BUFSIZ)
     360                 :     {
     361                 :         CPLError(CE_Failure, CPLE_AppDefined,
     362               0 :                  "File probably corrupted (million laugh pattern)");
     363               0 :         XML_StopParser(oParser, XML_FALSE);
     364               0 :         bStopParsing = TRUE;
     365               0 :         return;
     366                 :     }
     367                 : 
     368            2853 :     nWithoutEventCounter = 0;
     369                 : 
     370            2853 :     switch(stateStack[nStackDepth].eVal)
     371                 :     {
     372             306 :         case STATE_DEFAULT: break;
     373             289 :         case STATE_TABLE:   break;
     374            1007 :         case STATE_ROW:     break;
     375             797 :         case STATE_CELL:    break;
     376             454 :         case STATE_TEXTP:   dataHandlerTextP(data, nLen);
     377                 :         default:            break;
     378                 :     }
     379                 : }
     380                 : 
     381                 : /************************************************************************/
     382                 : /*                                PushState()                           */
     383                 : /************************************************************************/
     384                 : 
     385            2503 : void OGRODSDataSource::PushState(HandlerStateEnum eVal)
     386                 : {
     387            2503 :     if (nStackDepth + 1 == STACK_SIZE)
     388                 :     {
     389               0 :         bStopParsing = TRUE;
     390               0 :         return;
     391                 :     }
     392            2503 :     nStackDepth ++;
     393            2503 :     stateStack[nStackDepth].eVal = eVal;
     394            2503 :     stateStack[nStackDepth].nBeginDepth = nDepth;
     395                 : }
     396                 : 
     397                 : /************************************************************************/
     398                 : /*                          GetAttributeValue()                         */
     399                 : /************************************************************************/
     400                 : 
     401           10494 : static const char* GetAttributeValue(const char **ppszAttr,
     402                 :                                      const char* pszKey,
     403                 :                                      const char* pszDefaultVal)
     404                 : {
     405           28201 :     while(*ppszAttr)
     406                 :     {
     407           10313 :         if (strcmp(ppszAttr[0], pszKey) == 0)
     408            3100 :             return ppszAttr[1];
     409            7213 :         ppszAttr += 2;
     410                 :     }
     411            7394 :     return pszDefaultVal;
     412                 : }
     413                 : 
     414                 : /************************************************************************/
     415                 : /*                            GetOGRFieldType()                         */
     416                 : /************************************************************************/
     417                 : 
     418            1029 : OGRFieldType OGRODSDataSource::GetOGRFieldType(const char* pszValue,
     419                 :                                                const char* pszValueType)
     420                 : {
     421            1029 :     if (!bAutodetectTypes || pszValueType == NULL)
     422              30 :         return OFTString;
     423             999 :     else if (strcmp(pszValueType, "string") == 0)
     424             333 :         return OFTString;
     425             666 :     else if (strcmp(pszValueType, "float") == 0 ||
     426                 :              strcmp(pszValueType, "currency") == 0)
     427                 :     {
     428             340 :         if (CPLGetValueType(pszValue) == CPL_VALUE_INTEGER)
     429             241 :             return OFTInteger;
     430                 :         else
     431              99 :             return OFTReal;
     432                 :     }
     433             326 :     else if (strcmp(pszValueType, "percentage") == 0)
     434              35 :         return OFTReal;
     435             291 :     else if (strcmp(pszValueType, "date") == 0)
     436                 :     {
     437             105 :         if (strlen(pszValue) == 4 + 1 + 2 + 1 + 2)
     438              52 :             return OFTDate;
     439                 :         else
     440              53 :             return OFTDateTime;
     441                 :     }
     442             186 :     else if (strcmp(pszValueType, "time") == 0)
     443                 :     {
     444              21 :         return OFTTime;
     445                 :     }
     446                 :     else
     447             165 :         return OFTString;
     448                 : }
     449                 : 
     450                 : /************************************************************************/
     451                 : /*                              SetField()                              */
     452                 : /************************************************************************/
     453                 : 
     454            1012 : static void SetField(OGRFeature* poFeature,
     455                 :                      int i,
     456                 :                      const char* pszValue)
     457                 : {
     458            1012 :     if (pszValue[0] == '\0')
     459             218 :         return;
     460                 : 
     461             794 :     OGRFieldType eType = poFeature->GetFieldDefnRef(i)->GetType();
     462             794 :     if (eType == OFTTime)
     463                 :     {
     464                 :         int nHour, nHourRepeated, nMinute, nSecond;
     465                 :         char c;
     466              10 :         if (strncmp(pszValue, "PT", 2) == 0 &&
     467                 :             sscanf(pszValue + 2, "%02d%c%02d%c%02d%c",
     468                 :                    &nHour, &c, &nMinute, &c, &nSecond, &c) == 6)
     469                 :         {
     470               9 :             poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
     471                 :         }
     472                 :         /* bug with kspread 2.1.2 ? */
     473                 :         /* ex PT121234M56S */
     474               1 :         else if (strncmp(pszValue, "PT", 2) == 0 &&
     475                 :                  sscanf(pszValue + 2, "%02d%02d%02d%c%02d%c",
     476                 :                         &nHour, &nHourRepeated, &nMinute, &c, &nSecond, &c) == 6 &&
     477                 :                  nHour == nHourRepeated)
     478                 :         {
     479               1 :             poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
     480                 :         }
     481                 :     }
     482             839 :     else if (eType == OFTDate || eType == OFTDateTime)
     483                 :     {
     484                 :         int nYear, nMonth, nDay, nHour, nMinute, nTZ;
     485                 :         float fCur;
     486              55 :         if (OGRParseXMLDateTime( pszValue,
     487                 :                                  &nYear, &nMonth, &nDay,
     488                 :                                  &nHour, &nMinute, &fCur, &nTZ) )
     489                 :         {
     490                 :             poFeature->SetField(i, nYear, nMonth, nDay,
     491              55 :                                 nHour, nMinute, (int)fCur, nTZ);
     492                 :         }
     493                 :     }
     494                 :     else
     495             729 :         poFeature->SetField(i, pszValue);
     496                 : }
     497                 : 
     498                 : /************************************************************************/
     499                 : /*                          DetectHeaderLine()                          */
     500                 : /************************************************************************/
     501                 : 
     502              75 : void OGRODSDataSource::DetectHeaderLine()
     503                 : 
     504                 : {
     505              75 :     int bHeaderLineCandidate = TRUE;
     506                 :     size_t i;
     507             267 :     for(i = 0; i < apoFirstLineTypes.size(); i++)
     508                 :     {
     509             217 :         if (apoFirstLineTypes[i] != "string")
     510                 :         {
     511                 :             /* If the values in the first line are not text, then it is */
     512                 :             /* not a header line */
     513              25 :             bHeaderLineCandidate = FALSE;
     514              25 :             break;
     515                 :         }
     516                 :     }
     517                 : 
     518              75 :     size_t nCountTextOnCurLine = 0;
     519              75 :     size_t nCountNonEmptyOnCurLine = 0;
     520             267 :     for(i = 0; bHeaderLineCandidate && i < apoCurLineTypes.size(); i++)
     521                 :     {
     522             192 :         if (apoCurLineTypes[i] == "string")
     523                 :         {
     524                 :             /* If there are only text values on the second line, then we cannot */
     525                 :             /* know if it is a header line or just a regular line */
     526              39 :             nCountTextOnCurLine ++;
     527                 :         }
     528             153 :         else if (apoCurLineTypes[i] != "")
     529                 :         {
     530             129 :             nCountNonEmptyOnCurLine ++;
     531                 :         }
     532                 :     }
     533                 : 
     534              75 :     const char* pszODSHeaders = CPLGetConfigOption("OGR_ODS_HEADERS", "");
     535              75 :     bFirstLineIsHeaders = FALSE;
     536              75 :     if (EQUAL(pszODSHeaders, "FORCE"))
     537               0 :         bFirstLineIsHeaders = TRUE;
     538              75 :     else if (EQUAL(pszODSHeaders, "DISABLE"))
     539               6 :         bFirstLineIsHeaders = FALSE;
     540              69 :     else if (osSetLayerHasSplitter.find(poCurLayer->GetName()) !=
     541                 :              osSetLayerHasSplitter.end())
     542                 :     {
     543               2 :         bFirstLineIsHeaders = TRUE;
     544                 :     }
     545              67 :     else if (bHeaderLineCandidate &&
     546                 :              apoFirstLineTypes.size() != 0 &&
     547                 :              apoFirstLineTypes.size() == apoCurLineTypes.size() &&
     548                 :              nCountTextOnCurLine != apoFirstLineTypes.size() &&
     549                 :              nCountNonEmptyOnCurLine != 0)
     550                 :     {
     551               9 :         bFirstLineIsHeaders = TRUE;
     552                 :     }
     553                 :     CPLDebug("ODS", "%s %s",
     554              75 :              poCurLayer->GetName(),
     555             150 :              bFirstLineIsHeaders ? "has header line" : "has no header line");
     556              75 : }
     557                 : 
     558                 : /************************************************************************/
     559                 : /*                          startElementDefault()                       */
     560                 : /************************************************************************/
     561                 : 
     562             795 : void OGRODSDataSource::startElementDefault(const char *pszName,
     563                 :                                            const char **ppszAttr)
     564                 : {
     565             795 :     if (strcmp(pszName, "table:table") == 0)
     566                 :     {
     567                 :         const char* pszTableName =
     568             107 :             GetAttributeValue(ppszAttr, "table:name", "unnamed");
     569                 : 
     570             107 :         poCurLayer = new OGRODSLayer(this, pszTableName);
     571             107 :         papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     572             107 :         papoLayers[nLayers++] = poCurLayer;
     573                 : 
     574             107 :         nCurLine = 0;
     575             107 :         nEmptyRowsAccumulated = 0;
     576             214 :         apoFirstLineValues.resize(0);
     577             214 :         apoFirstLineTypes.resize(0);
     578             107 :         PushState(STATE_TABLE);
     579             107 :         bEndTableParsing = FALSE;
     580                 :     }
     581             795 : }
     582                 : 
     583                 : /************************************************************************/
     584                 : /*                          startElementTable()                        */
     585                 : /************************************************************************/
     586                 : 
     587             652 : void OGRODSDataSource::startElementTable(const char *pszName,
     588                 :                                          const char **ppszAttr)
     589                 : {
     590             652 :     if (strcmp(pszName, "table:table-row") == 0 && !bEndTableParsing)
     591                 :     {
     592                 :         nRowsRepeated = atoi(
     593             448 :             GetAttributeValue(ppszAttr, "table:number-rows-repeated", "1"));
     594             448 :         if (nRowsRepeated > 65536)
     595                 :         {
     596               0 :             bEndTableParsing = TRUE;
     597               0 :             return;
     598                 :         }
     599                 : 
     600             448 :         nCurCol = 0;
     601                 : 
     602             448 :         apoCurLineValues.resize(0);
     603             896 :         apoCurLineTypes.resize(0);
     604                 : 
     605             448 :         PushState(STATE_ROW);
     606                 :     }
     607                 : }
     608                 : 
     609                 : /************************************************************************/
     610                 : /*                           endElementTable()                          */
     611                 : /************************************************************************/
     612                 : 
     613             311 : void OGRODSDataSource::endElementTable(const char *pszName)
     614                 : {
     615             311 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     616                 :     {
     617             107 :         CPLAssert(strcmp(pszName, "table:table") == 0);
     618                 : 
     619             107 :         if (nCurLine == 0 ||
     620                 :             (nCurLine == 1 && apoFirstLineValues.size() == 0))
     621                 :         {
     622                 :             /* Remove empty sheet */
     623              10 :             delete poCurLayer;
     624              10 :             nLayers --;
     625              10 :             poCurLayer = NULL;
     626                 :         }
     627              97 :         else if (nCurLine == 1)
     628                 :         {
     629                 :             /* If we have only one single line in the sheet */
     630                 :             size_t i;
     631              36 :             for(i = 0; i < apoFirstLineValues.size(); i++)
     632                 :             {
     633              24 :                 const char* pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
     634                 :                 OGRFieldType eType = GetOGRFieldType(apoFirstLineValues[i].c_str(),
     635              24 :                                                      apoFirstLineTypes[i].c_str());
     636              24 :                 OGRFieldDefn oFieldDefn(pszFieldName, eType);
     637              24 :                 poCurLayer->CreateField(&oFieldDefn);
     638                 :             }
     639                 : 
     640              12 :             OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     641              36 :             for(i = 0; i < apoFirstLineValues.size(); i++)
     642                 :             {
     643              24 :                 SetField(poFeature, i, apoFirstLineValues[i].c_str());
     644                 :             }
     645              12 :             poCurLayer->CreateFeature(poFeature);
     646              12 :             delete poFeature;
     647                 :         }
     648                 : 
     649             107 :         if (poCurLayer)
     650                 :         {
     651                 :             OGRFeature* poFeature;
     652                 : 
     653              97 :             if (CSLTestBoolean(CPLGetConfigOption("ODS_RESOLVE_FORMULAS", "YES")))
     654                 :             {
     655              97 :                 poCurLayer->ResetReading();
     656                 : 
     657              97 :                 int nRow = 0;
     658              97 :                 poFeature = poCurLayer->GetNextFeature();
     659             721 :                 while (poFeature)
     660                 :                 {
     661            3403 :                     for(int i=0;i<poFeature->GetFieldCount();i++)
     662                 :                     {
     663            2876 :                         if (poFeature->IsFieldSet(i) &&
     664                 :                             poFeature->GetFieldDefnRef(i)->GetType() == OFTString)
     665                 :                         {
     666             595 :                             const char* pszVal = poFeature->GetFieldAsString(i);
     667             595 :                             if (strncmp(pszVal, "of:=", 4) == 0)
     668                 :                             {
     669             110 :                                 ODSCellEvaluator oCellEvaluator(poCurLayer);
     670             110 :                                 oCellEvaluator.Evaluate(nRow, i);
     671                 :                             }
     672                 :                         }
     673                 :                     }
     674             527 :                     delete poFeature;
     675                 : 
     676             527 :                     poFeature = poCurLayer->GetNextFeature();
     677             527 :                     nRow ++;
     678                 :                 }
     679                 :             }
     680                 : 
     681              97 :             poCurLayer->ResetReading();
     682                 : 
     683              97 :             ((OGRMemLayer*)poCurLayer)->SetUpdatable(bUpdatable);
     684              97 :             ((OGRMemLayer*)poCurLayer)->SetAdvertizeUTF8(TRUE);
     685              97 :             ((OGRODSLayer*)poCurLayer)->SetUpdated(FALSE);
     686                 :         }
     687                 : 
     688             107 :         poCurLayer = NULL;
     689                 :     }
     690             311 : }
     691                 : 
     692                 : /************************************************************************/
     693                 : /*                            startElementRow()                         */
     694                 : /************************************************************************/
     695                 : 
     696            1561 : void OGRODSDataSource::startElementRow(const char *pszName,
     697                 :                                        const char **ppszAttr)
     698                 : {
     699            1561 :     if (strcmp(pszName, "table:table-cell") == 0)
     700                 :     {
     701            1530 :         PushState(STATE_CELL);
     702                 : 
     703            1530 :         osValueType = GetAttributeValue(ppszAttr, "office:value-type", "");
     704                 :         const char* pszValue =
     705            1530 :             GetAttributeValue(ppszAttr, "office:value", NULL);
     706            1530 :         if (pszValue)
     707             311 :             osValue = pszValue;
     708                 :         else
     709                 :         {
     710                 :             const char* pszDateValue =
     711            1219 :                 GetAttributeValue(ppszAttr, "office:date-value", NULL);
     712            1219 :             if (pszDateValue)
     713              65 :                 osValue = pszDateValue;
     714                 :             else
     715            1154 :                 osValue = GetAttributeValue(ppszAttr, "office:time-value", "");
     716                 :         }
     717                 : 
     718            1530 :         const char* pszFormula = GetAttributeValue(ppszAttr, "table:formula", NULL);
     719            1667 :         if (pszFormula && strncmp(pszFormula, "of:=", 4) == 0)
     720                 :         {
     721             137 :             osFormula = pszFormula;
     722             137 :             if (osValueType.size() == 0)
     723             110 :                 osValueType = "formula";
     724                 :         }
     725                 :         else
     726            1393 :             osFormula = "";
     727                 : 
     728                 :         nCellsRepeated = atoi(
     729            1530 :             GetAttributeValue(ppszAttr, "table:number-columns-repeated", "1"));
     730                 :     }
     731              31 :     else if (strcmp(pszName, "table:covered-table-cell") == 0)
     732                 :     {
     733                 :         /* Merged cell */
     734              31 :         apoCurLineValues.push_back("");
     735              62 :         apoCurLineTypes.push_back("");
     736                 : 
     737              31 :         nCurCol += 1;
     738                 :     }
     739            1561 : }
     740                 : 
     741                 : /************************************************************************/
     742                 : /*                            endElementRow()                           */
     743                 : /************************************************************************/
     744                 : 
     745             479 : void OGRODSDataSource::endElementRow(const char *pszName)
     746                 : {
     747             479 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     748                 :     {
     749             448 :         CPLAssert(strcmp(pszName, "table:table-row") == 0);
     750                 : 
     751                 :         OGRFeature* poFeature;
     752                 :         size_t i;
     753                 : 
     754                 :         /* Remove blank columns at the right to defer type evaluation */
     755                 :         /* until necessary */
     756             448 :         i = apoCurLineTypes.size();
     757            1988 :         while(i > 0)
     758                 :         {
     759            1464 :             i --;
     760            1464 :             if (apoCurLineTypes[i] == "")
     761                 :             {
     762            1092 :                 apoCurLineValues.resize(i);
     763            2184 :                 apoCurLineTypes.resize(i);
     764                 :             }
     765                 :             else
     766             372 :                 break;
     767                 :         }
     768                 : 
     769                 :         /* Do not add immediately empty rows. Wait until there is another non */
     770                 :         /* empty row */
     771             448 :         if (nCurLine >= 2 && apoCurLineTypes.size() == 0)
     772                 :         {
     773              28 :             nEmptyRowsAccumulated += nRowsRepeated;
     774              28 :             return;
     775                 :         }
     776             420 :         else if (nEmptyRowsAccumulated > 0)
     777                 :         {
     778             120 :             for(i = 0; i < (size_t)nEmptyRowsAccumulated; i++)
     779                 :             {
     780             108 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     781             108 :                 poCurLayer->CreateFeature(poFeature);
     782             216 :                 delete poFeature;
     783                 :             }
     784              12 :             nCurLine += nEmptyRowsAccumulated;
     785              12 :             nEmptyRowsAccumulated = 0;
     786                 :         }
     787                 : 
     788                 :         /* Backup first line values and types in special arrays */
     789             420 :         if (nCurLine == 0)
     790                 :         {
     791             107 :             apoFirstLineTypes = apoCurLineTypes;
     792             107 :             apoFirstLineValues = apoCurLineValues;
     793                 : 
     794                 :     #if skip_leading_empty_rows
     795                 :             if (apoFirstLineTypes.size() == 0)
     796                 :             {
     797                 :                 /* Skip leading empty rows */
     798                 :                 apoFirstLineTypes.resize(0);
     799                 :                 apoFirstLineValues.resize(0);
     800                 :                 return;
     801                 :             }
     802                 :     #endif
     803                 :         }
     804                 : 
     805             420 :         if (nCurLine == 1)
     806                 :         {
     807              75 :             DetectHeaderLine();
     808                 : 
     809              75 :             poCurLayer->SetHasHeaderLine(bFirstLineIsHeaders);
     810                 : 
     811              75 :             if (bFirstLineIsHeaders)
     812                 :             {
     813             143 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     814                 :                 {
     815             132 :                     const char* pszFieldName = apoFirstLineValues[i].c_str();
     816             132 :                     if (pszFieldName[0] == '\0')
     817               0 :                         pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
     818             132 :                     OGRFieldType eType = OFTString;
     819             132 :                     if (i < apoCurLineValues.size())
     820                 :                     {
     821                 :                         eType = GetOGRFieldType(apoCurLineValues[i].c_str(),
     822             132 :                                                 apoCurLineTypes[i].c_str());
     823                 :                     }
     824             132 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     825             132 :                     poCurLayer->CreateField(&oFieldDefn);
     826                 :                 }
     827                 :             }
     828                 :             else
     829                 :             {
     830             163 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     831                 :                 {
     832                 :                     const char* pszFieldName =
     833              99 :                         CPLSPrintf("Field%d", (int)i + 1);
     834                 :                     OGRFieldType eType = GetOGRFieldType(
     835                 :                                             apoFirstLineValues[i].c_str(),
     836              99 :                                             apoFirstLineTypes[i].c_str());
     837              99 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     838              99 :                     poCurLayer->CreateField(&oFieldDefn);
     839                 :                 }
     840                 : 
     841              64 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     842             163 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     843                 :                 {
     844              99 :                     SetField(poFeature, i, apoFirstLineValues[i].c_str());
     845                 :                 }
     846              64 :                 poCurLayer->CreateFeature(poFeature);
     847              64 :                 delete poFeature;
     848                 :             }
     849                 :         }
     850                 : 
     851             420 :         if (nCurLine >= 1 || (nCurLine == 0 && nRowsRepeated > 1))
     852                 :         {
     853                 :             /* Add new fields found on following lines. */
     854             646 :             if (apoCurLineValues.size() >
     855             323 :                 (size_t)poCurLayer->GetLayerDefn()->GetFieldCount())
     856                 :             {
     857             199 :                 for(i = (size_t)poCurLayer->GetLayerDefn()->GetFieldCount();
     858                 :                     i < apoCurLineValues.size();
     859                 :                     i++)
     860                 :                 {
     861                 :                     const char* pszFieldName =
     862             137 :                         CPLSPrintf("Field%d", (int)i + 1);
     863                 :                     OGRFieldType eType = GetOGRFieldType(
     864                 :                                                 apoCurLineValues[i].c_str(),
     865             137 :                                                 apoCurLineTypes[i].c_str());
     866             137 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     867             137 :                     poCurLayer->CreateField(&oFieldDefn);
     868                 :                 }
     869                 :             }
     870                 : 
     871                 :             /* Update field type if necessary */
     872             323 :             if (bAutodetectTypes)
     873                 :             {
     874            1111 :                 for(i = 0; i < apoCurLineValues.size(); i++)
     875                 :                 {
     876             815 :                     if (apoCurLineValues[i].size())
     877                 :                     {
     878                 :                         OGRFieldType eValType = GetOGRFieldType(
     879                 :                                                 apoCurLineValues[i].c_str(),
     880             637 :                                                 apoCurLineTypes[i].c_str());
     881                 :                         OGRFieldType eFieldType =
     882             637 :                             poCurLayer->GetLayerDefn()->GetFieldDefn(i)->GetType();
     883             637 :                         if (eFieldType == OFTDateTime &&
     884                 :                             (eValType == OFTDate || eValType == OFTTime) )
     885                 :                         {
     886                 :                             /* ok */
     887                 :                         }
     888             637 :                         else if (eFieldType == OFTReal && eValType == OFTInteger)
     889                 :                         {
     890                 :                            /* ok */;
     891                 :                         }
     892             629 :                         else if (eFieldType != OFTString && eValType != eFieldType)
     893                 :                         {
     894                 :                             OGRFieldDefn oNewFieldDefn(
     895              26 :                                 poCurLayer->GetLayerDefn()->GetFieldDefn(i));
     896              33 :                             if ((eFieldType == OFTDate || eFieldType == OFTTime) &&
     897                 :                                    eValType == OFTDateTime)
     898               7 :                                 oNewFieldDefn.SetType(OFTDateTime);
     899              27 :                             else if (eFieldType == OFTInteger &&
     900                 :                                      eValType == OFTReal)
     901               8 :                                 oNewFieldDefn.SetType(OFTReal);
     902                 :                             else
     903              11 :                                 oNewFieldDefn.SetType(OFTString);
     904                 :                             poCurLayer->AlterFieldDefn(i, &oNewFieldDefn,
     905              26 :                                                        ALTER_TYPE_FLAG);
     906                 :                         }
     907                 :                     }
     908                 :                 }
     909                 :             }
     910                 : 
     911                 :             /* Add feature for current line */
     912             666 :             for(int j=0;j<nRowsRepeated;j++)
     913                 :             {
     914             343 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     915            1232 :                 for(i = 0; i < apoCurLineValues.size(); i++)
     916                 :                 {
     917             889 :                     SetField(poFeature, i, apoCurLineValues[i].c_str());
     918                 :                 }
     919             343 :                 poCurLayer->CreateFeature(poFeature);
     920             343 :                 delete poFeature;
     921                 :             }
     922                 :         }
     923                 : 
     924             420 :         nCurLine += nRowsRepeated;
     925                 :     }
     926                 : }
     927                 : 
     928                 : /************************************************************************/
     929                 : /*                           startElementCell()                         */
     930                 : /************************************************************************/
     931                 : 
     932             775 : void OGRODSDataSource::startElementCell(const char *pszName,
     933                 :                                         const char **ppszAttr)
     934                 : {
     935             775 :     if (osValue.size() == 0 && strcmp(pszName, "text:p") == 0)
     936                 :     {
     937             418 :         PushState(STATE_TEXTP);
     938                 :     }
     939             775 : }
     940                 : 
     941                 : /************************************************************************/
     942                 : /*                            endElementCell()                          */
     943                 : /************************************************************************/
     944                 : 
     945            1887 : void OGRODSDataSource::endElementCell(const char *pszName)
     946                 : {
     947            1887 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     948                 :     {
     949            1530 :         CPLAssert(strcmp(pszName, "table:table-cell") == 0);
     950                 : 
     951            3725 :         for(int i = 0; i < nCellsRepeated; i++)
     952                 :         {
     953            2195 :             apoCurLineValues.push_back(osValue.size() ? osValue : osFormula);
     954            2195 :             apoCurLineTypes.push_back(osValueType);
     955                 :         }
     956                 : 
     957            1530 :         nCurCol += nCellsRepeated;
     958                 :     }
     959            1887 : }
     960                 : 
     961                 : /************************************************************************/
     962                 : /*                           dataHandlerTextP()                         */
     963                 : /************************************************************************/
     964                 : 
     965             454 : void OGRODSDataSource::dataHandlerTextP(const char *data, int nLen)
     966                 : {
     967             454 :     osValue.append(data, nLen);
     968             454 : }
     969                 : 
     970                 : /************************************************************************/
     971                 : /*                             AnalyseFile()                            */
     972                 : /************************************************************************/
     973                 : 
     974             740 : void OGRODSDataSource::AnalyseFile()
     975                 : {
     976             740 :     if (bAnalysedFile)
     977             727 :         return;
     978                 : 
     979              13 :     bAnalysedFile = TRUE;
     980                 : 
     981              13 :     AnalyseSettings();
     982                 : 
     983              13 :     oParser = OGRCreateExpatXMLParser();
     984              13 :     XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
     985              13 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
     986              13 :     XML_SetUserData(oParser, this);
     987                 : 
     988              13 :     nDepth = 0;
     989              13 :     nStackDepth = 0;
     990              13 :     stateStack[0].nBeginDepth = 0;
     991              13 :     bStopParsing = FALSE;
     992              13 :     nWithoutEventCounter = 0;
     993                 : 
     994              13 :     VSIFSeekL( fpContent, 0, SEEK_SET );
     995                 : 
     996                 :     char aBuf[BUFSIZ];
     997                 :     int nDone;
     998              50 :     do
     999                 :     {
    1000              50 :         nDataHandlerCounter = 0;
    1001                 :         unsigned int nLen =
    1002              50 :             (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpContent );
    1003              50 :         nDone = VSIFEofL(fpContent);
    1004              50 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1005                 :         {
    1006                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1007                 :                      "XML parsing of ODS file failed : %s at line %d, column %d",
    1008                 :                      XML_ErrorString(XML_GetErrorCode(oParser)),
    1009                 :                      (int)XML_GetCurrentLineNumber(oParser),
    1010               0 :                      (int)XML_GetCurrentColumnNumber(oParser));
    1011               0 :             bStopParsing = TRUE;
    1012                 :         }
    1013              50 :         nWithoutEventCounter ++;
    1014                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1015                 : 
    1016              13 :     XML_ParserFree(oParser);
    1017              13 :     oParser = NULL;
    1018                 : 
    1019              13 :     if (nWithoutEventCounter == 10)
    1020                 :     {
    1021                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1022               0 :                  "Too much data inside one element. File probably corrupted");
    1023               0 :         bStopParsing = TRUE;
    1024                 :     }
    1025                 : 
    1026              13 :     VSIFCloseL(fpContent);
    1027              13 :     fpContent = NULL;
    1028                 : 
    1029              13 :     bUpdated = FALSE;
    1030                 : }
    1031                 : 
    1032                 : /************************************************************************/
    1033                 : /*                        startElementStylesCbk()                       */
    1034                 : /************************************************************************/
    1035                 : 
    1036            2060 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
    1037                 :                                     const char **ppszAttr)
    1038                 : {
    1039            2060 :     ((OGRODSDataSource*)pUserData)->startElementStylesCbk(pszName, ppszAttr);
    1040            2060 : }
    1041                 : 
    1042            2060 : void OGRODSDataSource::startElementStylesCbk(const char *pszName,
    1043                 :                                              const char **ppszAttr)
    1044                 : {
    1045            2060 :     if (bStopParsing) return;
    1046                 : 
    1047            2060 :     nWithoutEventCounter = 0;
    1048                 : 
    1049            2060 :     if (nStackDepth == 0 &&
    1050                 :         strcmp(pszName, "config:config-item-map-named") == 0 &&
    1051                 :         strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
    1052                 :     {
    1053              12 :         stateStack[++nStackDepth].nBeginDepth = nDepth;
    1054                 :     }
    1055            2140 :     else if (nStackDepth == 1 && strcmp(pszName, "config:config-item-map-entry") == 0)
    1056                 :     {
    1057              92 :         const char* pszTableName = GetAttributeValue(ppszAttr, "config:name", NULL);
    1058              92 :         if (pszTableName)
    1059                 :         {
    1060              92 :             osCurrentConfigTableName = pszTableName;
    1061              92 :             nFlags = 0;
    1062              92 :             stateStack[++nStackDepth].nBeginDepth = nDepth;
    1063                 :         }
    1064                 :     }
    1065            1956 :     else if (nStackDepth == 2 && strcmp(pszName, "config:config-item") == 0)
    1066                 :     {
    1067            1342 :         const char* pszConfigName = GetAttributeValue(ppszAttr, "config:name", NULL);
    1068            1342 :         if (pszConfigName)
    1069                 :         {
    1070            1342 :             osConfigName = pszConfigName;
    1071            1342 :             osValue = "";
    1072            1342 :             stateStack[++nStackDepth].nBeginDepth = nDepth;
    1073                 :         }
    1074                 :     }
    1075                 : 
    1076            2060 :     nDepth++;
    1077                 : }
    1078                 : 
    1079                 : /************************************************************************/
    1080                 : /*                        endElementStylesCbk()                         */
    1081                 : /************************************************************************/
    1082                 : 
    1083            2060 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
    1084                 : {
    1085            2060 :     ((OGRODSDataSource*)pUserData)->endElementStylesCbk(pszName);
    1086            2060 : }
    1087                 : 
    1088            2060 : void OGRODSDataSource::endElementStylesCbk(const char *pszName)
    1089                 : {
    1090            2060 :     if (bStopParsing) return;
    1091                 : 
    1092            2060 :     nWithoutEventCounter = 0;
    1093            2060 :     nDepth--;
    1094                 : 
    1095            2060 :     if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
    1096                 :     {
    1097            1446 :         if (nStackDepth == 2)
    1098                 :         {
    1099              92 :             if (nFlags == (1 | 2))
    1100               2 :                 osSetLayerHasSplitter.insert(osCurrentConfigTableName);
    1101                 :         }
    1102            1446 :         if (nStackDepth == 3)
    1103                 :         {
    1104            1342 :             if (osConfigName == "VerticalSplitMode" && osValue == "2")
    1105               2 :                 nFlags |= 1;
    1106            1340 :             else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
    1107               2 :                 nFlags |= 2;
    1108                 :         }
    1109            1446 :         nStackDepth --;
    1110                 :     }
    1111                 : }
    1112                 : 
    1113                 : /************************************************************************/
    1114                 : /*                         dataHandlerStylesCbk()                       */
    1115                 : /************************************************************************/
    1116                 : 
    1117            2161 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data, int nLen)
    1118                 : {
    1119            2161 :     ((OGRODSDataSource*)pUserData)->dataHandlerStylesCbk(data, nLen);
    1120            2161 : }
    1121                 : 
    1122            2161 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
    1123                 : {
    1124            2161 :     if (bStopParsing) return;
    1125                 : 
    1126            2161 :     nDataHandlerCounter ++;
    1127            2161 :     if (nDataHandlerCounter >= BUFSIZ)
    1128                 :     {
    1129                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1130               0 :                  "File probably corrupted (million laugh pattern)");
    1131               0 :         XML_StopParser(oParser, XML_FALSE);
    1132               0 :         bStopParsing = TRUE;
    1133               0 :         return;
    1134                 :     }
    1135                 : 
    1136            2161 :     nWithoutEventCounter = 0;
    1137                 : 
    1138            2161 :     if (nStackDepth == 3)
    1139                 :     {
    1140            1342 :         osValue.append(data, nLen);
    1141                 :     }
    1142                 : }
    1143                 : 
    1144                 : /************************************************************************/
    1145                 : /*                           AnalyseSettings()                          */
    1146                 : /*                                                                      */
    1147                 : /* We parse settings.xml to see which layers have a vertical splitter   */
    1148                 : /* on the first line, so as to use it as the header line.               */
    1149                 : /************************************************************************/
    1150                 : 
    1151              13 : void OGRODSDataSource::AnalyseSettings()
    1152                 : {
    1153              13 :     if (fpSettings == NULL)
    1154               1 :         return;
    1155                 : 
    1156              12 :     oParser = OGRCreateExpatXMLParser();
    1157              12 :     XML_SetElementHandler(oParser, ::startElementStylesCbk, ::endElementStylesCbk);
    1158              12 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerStylesCbk);
    1159              12 :     XML_SetUserData(oParser, this);
    1160                 : 
    1161              12 :     nDepth = 0;
    1162              12 :     nStackDepth = 0;
    1163              12 :     bStopParsing = FALSE;
    1164              12 :     nWithoutEventCounter = 0;
    1165                 : 
    1166              12 :     VSIFSeekL( fpSettings, 0, SEEK_SET );
    1167                 : 
    1168                 :     char aBuf[BUFSIZ];
    1169                 :     int nDone;
    1170              43 :     do
    1171                 :     {
    1172              43 :         nDataHandlerCounter = 0;
    1173                 :         unsigned int nLen =
    1174              43 :             (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpSettings );
    1175              43 :         nDone = VSIFEofL(fpSettings);
    1176              43 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1177                 :         {
    1178                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1179                 :                      "XML parsing of styles.xml file failed : %s at line %d, column %d",
    1180                 :                      XML_ErrorString(XML_GetErrorCode(oParser)),
    1181                 :                      (int)XML_GetCurrentLineNumber(oParser),
    1182               0 :                      (int)XML_GetCurrentColumnNumber(oParser));
    1183               0 :             bStopParsing = TRUE;
    1184                 :         }
    1185              43 :         nWithoutEventCounter ++;
    1186                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1187                 : 
    1188              12 :     XML_ParserFree(oParser);
    1189              12 :     oParser = NULL;
    1190                 : 
    1191              12 :     if (nWithoutEventCounter == 10)
    1192                 :     {
    1193                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1194               0 :                  "Too much data inside one element. File probably corrupted");
    1195               0 :         bStopParsing = TRUE;
    1196                 :     }
    1197                 : 
    1198              12 :     VSIFCloseL(fpSettings);
    1199              12 :     fpSettings = NULL;
    1200                 : }
    1201                 : 
    1202                 : /************************************************************************/
    1203                 : /*                            CreateLayer()                             */
    1204                 : /************************************************************************/
    1205                 : 
    1206                 : OGRLayer *
    1207               8 : OGRODSDataSource::CreateLayer( const char * pszLayerName,
    1208                 :                                 OGRSpatialReference *poSRS,
    1209                 :                                 OGRwkbGeometryType eType,
    1210                 :                                 char ** papszOptions )
    1211                 : 
    1212                 : {
    1213                 : /* -------------------------------------------------------------------- */
    1214                 : /*      Verify we are in update mode.                                   */
    1215                 : /* -------------------------------------------------------------------- */
    1216               8 :     if( !bUpdatable )
    1217                 :     {
    1218                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
    1219                 :                   "Data source %s opened read-only.\n"
    1220                 :                   "New layer %s cannot be created.\n",
    1221               0 :                   pszName, pszLayerName );
    1222                 : 
    1223               0 :         return NULL;
    1224                 :     }
    1225                 : 
    1226               8 :     AnalyseFile();
    1227                 : 
    1228                 : /* -------------------------------------------------------------------- */
    1229                 : /*      Do we already have this layer?  If so, should we blow it        */
    1230                 : /*      away?                                                           */
    1231                 : /* -------------------------------------------------------------------- */
    1232                 :     int iLayer;
    1233                 : 
    1234              36 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
    1235                 :     {
    1236              28 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) )
    1237                 :         {
    1238               0 :             if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
    1239                 :                 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
    1240                 :             {
    1241               0 :                 DeleteLayer( pszLayerName );
    1242                 :             }
    1243                 :             else
    1244                 :             {
    1245                 :                 CPLError( CE_Failure, CPLE_AppDefined,
    1246                 :                           "Layer %s already exists, CreateLayer failed.\n"
    1247                 :                           "Use the layer creation option OVERWRITE=YES to "
    1248                 :                           "replace it.",
    1249               0 :                           pszLayerName );
    1250               0 :                 return NULL;
    1251                 :             }
    1252                 :         }
    1253                 :     }
    1254                 : 
    1255                 : /* -------------------------------------------------------------------- */
    1256                 : /*      Create the layer object.                                        */
    1257                 : /* -------------------------------------------------------------------- */
    1258               8 :     OGRLayer* poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
    1259                 : 
    1260               8 :     papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
    1261               8 :     papoLayers[nLayers] = poLayer;
    1262               8 :     nLayers ++;
    1263                 : 
    1264               8 :     bUpdated = TRUE;
    1265                 : 
    1266               8 :     return poLayer;
    1267                 : }
    1268                 : 
    1269                 : /************************************************************************/
    1270                 : /*                            DeleteLayer()                             */
    1271                 : /************************************************************************/
    1272                 : 
    1273               0 : void OGRODSDataSource::DeleteLayer( const char *pszLayerName )
    1274                 : 
    1275                 : {
    1276                 :     int iLayer;
    1277                 : 
    1278                 : /* -------------------------------------------------------------------- */
    1279                 : /*      Verify we are in update mode.                                   */
    1280                 : /* -------------------------------------------------------------------- */
    1281               0 :     if( !bUpdatable )
    1282                 :     {
    1283                 :         CPLError( CE_Failure, CPLE_NoWriteAccess,
    1284                 :                   "Data source %s opened read-only.\n"
    1285                 :                   "Layer %s cannot be deleted.\n",
    1286               0 :                   pszName, pszLayerName );
    1287                 : 
    1288               0 :         return;
    1289                 :     }
    1290                 : 
    1291                 : /* -------------------------------------------------------------------- */
    1292                 : /*      Try to find layer.                                              */
    1293                 : /* -------------------------------------------------------------------- */
    1294               0 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
    1295                 :     {
    1296               0 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) )
    1297               0 :             break;
    1298                 :     }
    1299                 : 
    1300               0 :     if( iLayer == nLayers )
    1301                 :     {
    1302                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1303                 :                   "Attempt to delete layer '%s', but this layer is not known to OGR.",
    1304               0 :                   pszLayerName );
    1305               0 :         return;
    1306                 :     }
    1307                 : 
    1308               0 :     DeleteLayer(iLayer);
    1309                 : }
    1310                 : 
    1311                 : /************************************************************************/
    1312                 : /*                            DeleteLayer()                             */
    1313                 : /************************************************************************/
    1314                 : 
    1315               0 : OGRErr OGRODSDataSource::DeleteLayer(int iLayer)
    1316                 : {
    1317               0 :     AnalyseFile();
    1318                 : 
    1319               0 :     if( iLayer < 0 || iLayer >= nLayers )
    1320                 :     {
    1321                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1322                 :                   "Layer %d not in legal range of 0 to %d.",
    1323               0 :                   iLayer, nLayers-1 );
    1324               0 :         return OGRERR_FAILURE;
    1325                 :     }
    1326                 : 
    1327                 : /* -------------------------------------------------------------------- */
    1328                 : /*      Blow away our OGR structures related to the layer.  This is     */
    1329                 : /*      pretty dangerous if anything has a reference to this layer!     */
    1330                 : /* -------------------------------------------------------------------- */
    1331                 : 
    1332               0 :     delete papoLayers[iLayer];
    1333                 :     memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
    1334               0 :              sizeof(void *) * (nLayers - iLayer - 1) );
    1335               0 :     nLayers--;
    1336                 : 
    1337               0 :     bUpdated = TRUE;
    1338                 : 
    1339               0 :     return OGRERR_NONE;
    1340                 : }
    1341                 : 
    1342                 : /************************************************************************/
    1343                 : /*                           HasHeaderLine()                            */
    1344                 : /************************************************************************/
    1345                 : 
    1346              32 : static int HasHeaderLine(OGRLayer* poLayer)
    1347                 : {
    1348              32 :     OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
    1349              32 :     int bHasHeaders = FALSE;
    1350                 : 
    1351             152 :     for(int j=0;j<poFDefn->GetFieldCount();j++)
    1352                 :     {
    1353             120 :         if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
    1354                 :                     CPLSPrintf("Field%d", j+1)) != 0)
    1355              48 :             bHasHeaders = TRUE;
    1356                 :     }
    1357                 : 
    1358              32 :     return bHasHeaders;
    1359                 : }
    1360                 : 
    1361                 : /************************************************************************/
    1362                 : /*                            WriteLayer()                              */
    1363                 : /************************************************************************/
    1364                 : 
    1365              16 : static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
    1366                 : {
    1367                 :     int j;
    1368              16 :     const char* pszLayerName = poLayer->GetName();
    1369              16 :     char* pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
    1370              16 :     VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
    1371              16 :     CPLFree(pszXML);
    1372                 :     
    1373              16 :     poLayer->ResetReading();
    1374                 : 
    1375              16 :     OGRFeature* poFeature = poLayer->GetNextFeature();
    1376                 : 
    1377              16 :     OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
    1378              16 :     int bHasHeaders = HasHeaderLine(poLayer);
    1379                 : 
    1380              76 :     for(j=0;j<poFDefn->GetFieldCount();j++)
    1381                 :     {
    1382              60 :         int nStyleNumber = 1;
    1383              60 :         if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
    1384               6 :             nStyleNumber = 2;
    1385                 :         VSIFPrintfL(fp, "<table:table-column table:style-name=\"co%d\" "
    1386                 :                         "table:default-cell-style-name=\"Default\"/>\n",
    1387              60 :                     nStyleNumber);
    1388                 :     }
    1389                 : 
    1390              16 :     if (bHasHeaders && poFeature != NULL)
    1391                 :     {
    1392               2 :         VSIFPrintfL(fp, "<table:table-row>\n");
    1393              26 :         for(j=0;j<poFDefn->GetFieldCount();j++)
    1394                 :         {
    1395              24 :             const char* pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
    1396                 : 
    1397              24 :             VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
    1398              24 :             pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
    1399              24 :             VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
    1400              24 :             CPLFree(pszXML);
    1401              24 :             VSIFPrintfL(fp, "</table:table-cell>\n");
    1402                 :         }
    1403               2 :         VSIFPrintfL(fp, "</table:table-row>\n");
    1404                 :     }
    1405                 : 
    1406             118 :     while(poFeature != NULL)
    1407                 :     {
    1408              86 :         VSIFPrintfL(fp, "<table:table-row>\n");
    1409             510 :         for(j=0;j<poFeature->GetFieldCount();j++)
    1410                 :         {
    1411             424 :             if (poFeature->IsFieldSet(j))
    1412                 :             {
    1413             110 :                 OGRFieldType eType = poFDefn->GetFieldDefn(j)->GetType();
    1414                 : 
    1415             110 :                 if (eType == OFTReal)
    1416                 :                 {
    1417                 :                     VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
    1418                 :                                 "office:value=\"%.16f\"/>\n",
    1419              16 :                                 poFeature->GetFieldAsDouble(j));
    1420                 :                 }
    1421              94 :                 else if (eType == OFTInteger)
    1422                 :                 {
    1423                 :                     VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
    1424                 :                                 "office:value=\"%d\"/>\n",
    1425              12 :                                 poFeature->GetFieldAsInteger(j));
    1426                 :                 }
    1427              82 :                 else if (eType == OFTDateTime)
    1428                 :                 {
    1429                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
    1430                 :                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
    1431               8 :                                                     &nHour, &nMinute, &nSecond, &nTZFlag);
    1432                 :                     VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDateTime\" "
    1433                 :                                 "office:value-type=\"date\" "
    1434                 :                                 "office:date-value=\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
    1435               8 :                                 nYear, nMonth, nDay, nHour, nMinute, nSecond);
    1436                 :                     VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
    1437               8 :                                 nDay, nMonth, nYear, nHour, nMinute, nSecond);
    1438               8 :                     VSIFPrintfL(fp, "</table:table-cell>\n");
    1439                 :                 }
    1440              74 :                 else if (eType == OFTDateTime)
    1441                 :                 {
    1442                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
    1443                 :                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
    1444               0 :                                                     &nHour, &nMinute, &nSecond, &nTZFlag);
    1445                 :                     VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDate\" "
    1446                 :                                 "office:value-type=\"date\" "
    1447                 :                                 "office:date-value=\"%04d-%02d-%02dT\">\n",
    1448               0 :                                 nYear, nMonth, nDay);
    1449                 :                     VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d</text:p>\n",
    1450               0 :                                 nDay, nMonth, nYear);
    1451               0 :                     VSIFPrintfL(fp, "</table:table-cell>\n");
    1452                 :                 }
    1453              74 :                 else if (eType == OFTTime)
    1454                 :                 {
    1455                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
    1456                 :                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
    1457               2 :                                                     &nHour, &nMinute, &nSecond, &nTZFlag);
    1458                 :                     VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stTime\" "
    1459                 :                                 "office:value-type=\"time\" "
    1460                 :                                 "office:time-value=\"PT%02dH%02dM%02dS\">\n",
    1461               2 :                                 nHour, nMinute, nSecond);
    1462                 :                     VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n",
    1463               2 :                                 nHour, nMinute, nSecond);
    1464               2 :                     VSIFPrintfL(fp, "</table:table-cell>\n");
    1465                 :                 }
    1466                 :                 else
    1467                 :                 {
    1468              72 :                     const char* pszVal = poFeature->GetFieldAsString(j);
    1469              72 :                     pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
    1470              72 :                     if (strncmp(pszVal, "of:=", 4) == 0)
    1471                 :                     {
    1472               0 :                         VSIFPrintfL(fp, "<table:table-cell table:formula=\"%s\"/>\n", pszXML);
    1473                 :                     }
    1474                 :                     else
    1475                 :                     {
    1476              72 :                         VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
    1477              72 :                         VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
    1478              72 :                         VSIFPrintfL(fp, "</table:table-cell>\n");
    1479                 :                     }
    1480              72 :                     CPLFree(pszXML);
    1481                 :                 }
    1482                 :             }
    1483                 :             else
    1484                 :             {
    1485             314 :                 VSIFPrintfL(fp, "<table:table-cell/>\n");
    1486                 :             }
    1487                 :         }
    1488              86 :         VSIFPrintfL(fp, "</table:table-row>\n");
    1489                 : 
    1490              86 :         delete poFeature;
    1491              86 :         poFeature = poLayer->GetNextFeature();
    1492                 :     }
    1493                 : 
    1494              16 :     VSIFPrintfL(fp, "</table:table>\n");
    1495              16 : }
    1496                 : 
    1497                 : /************************************************************************/
    1498                 : /*                            SyncToDisk()                              */
    1499                 : /************************************************************************/
    1500                 : 
    1501              14 : OGRErr OGRODSDataSource::SyncToDisk()
    1502                 : {
    1503              14 :     if (!bUpdated)
    1504              12 :         return OGRERR_NONE;
    1505                 : 
    1506               2 :     CPLAssert(fpSettings == NULL);
    1507               2 :     CPLAssert(fpContent == NULL);
    1508                 : 
    1509                 :     VSIStatBufL sStat;
    1510               2 :     if (VSIStatL(pszName, &sStat) == 0)
    1511                 :     {
    1512               1 :         if (VSIUnlink( pszName ) != 0)
    1513                 :         {
    1514                 :             CPLError(CE_Failure, CPLE_FileIO,
    1515               0 :                     "Cannot delete %s", pszName);
    1516               0 :             return OGRERR_FAILURE;
    1517                 :         }
    1518                 :     }
    1519                 : 
    1520                 :     /* Maintain new ZIP files opened */
    1521               2 :     void *hZIP = CPLCreateZip(pszName, NULL);
    1522               2 :     if (hZIP == NULL)
    1523                 :     {
    1524                 :         CPLError(CE_Failure, CPLE_FileIO,
    1525               0 :                  "Cannot create %s", pszName);
    1526               0 :         return OGRERR_FAILURE;
    1527                 :     }
    1528                 : 
    1529                 :     /* Write uncopressed mimetype */
    1530               2 :     char** papszOptions = CSLAddString(NULL, "COMPRESSED=NO");
    1531               2 :     CPLCreateFileInZip(hZIP, "mimetype", papszOptions );
    1532                 :     CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
    1533               2 :                       strlen("application/vnd.oasis.opendocument.spreadsheet"));
    1534               2 :     CPLCloseFileInZip(hZIP);
    1535               2 :     CSLDestroy(papszOptions);
    1536                 : 
    1537                 :     /* Now close ZIP file */
    1538               2 :     CPLCloseZip(hZIP);
    1539               2 :     hZIP = NULL;
    1540                 : 
    1541                 :     /* Re-open with VSILFILE */
    1542               2 :     VSILFILE* fpZIP = VSIFOpenL(CPLSPrintf("/vsizip/%s", pszName), "ab");
    1543               2 :     if (fpZIP == NULL)
    1544               0 :         return OGRERR_FAILURE;
    1545                 : 
    1546                 :     VSILFILE* fp;
    1547                 :     int i;
    1548                 : 
    1549               2 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName), "wb");
    1550               2 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1551               2 :     VSIFPrintfL(fp, "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n");
    1552                 :     VSIFPrintfL(fp, "<manifest:file-entry "
    1553                 :                 "manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\" "
    1554               2 :                 "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
    1555                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1556               2 :                     "manifest:full-path=\"content.xml\"/>\n");
    1557                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1558               2 :                     "manifest:full-path=\"styles.xml\"/>\n");
    1559                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1560               2 :                     "manifest:full-path=\"meta.xml\"/>\n");
    1561                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1562               2 :                     "manifest:full-path=\"settings.xml\"/>\n");
    1563               2 :     VSIFPrintfL(fp, "</manifest:manifest>\n");
    1564               2 :     VSIFCloseL(fp);
    1565                 : 
    1566               2 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/meta.xml", pszName), "wb");
    1567               2 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1568                 :     VSIFPrintfL(fp, "<office:document-meta "
    1569                 :                 "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
    1570               2 :                 "office:version=\"1.2\">\n");
    1571               2 :     VSIFPrintfL(fp, "</office:document-meta>\n");
    1572               2 :     VSIFCloseL(fp);
    1573                 : 
    1574               2 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/settings.xml", pszName), "wb");
    1575               2 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1576                 :     VSIFPrintfL(fp, "<office:document-settings "
    1577                 :                 "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
    1578                 :                 "xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" "
    1579                 :                 "xmlns:ooo=\"http://openoffice.org/2004/office\" "
    1580               2 :                 "office:version=\"1.2\">\n");
    1581               2 :     VSIFPrintfL(fp, "<office:settings>\n");
    1582               2 :     VSIFPrintfL(fp, "<config:config-item-set config:name=\"ooo:view-settings\">\n");
    1583               2 :     VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
    1584               2 :     VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
    1585               2 :     VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
    1586              18 :     for(i=0;i<nLayers;i++)
    1587                 :     {
    1588              16 :         OGRLayer* poLayer = GetLayer(i);
    1589              16 :         if (HasHeaderLine(poLayer))
    1590                 :         {
    1591                 :             /* Add vertical splitter */
    1592               2 :             char* pszXML = OGRGetXML_UTF8_EscapedString(GetLayer(i)->GetName());
    1593               2 :             VSIFPrintfL(fp, "<config:config-item-map-entry config:name=\"%s\">\n", pszXML);
    1594               2 :             CPLFree(pszXML);
    1595               2 :             VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitMode\" config:type=\"short\">2</config:config-item>\n");
    1596               2 :             VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitPosition\" config:type=\"int\">1</config:config-item>\n");
    1597               2 :             VSIFPrintfL(fp, "<config:config-item config:name=\"ActiveSplitRange\" config:type=\"short\">2</config:config-item>\n");
    1598               2 :             VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" config:type=\"int\">0</config:config-item>\n");
    1599               2 :             VSIFPrintfL(fp, "<config:config-item config:name=\"PositionBottom\" config:type=\"int\">1</config:config-item>\n");
    1600               2 :             VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
    1601                 :         }
    1602                 :     }
    1603               2 :     VSIFPrintfL(fp, "</config:config-item-map-named>\n");
    1604               2 :     VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
    1605               2 :     VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
    1606               2 :     VSIFPrintfL(fp, "</config:config-item-set>\n");
    1607               2 :     VSIFPrintfL(fp, "</office:settings>\n");
    1608               2 :     VSIFPrintfL(fp, "</office:document-settings>\n");
    1609               2 :     VSIFCloseL(fp);
    1610                 : 
    1611               2 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/styles.xml", pszName), "wb");
    1612               2 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1613                 :     VSIFPrintfL(fp, "<office:document-styles "
    1614                 :                 "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
    1615                 :                 "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
    1616               2 :                 "office:version=\"1.2\">\n");
    1617               2 :     VSIFPrintfL(fp, "<office:styles>\n");
    1618                 :     VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
    1619               2 :                     "style:family=\"table-cell\">\n");
    1620               2 :     VSIFPrintfL(fp, "</style:style>\n");
    1621               2 :     VSIFPrintfL(fp, "</office:styles>\n");
    1622               2 :     VSIFPrintfL(fp, "</office:document-styles>\n");
    1623               2 :     VSIFCloseL(fp);
    1624                 : 
    1625               2 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/content.xml", pszName), "wb");
    1626               2 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1627                 :     VSIFPrintfL(fp, "<office:document-content "
    1628                 :                 "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" "
    1629                 :                 "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" "
    1630                 :                 "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" "
    1631                 :                 "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" "
    1632                 :                 "xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" "
    1633                 :                 "xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" "
    1634                 :                 "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" "
    1635               2 :                 "office:version=\"1.2\">\n");
    1636               2 :     VSIFPrintfL(fp, "<office:scripts/>\n");
    1637               2 :     VSIFPrintfL(fp, "<office:automatic-styles>\n");
    1638                 :     VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
    1639               2 :                     "style:family=\"table-column\">\n");
    1640                 :     VSIFPrintfL(fp, "<style:table-column-properties "
    1641                 :                     "fo:break-before=\"auto\" "
    1642               2 :                     "style:column-width=\"2.5cm\"/>\n");
    1643               2 :     VSIFPrintfL(fp, "</style:style>\n");
    1644                 :     VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
    1645               2 :                     "style:family=\"table-column\">\n");
    1646                 :     VSIFPrintfL(fp, "<style:table-column-properties "
    1647                 :                     "fo:break-before=\"auto\" "
    1648               2 :                     "style:column-width=\"5cm\"/>\n");
    1649               2 :     VSIFPrintfL(fp, "</style:style>\n");
    1650                 :     VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
    1651               2 :                     "number:automatic-order=\"true\">\n");
    1652               2 :     VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
    1653               2 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1654               2 :     VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
    1655               2 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1656               2 :     VSIFPrintfL(fp, "<number:year/>\n");
    1657               2 :     VSIFPrintfL(fp, "</number:date-style>\n");
    1658               2 :     VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
    1659               2 :     VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
    1660               2 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1661               2 :     VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
    1662               2 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1663               2 :     VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
    1664               2 :     VSIFPrintfL(fp, "</number:time-style>\n");
    1665                 :     VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
    1666               2 :                     "number:automatic-order=\"true\">\n");
    1667               2 :     VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
    1668               2 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1669               2 :     VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
    1670               2 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1671               2 :     VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
    1672               2 :     VSIFPrintfL(fp, "<number:text> </number:text>\n");
    1673               2 :     VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
    1674               2 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1675               2 :     VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
    1676               2 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1677               2 :     VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
    1678               2 :     VSIFPrintfL(fp, "</number:date-style>\n");
    1679                 :     VSIFPrintfL(fp, "<style:style style:name=\"stDate\" "
    1680                 :                     "style:family=\"table-cell\" "
    1681                 :                     "style:parent-style-name=\"Default\" "
    1682               2 :                     "style:data-style-name=\"nDate\"/>\n");
    1683                 :     VSIFPrintfL(fp, "<style:style style:name=\"stTime\" "
    1684                 :                     "style:family=\"table-cell\" "
    1685                 :                     "style:parent-style-name=\"Default\" "
    1686               2 :                     "style:data-style-name=\"nTime\"/>\n");
    1687                 :     VSIFPrintfL(fp, "<style:style style:name=\"stDateTime\" "
    1688                 :                     "style:family=\"table-cell\" "
    1689                 :                     "style:parent-style-name=\"Default\" "
    1690               2 :                     "style:data-style-name=\"nDateTime\"/>\n");
    1691               2 :     VSIFPrintfL(fp, "</office:automatic-styles>\n");
    1692               2 :     VSIFPrintfL(fp, "<office:body>\n");
    1693               2 :     VSIFPrintfL(fp, "<office:spreadsheet>\n");
    1694              18 :     for(i=0;i<nLayers;i++)
    1695                 :     {
    1696              16 :         WriteLayer(fp, GetLayer(i));
    1697                 :     }
    1698               2 :     VSIFPrintfL(fp, "</office:spreadsheet>\n");
    1699               2 :     VSIFPrintfL(fp, "</office:body>\n");
    1700               2 :     VSIFPrintfL(fp, "</office:document-content>\n");
    1701               2 :     VSIFCloseL(fp);
    1702                 : 
    1703                 :     /* Now close ZIP file */
    1704               2 :     VSIFCloseL(fpZIP);
    1705                 : 
    1706                 :     /* Reset updated flag at datasource and layer level */
    1707               2 :     bUpdated = FALSE;
    1708              18 :     for(int i = 0; i<nLayers; i++)
    1709                 :     {
    1710              16 :         ((OGRODSLayer*)papoLayers[i])->SetUpdated(FALSE);
    1711                 :     }
    1712                 : 
    1713               2 :     return OGRERR_NONE;
    1714                 : }
    1715                 : 
    1716                 : /************************************************************************/
    1717                 : /*                          EvaluateRange()                             */
    1718                 : /************************************************************************/
    1719                 : 
    1720              34 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
    1721                 :                                     std::vector<ods_formula_node>& aoOutValues)
    1722                 : {
    1723              68 :     if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) ||
    1724              34 :         nCol1 < 0 || nCol1 >= poLayer->GetLayerDefn()->GetFieldCount())
    1725                 :     {
    1726                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1727               0 :                 "Invalid cell (row=%d, col=%d)", nRow1 + 1, nCol1 + 1);
    1728               0 :         return FALSE;
    1729                 :     }
    1730                 : 
    1731              68 :     if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) ||
    1732              34 :         nCol2 < 0 || nCol2 >= poLayer->GetLayerDefn()->GetFieldCount())
    1733                 :     {
    1734                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1735               0 :                 "Invalid cell (row=%d, col=%d)", nRow2 + 1, nCol2 + 1);
    1736               0 :         return FALSE;
    1737                 :     }
    1738                 : 
    1739              34 :     int nIndexBackup = poLayer->GetNextReadFID();
    1740                 : 
    1741              34 :     if (poLayer->SetNextByIndex(nRow1) != OGRERR_NONE)
    1742                 :     {
    1743                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1744               0 :                 "Cannot fetch feature for row = %d", nRow1);
    1745               0 :         return FALSE;
    1746                 :     }
    1747                 : 
    1748              65 :     for(int nRow = nRow1; nRow <= nRow2; nRow ++)
    1749                 :     {
    1750              34 :         OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1751                 : 
    1752              34 :         if (poFeature == NULL)
    1753                 :         {
    1754                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1755               0 :                     "Cannot fetch feature for for row = %d", nRow);
    1756               0 :             poLayer->SetNextByIndex(nIndexBackup);
    1757               0 :             return FALSE;
    1758                 :         }
    1759                 : 
    1760              83 :         for(int nCol = nCol1; nCol <= nCol2; nCol++)
    1761                 :         {
    1762              52 :             if (!poFeature->IsFieldSet(nCol))
    1763                 :             {
    1764               6 :                 aoOutValues.push_back(ods_formula_node());
    1765                 :             }
    1766              46 :             else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
    1767                 :             {
    1768               0 :                 aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
    1769                 :             }
    1770              46 :             else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
    1771                 :             {
    1772               0 :                 aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
    1773                 :             }
    1774                 :             else
    1775                 :             {
    1776              46 :                 std::string osVal(poFeature->GetFieldAsString(nCol));
    1777              92 :                 if (strncmp(osVal.c_str(), "of:=", 4) == 0)
    1778                 :                 {
    1779              10 :                     delete poFeature;
    1780              10 :                     poFeature = NULL;
    1781                 : 
    1782              10 :                     if (!Evaluate(nRow, nCol))
    1783                 :                     {
    1784                 :                         /*CPLError(CE_Warning, CPLE_AppDefined,
    1785                 :                                 "Formula at cell (%d, %d) has not yet been resolved",
    1786                 :                                 nRow + 1, nCol + 1);*/
    1787               3 :                         poLayer->SetNextByIndex(nIndexBackup);
    1788               3 :                         return FALSE;
    1789                 :                     }
    1790                 : 
    1791               7 :                     poLayer->SetNextByIndex(nRow);
    1792               7 :                     poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1793                 : 
    1794               7 :                     if (!poFeature->IsFieldSet(nCol))
    1795                 :                     {
    1796               0 :                         aoOutValues.push_back(ods_formula_node());
    1797                 :                     }
    1798               7 :                     else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
    1799                 :                     {
    1800               0 :                         aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
    1801                 :                     }
    1802               7 :                     else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
    1803                 :                     {
    1804               0 :                         aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
    1805                 :                     }
    1806                 :                     else
    1807                 :                     {
    1808               7 :                         osVal = poFeature->GetFieldAsString(nCol);
    1809               7 :                         if (strncmp(osVal.c_str(), "of:=", 4) != 0)
    1810                 :                         {
    1811               1 :                             CPLValueType eType = CPLGetValueType(osVal.c_str());
    1812                 :                             /* Try to convert into numeric value if possible */
    1813               1 :                             if (eType != CPL_VALUE_STRING)
    1814               1 :                                 aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
    1815                 :                             else
    1816               0 :                                 aoOutValues.push_back(ods_formula_node(osVal.c_str()));
    1817                 :                         }
    1818                 :                     }
    1819                 :                 }
    1820                 :                 else
    1821                 :                 {
    1822              36 :                     CPLValueType eType = CPLGetValueType(osVal.c_str());
    1823                 :                     /* Try to convert into numeric value if possible */
    1824              36 :                     if (eType != CPL_VALUE_STRING)
    1825              13 :                         aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
    1826                 :                     else
    1827              23 :                         aoOutValues.push_back(ods_formula_node(osVal.c_str()));
    1828               0 :                 }
    1829                 :             }
    1830                 :         }
    1831                 : 
    1832              31 :         delete poFeature;
    1833                 :     }
    1834                 : 
    1835              31 :     poLayer->SetNextByIndex(nIndexBackup);
    1836                 : 
    1837              31 :     return TRUE;
    1838                 : }
    1839                 : 
    1840                 : /************************************************************************/
    1841                 : /*                            Evaluate()                                */
    1842                 : /************************************************************************/
    1843                 : 
    1844             120 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
    1845                 : {
    1846             120 :     if (oVisisitedCells.find(std::pair<int,int>(nRow, nCol)) != oVisisitedCells.end())
    1847                 :     {
    1848                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1849               3 :                 "Circular dependency with (row=%d, col=%d)", nRow + 1, nCol + 1);
    1850               3 :         return FALSE;
    1851                 :     }
    1852                 : 
    1853             117 :     oVisisitedCells.insert(std::pair<int,int>(nRow, nCol));
    1854                 : 
    1855             117 :     if (poLayer->SetNextByIndex(nRow) != OGRERR_NONE)
    1856                 :     {
    1857                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1858               0 :                 "Cannot fetch feature for row = %d", nRow);
    1859               0 :         return FALSE;
    1860                 :     }
    1861                 : 
    1862             117 :     OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1863             117 :     if (poFeature->IsFieldSet(nCol) &&
    1864                 :         poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
    1865                 :     {
    1866             117 :         const char* pszVal = poFeature->GetFieldAsString(nCol);
    1867             117 :         if (strncmp(pszVal, "of:=", 4) == 0)
    1868                 :         {
    1869             116 :             ods_formula_node* expr_out = ods_formula_compile( pszVal + 4 );
    1870             116 :             if (expr_out &&
    1871                 :                 expr_out->Evaluate(this) &&
    1872                 :                 expr_out->eNodeType == SNT_CONSTANT)
    1873                 :             {
    1874                 :                 /* Refetch feature in case Evaluate() modified another cell in this row */
    1875             106 :                 delete poFeature;
    1876             106 :                 poLayer->SetNextByIndex(nRow);
    1877             106 :                 poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1878                 : 
    1879             106 :                 if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
    1880                 :                 {
    1881               0 :                     poFeature->UnsetField(nCol);
    1882               0 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1883                 :                 }
    1884             106 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
    1885                 :                 {
    1886              83 :                     poFeature->SetField(nCol, expr_out->int_value);
    1887              83 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1888                 :                 }
    1889              23 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
    1890                 :                 {
    1891               7 :                     poFeature->SetField(nCol, expr_out->float_value);
    1892               7 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1893                 :                 }
    1894              16 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
    1895                 :                 {
    1896              16 :                     poFeature->SetField(nCol, expr_out->string_value);
    1897              16 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1898                 :                 }
    1899                 :             }
    1900             116 :             delete expr_out;
    1901                 :         }
    1902                 :     }
    1903                 : 
    1904             117 :     delete poFeature;
    1905                 : 
    1906             117 :     return TRUE;
    1907                 : }

Generated by: LCOV version 1.7