LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/ods - ogrodsdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 828 739 89.3 %
Date: 2012-04-28 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             220 : {
      46                 : private:
      47                 :         OGRODSLayer* poLayer;
      48                 :         std::set<std::pair<int,int> > oVisisitedCells;
      49                 : 
      50                 : public:
      51             220 :         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             230 : OGRODSLayer::OGRODSLayer( OGRODSDataSource* poDSIn,
      64                 :                             const char * pszName,
      65                 :                             int bUpdatedIn) :
      66             230 :                                 OGRMemLayer(pszName, NULL, wkbNone)
      67                 : {
      68             230 :     poDS = poDSIn;
      69             230 :     bUpdated = bUpdatedIn;
      70             230 :     bHasHeaderLine = FALSE;
      71             230 : }
      72                 : 
      73                 : /************************************************************************/
      74                 : /*                             Updated()                                */
      75                 : /************************************************************************/
      76                 : 
      77            3616 : void OGRODSLayer::SetUpdated(int bUpdatedIn)
      78                 : {
      79            3616 :     if (bUpdatedIn && !bUpdated && poDS->GetUpdatable())
      80                 :     {
      81              18 :         bUpdated = TRUE;
      82              18 :         poDS->SetUpdated();
      83                 :     }
      84            3598 :     else if (bUpdated && !bUpdatedIn)
      85                 :     {
      86              34 :         bUpdated = FALSE;
      87                 :     }
      88            3616 : }
      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            2060 : OGRFeature* OGRODSLayer::GetNextFeature()
     104                 : {
     105            2060 :     OGRFeature* poFeature = OGRMemLayer::GetNextFeature();
     106            2060 :     if (poFeature)
     107            1748 :         poFeature->SetFID(poFeature->GetFID() + 1 + bHasHeaderLine);
     108            2060 :     return poFeature;
     109                 : }
     110                 : 
     111                 : /************************************************************************/
     112                 : /*                           GetFeature()                               */
     113                 : /************************************************************************/
     114                 : 
     115               4 : OGRFeature* OGRODSLayer::GetFeature( long nFeatureId )
     116                 : {
     117               4 :     OGRFeature* poFeature = OGRMemLayer::GetFeature(nFeatureId - (1 + bHasHeaderLine));
     118               4 :     if (poFeature)
     119               4 :         poFeature->SetFID(nFeatureId);
     120               4 :     return poFeature;
     121                 : }
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                           SetFeature()                               */
     125                 : /************************************************************************/
     126                 : 
     127            1142 : OGRErr OGRODSLayer::SetFeature( OGRFeature *poFeature )
     128                 : {
     129            1142 :     if (poFeature == NULL)
     130               0 :         return OGRMemLayer::SetFeature(poFeature);
     131                 : 
     132            1142 :     long nFID = poFeature->GetFID();
     133            1142 :     if (nFID != OGRNullFID)
     134               2 :         poFeature->SetFID(nFID - (1 + bHasHeaderLine));
     135            1142 :     SetUpdated(); 
     136            1142 :     OGRErr eErr = OGRMemLayer::SetFeature(poFeature);
     137            1142 :     poFeature->SetFID(nFID);
     138            1142 :     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              28 : OGRODSDataSource::OGRODSDataSource()
     156                 : 
     157                 : {
     158              28 :     pszName = NULL;
     159              28 :     fpContent = NULL;
     160              28 :     fpSettings = NULL;
     161              28 :     bUpdatable = FALSE;
     162              28 :     bUpdated = FALSE;
     163              28 :     bAnalysedFile = FALSE;
     164                 : 
     165              28 :     nLayers = 0;
     166              28 :     papoLayers = NULL;
     167                 : 
     168              28 :     bFirstLineIsHeaders = FALSE;
     169                 : 
     170              28 :     oParser = NULL;
     171              28 :     bStopParsing = FALSE;
     172              28 :     nWithoutEventCounter = 0;
     173              28 :     nDataHandlerCounter = 0;
     174              28 :     nStackDepth = 0;
     175              28 :     nDepth = 0;
     176              28 :     nCurLine = 0;
     177              28 :     nEmptyRowsAccumulated = 0;
     178              28 :     nCurCol = 0;
     179              28 :     nRowsRepeated = 0;
     180              28 :     nCellsRepeated = 0;
     181              28 :     stateStack[0].eVal = STATE_DEFAULT;
     182              28 :     stateStack[0].nBeginDepth = 0;
     183              28 :     bEndTableParsing = FALSE;
     184                 : 
     185              28 :     poCurLayer = NULL;
     186                 : 
     187                 :     const char* pszODSFieldTypes =
     188              28 :                 CPLGetConfigOption("OGR_ODS_FIELD_TYPES", "");
     189              28 :     bAutodetectTypes = !EQUAL(pszODSFieldTypes, "STRING");
     190              28 : }
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                         ~OGRODSDataSource()                          */
     194                 : /************************************************************************/
     195                 : 
     196              28 : OGRODSDataSource::~OGRODSDataSource()
     197                 : 
     198                 : {
     199              28 :     SyncToDisk();
     200                 : 
     201              28 :     CPLFree( pszName );
     202                 : 
     203              28 :     if (fpContent)
     204               0 :         VSIFCloseL(fpContent);
     205              28 :     if (fpSettings)
     206               0 :         VSIFCloseL(fpSettings);
     207                 : 
     208             238 :     for(int i=0;i<nLayers;i++)
     209             210 :         delete papoLayers[i];
     210              28 :     CPLFree( papoLayers );
     211              28 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                           TestCapability()                           */
     215                 : /************************************************************************/
     216                 : 
     217              22 : int OGRODSDataSource::TestCapability( const char * pszCap )
     218                 : 
     219                 : {
     220              22 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     221              16 :         return bUpdatable;
     222               6 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     223               0 :         return bUpdatable;
     224                 :     else
     225               6 :         return FALSE;
     226                 : }
     227                 : 
     228                 : 
     229                 : /************************************************************************/
     230                 : /*                              GetLayer()                              */
     231                 : /************************************************************************/
     232                 : 
     233             510 : OGRLayer *OGRODSDataSource::GetLayer( int iLayer )
     234                 : 
     235                 : {
     236             510 :     AnalyseFile();
     237             510 :     if (iLayer < 0 || iLayer >= nLayers)
     238               0 :         return NULL;
     239                 : 
     240             510 :     return papoLayers[iLayer];
     241                 : }
     242                 : 
     243                 : /************************************************************************/
     244                 : /*                            GetLayerCount()                           */
     245                 : /************************************************************************/
     246                 : 
     247             448 : int OGRODSDataSource::GetLayerCount()
     248                 : {
     249             448 :     AnalyseFile();
     250             448 :     return nLayers;
     251                 : }
     252                 : 
     253                 : /************************************************************************/
     254                 : /*                                Open()                                */
     255                 : /************************************************************************/
     256                 : 
     257              26 : int OGRODSDataSource::Open( const char * pszFilename,
     258                 :                             VSILFILE* fpContentIn,
     259                 :                             VSILFILE* fpSettingsIn,
     260                 :                             int bUpdatableIn)
     261                 : 
     262                 : {
     263              26 :     bUpdatable = bUpdatableIn;
     264                 : 
     265              26 :     pszName = CPLStrdup( pszFilename );
     266              26 :     fpContent = fpContentIn;
     267              26 :     fpSettings = fpSettingsIn;
     268                 : 
     269              26 :     return TRUE;
     270                 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                             Create()                                 */
     274                 : /************************************************************************/
     275                 : 
     276               2 : int OGRODSDataSource::Create( const char * pszFilename, char **papszOptions )
     277                 : {
     278               2 :     bUpdated = TRUE;
     279               2 :     bUpdatable = TRUE;
     280               2 :     bAnalysedFile = TRUE;
     281                 : 
     282               2 :     pszName = CPLStrdup( pszFilename );
     283                 : 
     284               2 :     return TRUE;
     285                 : }
     286                 : 
     287                 : /************************************************************************/
     288                 : /*                           startElementCbk()                          */
     289                 : /************************************************************************/
     290                 : 
     291            7566 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
     292                 :                                     const char **ppszAttr)
     293                 : {
     294            7566 :     ((OGRODSDataSource*)pUserData)->startElementCbk(pszName, ppszAttr);
     295            7566 : }
     296                 : 
     297            7566 : void OGRODSDataSource::startElementCbk(const char *pszName,
     298                 :                                        const char **ppszAttr)
     299                 : {
     300            7566 :     if (bStopParsing) return;
     301                 : 
     302            7566 :     nWithoutEventCounter = 0;
     303            7566 :     switch(stateStack[nStackDepth].eVal)
     304                 :     {
     305            1590 :         case STATE_DEFAULT: startElementDefault(pszName, ppszAttr); break;
     306            1304 :         case STATE_TABLE:   startElementTable(pszName, ppszAttr); break;
     307            3122 :         case STATE_ROW:     startElementRow(pszName, ppszAttr); break;
     308            1550 :         case STATE_CELL:    startElementCell(pszName, ppszAttr); break;
     309                 :         case STATE_TEXTP:   break;
     310                 :         default:            break;
     311                 :     }
     312            7566 :     nDepth++;
     313                 : }
     314                 : 
     315                 : /************************************************************************/
     316                 : /*                            endElementCbk()                           */
     317                 : /************************************************************************/
     318                 : 
     319            7566 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
     320                 : {
     321            7566 :     ((OGRODSDataSource*)pUserData)->endElementCbk(pszName);
     322            7566 : }
     323                 : 
     324            7566 : void OGRODSDataSource::endElementCbk(const char *pszName)
     325                 : {
     326            7566 :     if (bStopParsing) return;
     327                 : 
     328            7566 :     nWithoutEventCounter = 0;
     329                 : 
     330            7566 :     nDepth--;
     331            7566 :     switch(stateStack[nStackDepth].eVal)
     332                 :     {
     333            1376 :         case STATE_DEFAULT: break;
     334             622 :         case STATE_TABLE:   endElementTable(pszName); break;
     335             958 :         case STATE_ROW:     endElementRow(pszName); break;
     336            3774 :         case STATE_CELL:    endElementCell(pszName); break;
     337                 :         case STATE_TEXTP:   break;
     338                 :         default:            break;
     339                 :     }
     340                 : 
     341            7566 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     342            5032 :         nStackDepth --;
     343                 : }
     344                 : 
     345                 : /************************************************************************/
     346                 : /*                            dataHandlerCbk()                          */
     347                 : /************************************************************************/
     348                 : 
     349            5706 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
     350                 : {
     351            5706 :     ((OGRODSDataSource*)pUserData)->dataHandlerCbk(data, nLen);
     352            5706 : }
     353                 : 
     354            5706 : void OGRODSDataSource::dataHandlerCbk(const char *data, int nLen)
     355                 : {
     356            5706 :     if (bStopParsing) return;
     357                 : 
     358            5706 :     nDataHandlerCounter ++;
     359            5706 :     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            5706 :     nWithoutEventCounter = 0;
     369                 : 
     370            5706 :     switch(stateStack[nStackDepth].eVal)
     371                 :     {
     372             612 :         case STATE_DEFAULT: break;
     373             578 :         case STATE_TABLE:   break;
     374            2014 :         case STATE_ROW:     break;
     375            1594 :         case STATE_CELL:    break;
     376             908 :         case STATE_TEXTP:   dataHandlerTextP(data, nLen);
     377                 :         default:            break;
     378                 :     }
     379                 : }
     380                 : 
     381                 : /************************************************************************/
     382                 : /*                                PushState()                           */
     383                 : /************************************************************************/
     384                 : 
     385            5006 : void OGRODSDataSource::PushState(HandlerStateEnum eVal)
     386                 : {
     387            5006 :     if (nStackDepth + 1 == STACK_SIZE)
     388                 :     {
     389               0 :         bStopParsing = TRUE;
     390               0 :         return;
     391                 :     }
     392            5006 :     nStackDepth ++;
     393            5006 :     stateStack[nStackDepth].eVal = eVal;
     394            5006 :     stateStack[nStackDepth].nBeginDepth = nDepth;
     395                 : }
     396                 : 
     397                 : /************************************************************************/
     398                 : /*                          GetAttributeValue()                         */
     399                 : /************************************************************************/
     400                 : 
     401           20988 : static const char* GetAttributeValue(const char **ppszAttr,
     402                 :                                      const char* pszKey,
     403                 :                                      const char* pszDefaultVal)
     404                 : {
     405           56402 :     while(*ppszAttr)
     406                 :     {
     407           20626 :         if (strcmp(ppszAttr[0], pszKey) == 0)
     408            6200 :             return ppszAttr[1];
     409           14426 :         ppszAttr += 2;
     410                 :     }
     411           14788 :     return pszDefaultVal;
     412                 : }
     413                 : 
     414                 : /************************************************************************/
     415                 : /*                            GetOGRFieldType()                         */
     416                 : /************************************************************************/
     417                 : 
     418            2058 : OGRFieldType OGRODSDataSource::GetOGRFieldType(const char* pszValue,
     419                 :                                                const char* pszValueType)
     420                 : {
     421            2058 :     if (!bAutodetectTypes || pszValueType == NULL)
     422              60 :         return OFTString;
     423            1998 :     else if (strcmp(pszValueType, "string") == 0)
     424             666 :         return OFTString;
     425            1332 :     else if (strcmp(pszValueType, "float") == 0 ||
     426                 :              strcmp(pszValueType, "currency") == 0)
     427                 :     {
     428             680 :         if (CPLGetValueType(pszValue) == CPL_VALUE_INTEGER)
     429             482 :             return OFTInteger;
     430                 :         else
     431             198 :             return OFTReal;
     432                 :     }
     433             652 :     else if (strcmp(pszValueType, "percentage") == 0)
     434              70 :         return OFTReal;
     435             582 :     else if (strcmp(pszValueType, "date") == 0)
     436                 :     {
     437             210 :         if (strlen(pszValue) == 4 + 1 + 2 + 1 + 2)
     438             104 :             return OFTDate;
     439                 :         else
     440             106 :             return OFTDateTime;
     441                 :     }
     442             372 :     else if (strcmp(pszValueType, "time") == 0)
     443                 :     {
     444              42 :         return OFTTime;
     445                 :     }
     446                 :     else
     447             330 :         return OFTString;
     448                 : }
     449                 : 
     450                 : /************************************************************************/
     451                 : /*                              SetField()                              */
     452                 : /************************************************************************/
     453                 : 
     454            2024 : static void SetField(OGRFeature* poFeature,
     455                 :                      int i,
     456                 :                      const char* pszValue)
     457                 : {
     458            2024 :     if (pszValue[0] == '\0')
     459             436 :         return;
     460                 : 
     461            1588 :     OGRFieldType eType = poFeature->GetFieldDefnRef(i)->GetType();
     462            1588 :     if (eType == OFTTime)
     463                 :     {
     464                 :         int nHour, nHourRepeated, nMinute, nSecond;
     465                 :         char c;
     466              20 :         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              18 :             poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
     471                 :         }
     472                 :         /* bug with kspread 2.1.2 ? */
     473                 :         /* ex PT121234M56S */
     474               2 :         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               2 :             poFeature->SetField(i, 0, 0, 0, nHour, nMinute, nSecond, 0);
     480                 :         }
     481                 :     }
     482            1678 :     else if (eType == OFTDate || eType == OFTDateTime)
     483                 :     {
     484                 :         int nYear, nMonth, nDay, nHour, nMinute, nTZ;
     485                 :         float fCur;
     486             110 :         if (OGRParseXMLDateTime( pszValue,
     487                 :                                  &nYear, &nMonth, &nDay,
     488                 :                                  &nHour, &nMinute, &fCur, &nTZ) )
     489                 :         {
     490                 :             poFeature->SetField(i, nYear, nMonth, nDay,
     491             110 :                                 nHour, nMinute, (int)fCur, nTZ);
     492                 :         }
     493                 :     }
     494                 :     else
     495            1458 :         poFeature->SetField(i, pszValue);
     496                 : }
     497                 : 
     498                 : /************************************************************************/
     499                 : /*                          DetectHeaderLine()                          */
     500                 : /************************************************************************/
     501                 : 
     502             150 : void OGRODSDataSource::DetectHeaderLine()
     503                 : 
     504                 : {
     505             150 :     int bHeaderLineCandidate = TRUE;
     506                 :     size_t i;
     507             534 :     for(i = 0; i < apoFirstLineTypes.size(); i++)
     508                 :     {
     509             434 :         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              50 :             bHeaderLineCandidate = FALSE;
     514              50 :             break;
     515                 :         }
     516                 :     }
     517                 : 
     518             150 :     size_t nCountTextOnCurLine = 0;
     519             150 :     size_t nCountNonEmptyOnCurLine = 0;
     520             534 :     for(i = 0; bHeaderLineCandidate && i < apoCurLineTypes.size(); i++)
     521                 :     {
     522             384 :         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              78 :             nCountTextOnCurLine ++;
     527                 :         }
     528             306 :         else if (apoCurLineTypes[i] != "")
     529                 :         {
     530             258 :             nCountNonEmptyOnCurLine ++;
     531                 :         }
     532                 :     }
     533                 : 
     534             150 :     const char* pszODSHeaders = CPLGetConfigOption("OGR_ODS_HEADERS", "");
     535             150 :     bFirstLineIsHeaders = FALSE;
     536             150 :     if (EQUAL(pszODSHeaders, "FORCE"))
     537               0 :         bFirstLineIsHeaders = TRUE;
     538             150 :     else if (EQUAL(pszODSHeaders, "DISABLE"))
     539              12 :         bFirstLineIsHeaders = FALSE;
     540             138 :     else if (osSetLayerHasSplitter.find(poCurLayer->GetName()) !=
     541                 :              osSetLayerHasSplitter.end())
     542                 :     {
     543               4 :         bFirstLineIsHeaders = TRUE;
     544                 :     }
     545             134 :     else if (bHeaderLineCandidate &&
     546                 :              apoFirstLineTypes.size() != 0 &&
     547                 :              apoFirstLineTypes.size() == apoCurLineTypes.size() &&
     548                 :              nCountTextOnCurLine != apoFirstLineTypes.size() &&
     549                 :              nCountNonEmptyOnCurLine != 0)
     550                 :     {
     551              18 :         bFirstLineIsHeaders = TRUE;
     552                 :     }
     553                 :     CPLDebug("ODS", "%s %s",
     554             150 :              poCurLayer->GetName(),
     555             300 :              bFirstLineIsHeaders ? "has header line" : "has no header line");
     556             150 : }
     557                 : 
     558                 : /************************************************************************/
     559                 : /*                          startElementDefault()                       */
     560                 : /************************************************************************/
     561                 : 
     562            1590 : void OGRODSDataSource::startElementDefault(const char *pszName,
     563                 :                                            const char **ppszAttr)
     564                 : {
     565            1590 :     if (strcmp(pszName, "table:table") == 0)
     566                 :     {
     567                 :         const char* pszTableName =
     568             214 :             GetAttributeValue(ppszAttr, "table:name", "unnamed");
     569                 : 
     570             214 :         poCurLayer = new OGRODSLayer(this, pszTableName);
     571             214 :         papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     572             214 :         papoLayers[nLayers++] = poCurLayer;
     573                 : 
     574             214 :         nCurLine = 0;
     575             214 :         nEmptyRowsAccumulated = 0;
     576             428 :         apoFirstLineValues.resize(0);
     577             428 :         apoFirstLineTypes.resize(0);
     578             214 :         PushState(STATE_TABLE);
     579             214 :         bEndTableParsing = FALSE;
     580                 :     }
     581            1590 : }
     582                 : 
     583                 : /************************************************************************/
     584                 : /*                          startElementTable()                        */
     585                 : /************************************************************************/
     586                 : 
     587            1304 : void OGRODSDataSource::startElementTable(const char *pszName,
     588                 :                                          const char **ppszAttr)
     589                 : {
     590            1304 :     if (strcmp(pszName, "table:table-row") == 0 && !bEndTableParsing)
     591                 :     {
     592                 :         nRowsRepeated = atoi(
     593             896 :             GetAttributeValue(ppszAttr, "table:number-rows-repeated", "1"));
     594             896 :         if (nRowsRepeated > 65536)
     595                 :         {
     596               0 :             bEndTableParsing = TRUE;
     597               0 :             return;
     598                 :         }
     599                 : 
     600             896 :         nCurCol = 0;
     601                 : 
     602             896 :         apoCurLineValues.resize(0);
     603            1792 :         apoCurLineTypes.resize(0);
     604                 : 
     605             896 :         PushState(STATE_ROW);
     606                 :     }
     607                 : }
     608                 : 
     609                 : /************************************************************************/
     610                 : /*                           endElementTable()                          */
     611                 : /************************************************************************/
     612                 : 
     613             622 : void OGRODSDataSource::endElementTable(const char *pszName)
     614                 : {
     615             622 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     616                 :     {
     617             214 :         CPLAssert(strcmp(pszName, "table:table") == 0);
     618                 : 
     619             214 :         if (nCurLine == 0 ||
     620                 :             (nCurLine == 1 && apoFirstLineValues.size() == 0))
     621                 :         {
     622                 :             /* Remove empty sheet */
     623              20 :             delete poCurLayer;
     624              20 :             nLayers --;
     625              20 :             poCurLayer = NULL;
     626                 :         }
     627             194 :         else if (nCurLine == 1)
     628                 :         {
     629                 :             /* If we have only one single line in the sheet */
     630                 :             size_t i;
     631              72 :             for(i = 0; i < apoFirstLineValues.size(); i++)
     632                 :             {
     633              48 :                 const char* pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
     634                 :                 OGRFieldType eType = GetOGRFieldType(apoFirstLineValues[i].c_str(),
     635              48 :                                                      apoFirstLineTypes[i].c_str());
     636              48 :                 OGRFieldDefn oFieldDefn(pszFieldName, eType);
     637              48 :                 poCurLayer->CreateField(&oFieldDefn);
     638                 :             }
     639                 : 
     640              24 :             OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     641              72 :             for(i = 0; i < apoFirstLineValues.size(); i++)
     642                 :             {
     643              48 :                 SetField(poFeature, i, apoFirstLineValues[i].c_str());
     644                 :             }
     645              24 :             poCurLayer->CreateFeature(poFeature);
     646              24 :             delete poFeature;
     647                 :         }
     648                 : 
     649             214 :         if (poCurLayer)
     650                 :         {
     651                 :             OGRFeature* poFeature;
     652                 : 
     653             194 :             if (CSLTestBoolean(CPLGetConfigOption("ODS_RESOLVE_FORMULAS", "YES")))
     654                 :             {
     655             194 :                 poCurLayer->ResetReading();
     656                 : 
     657             194 :                 int nRow = 0;
     658             194 :                 poFeature = poCurLayer->GetNextFeature();
     659            1442 :                 while (poFeature)
     660                 :                 {
     661            6806 :                     for(int i=0;i<poFeature->GetFieldCount();i++)
     662                 :                     {
     663            5752 :                         if (poFeature->IsFieldSet(i) &&
     664                 :                             poFeature->GetFieldDefnRef(i)->GetType() == OFTString)
     665                 :                         {
     666            1190 :                             const char* pszVal = poFeature->GetFieldAsString(i);
     667            1190 :                             if (strncmp(pszVal, "of:=", 4) == 0)
     668                 :                             {
     669             220 :                                 ODSCellEvaluator oCellEvaluator(poCurLayer);
     670             220 :                                 oCellEvaluator.Evaluate(nRow, i);
     671                 :                             }
     672                 :                         }
     673                 :                     }
     674            1054 :                     delete poFeature;
     675                 : 
     676            1054 :                     poFeature = poCurLayer->GetNextFeature();
     677            1054 :                     nRow ++;
     678                 :                 }
     679                 :             }
     680                 : 
     681             194 :             poCurLayer->ResetReading();
     682                 : 
     683             194 :             ((OGRMemLayer*)poCurLayer)->SetUpdatable(bUpdatable);
     684             194 :             ((OGRMemLayer*)poCurLayer)->SetAdvertizeUTF8(TRUE);
     685             194 :             ((OGRODSLayer*)poCurLayer)->SetUpdated(FALSE);
     686                 :         }
     687                 : 
     688             214 :         poCurLayer = NULL;
     689                 :     }
     690             622 : }
     691                 : 
     692                 : /************************************************************************/
     693                 : /*                            startElementRow()                         */
     694                 : /************************************************************************/
     695                 : 
     696            3122 : void OGRODSDataSource::startElementRow(const char *pszName,
     697                 :                                        const char **ppszAttr)
     698                 : {
     699            3122 :     if (strcmp(pszName, "table:table-cell") == 0)
     700                 :     {
     701            3060 :         PushState(STATE_CELL);
     702                 : 
     703            3060 :         osValueType = GetAttributeValue(ppszAttr, "office:value-type", "");
     704                 :         const char* pszValue =
     705            3060 :             GetAttributeValue(ppszAttr, "office:value", NULL);
     706            3060 :         if (pszValue)
     707             622 :             osValue = pszValue;
     708                 :         else
     709                 :         {
     710                 :             const char* pszDateValue =
     711            2438 :                 GetAttributeValue(ppszAttr, "office:date-value", NULL);
     712            2438 :             if (pszDateValue)
     713             130 :                 osValue = pszDateValue;
     714                 :             else
     715            2308 :                 osValue = GetAttributeValue(ppszAttr, "office:time-value", "");
     716                 :         }
     717                 : 
     718            3060 :         const char* pszFormula = GetAttributeValue(ppszAttr, "table:formula", NULL);
     719            3334 :         if (pszFormula && strncmp(pszFormula, "of:=", 4) == 0)
     720                 :         {
     721             274 :             osFormula = pszFormula;
     722             274 :             if (osValueType.size() == 0)
     723             220 :                 osValueType = "formula";
     724                 :         }
     725                 :         else
     726            2786 :             osFormula = "";
     727                 : 
     728                 :         nCellsRepeated = atoi(
     729            3060 :             GetAttributeValue(ppszAttr, "table:number-columns-repeated", "1"));
     730                 :     }
     731              62 :     else if (strcmp(pszName, "table:covered-table-cell") == 0)
     732                 :     {
     733                 :         /* Merged cell */
     734              62 :         apoCurLineValues.push_back("");
     735             124 :         apoCurLineTypes.push_back("");
     736                 : 
     737              62 :         nCurCol += 1;
     738                 :     }
     739            3122 : }
     740                 : 
     741                 : /************************************************************************/
     742                 : /*                            endElementRow()                           */
     743                 : /************************************************************************/
     744                 : 
     745             958 : void OGRODSDataSource::endElementRow(const char *pszName)
     746                 : {
     747             958 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     748                 :     {
     749             896 :         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             896 :         i = apoCurLineTypes.size();
     757            3976 :         while(i > 0)
     758                 :         {
     759            2928 :             i --;
     760            2928 :             if (apoCurLineTypes[i] == "")
     761                 :             {
     762            2184 :                 apoCurLineValues.resize(i);
     763            4368 :                 apoCurLineTypes.resize(i);
     764                 :             }
     765                 :             else
     766             744 :                 break;
     767                 :         }
     768                 : 
     769                 :         /* Do not add immediately empty rows. Wait until there is another non */
     770                 :         /* empty row */
     771             896 :         if (nCurLine >= 2 && apoCurLineTypes.size() == 0)
     772                 :         {
     773              56 :             nEmptyRowsAccumulated += nRowsRepeated;
     774              56 :             return;
     775                 :         }
     776             840 :         else if (nEmptyRowsAccumulated > 0)
     777                 :         {
     778             240 :             for(i = 0; i < (size_t)nEmptyRowsAccumulated; i++)
     779                 :             {
     780             216 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     781             216 :                 poCurLayer->CreateFeature(poFeature);
     782             432 :                 delete poFeature;
     783                 :             }
     784              24 :             nCurLine += nEmptyRowsAccumulated;
     785              24 :             nEmptyRowsAccumulated = 0;
     786                 :         }
     787                 : 
     788                 :         /* Backup first line values and types in special arrays */
     789             840 :         if (nCurLine == 0)
     790                 :         {
     791             214 :             apoFirstLineTypes = apoCurLineTypes;
     792             214 :             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             840 :         if (nCurLine == 1)
     806                 :         {
     807             150 :             DetectHeaderLine();
     808                 : 
     809             150 :             poCurLayer->SetHasHeaderLine(bFirstLineIsHeaders);
     810                 : 
     811             150 :             if (bFirstLineIsHeaders)
     812                 :             {
     813             286 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     814                 :                 {
     815             264 :                     const char* pszFieldName = apoFirstLineValues[i].c_str();
     816             264 :                     if (pszFieldName[0] == '\0')
     817               0 :                         pszFieldName = CPLSPrintf("Field%d", (int)i + 1);
     818             264 :                     OGRFieldType eType = OFTString;
     819             264 :                     if (i < apoCurLineValues.size())
     820                 :                     {
     821                 :                         eType = GetOGRFieldType(apoCurLineValues[i].c_str(),
     822             264 :                                                 apoCurLineTypes[i].c_str());
     823                 :                     }
     824             264 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     825             264 :                     poCurLayer->CreateField(&oFieldDefn);
     826                 :                 }
     827                 :             }
     828                 :             else
     829                 :             {
     830             326 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     831                 :                 {
     832                 :                     const char* pszFieldName =
     833             198 :                         CPLSPrintf("Field%d", (int)i + 1);
     834                 :                     OGRFieldType eType = GetOGRFieldType(
     835                 :                                             apoFirstLineValues[i].c_str(),
     836             198 :                                             apoFirstLineTypes[i].c_str());
     837             198 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     838             198 :                     poCurLayer->CreateField(&oFieldDefn);
     839                 :                 }
     840                 : 
     841             128 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     842             326 :                 for(i = 0; i < apoFirstLineValues.size(); i++)
     843                 :                 {
     844             198 :                     SetField(poFeature, i, apoFirstLineValues[i].c_str());
     845                 :                 }
     846             128 :                 poCurLayer->CreateFeature(poFeature);
     847             128 :                 delete poFeature;
     848                 :             }
     849                 :         }
     850                 : 
     851             840 :         if (nCurLine >= 1 || (nCurLine == 0 && nRowsRepeated > 1))
     852                 :         {
     853                 :             /* Add new fields found on following lines. */
     854            1292 :             if (apoCurLineValues.size() >
     855             646 :                 (size_t)poCurLayer->GetLayerDefn()->GetFieldCount())
     856                 :             {
     857             398 :                 for(i = (size_t)poCurLayer->GetLayerDefn()->GetFieldCount();
     858                 :                     i < apoCurLineValues.size();
     859                 :                     i++)
     860                 :                 {
     861                 :                     const char* pszFieldName =
     862             274 :                         CPLSPrintf("Field%d", (int)i + 1);
     863                 :                     OGRFieldType eType = GetOGRFieldType(
     864                 :                                                 apoCurLineValues[i].c_str(),
     865             274 :                                                 apoCurLineTypes[i].c_str());
     866             274 :                     OGRFieldDefn oFieldDefn(pszFieldName, eType);
     867             274 :                     poCurLayer->CreateField(&oFieldDefn);
     868                 :                 }
     869                 :             }
     870                 : 
     871                 :             /* Update field type if necessary */
     872             646 :             if (bAutodetectTypes)
     873                 :             {
     874            2222 :                 for(i = 0; i < apoCurLineValues.size(); i++)
     875                 :                 {
     876            1630 :                     if (apoCurLineValues[i].size())
     877                 :                     {
     878                 :                         OGRFieldType eValType = GetOGRFieldType(
     879                 :                                                 apoCurLineValues[i].c_str(),
     880            1274 :                                                 apoCurLineTypes[i].c_str());
     881                 :                         OGRFieldType eFieldType =
     882            1274 :                             poCurLayer->GetLayerDefn()->GetFieldDefn(i)->GetType();
     883            1274 :                         if (eFieldType == OFTDateTime &&
     884                 :                             (eValType == OFTDate || eValType == OFTTime) )
     885                 :                         {
     886                 :                             /* ok */
     887                 :                         }
     888            1274 :                         else if (eFieldType == OFTReal && eValType == OFTInteger)
     889                 :                         {
     890                 :                            /* ok */;
     891                 :                         }
     892            1258 :                         else if (eFieldType != OFTString && eValType != eFieldType)
     893                 :                         {
     894                 :                             OGRFieldDefn oNewFieldDefn(
     895              52 :                                 poCurLayer->GetLayerDefn()->GetFieldDefn(i));
     896              66 :                             if ((eFieldType == OFTDate || eFieldType == OFTTime) &&
     897                 :                                    eValType == OFTDateTime)
     898              14 :                                 oNewFieldDefn.SetType(OFTDateTime);
     899              54 :                             else if (eFieldType == OFTInteger &&
     900                 :                                      eValType == OFTReal)
     901              16 :                                 oNewFieldDefn.SetType(OFTReal);
     902                 :                             else
     903              22 :                                 oNewFieldDefn.SetType(OFTString);
     904                 :                             poCurLayer->AlterFieldDefn(i, &oNewFieldDefn,
     905              52 :                                                        ALTER_TYPE_FLAG);
     906                 :                         }
     907                 :                     }
     908                 :                 }
     909                 :             }
     910                 : 
     911                 :             /* Add feature for current line */
     912            1332 :             for(int j=0;j<nRowsRepeated;j++)
     913                 :             {
     914             686 :                 poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
     915            2464 :                 for(i = 0; i < apoCurLineValues.size(); i++)
     916                 :                 {
     917            1778 :                     SetField(poFeature, i, apoCurLineValues[i].c_str());
     918                 :                 }
     919             686 :                 poCurLayer->CreateFeature(poFeature);
     920             686 :                 delete poFeature;
     921                 :             }
     922                 :         }
     923                 : 
     924             840 :         nCurLine += nRowsRepeated;
     925                 :     }
     926                 : }
     927                 : 
     928                 : /************************************************************************/
     929                 : /*                           startElementCell()                         */
     930                 : /************************************************************************/
     931                 : 
     932            1550 : void OGRODSDataSource::startElementCell(const char *pszName,
     933                 :                                         const char **ppszAttr)
     934                 : {
     935            1550 :     if (osValue.size() == 0 && strcmp(pszName, "text:p") == 0)
     936                 :     {
     937             836 :         PushState(STATE_TEXTP);
     938                 :     }
     939            1550 : }
     940                 : 
     941                 : /************************************************************************/
     942                 : /*                            endElementCell()                          */
     943                 : /************************************************************************/
     944                 : 
     945            3774 : void OGRODSDataSource::endElementCell(const char *pszName)
     946                 : {
     947            3774 :     if (stateStack[nStackDepth].nBeginDepth == nDepth)
     948                 :     {
     949            3060 :         CPLAssert(strcmp(pszName, "table:table-cell") == 0);
     950                 : 
     951            7450 :         for(int i = 0; i < nCellsRepeated; i++)
     952                 :         {
     953            4390 :             apoCurLineValues.push_back(osValue.size() ? osValue : osFormula);
     954            4390 :             apoCurLineTypes.push_back(osValueType);
     955                 :         }
     956                 : 
     957            3060 :         nCurCol += nCellsRepeated;
     958                 :     }
     959            3774 : }
     960                 : 
     961                 : /************************************************************************/
     962                 : /*                           dataHandlerTextP()                         */
     963                 : /************************************************************************/
     964                 : 
     965             908 : void OGRODSDataSource::dataHandlerTextP(const char *data, int nLen)
     966                 : {
     967             908 :     osValue.append(data, nLen);
     968             908 : }
     969                 : 
     970                 : /************************************************************************/
     971                 : /*                             AnalyseFile()                            */
     972                 : /************************************************************************/
     973                 : 
     974             974 : void OGRODSDataSource::AnalyseFile()
     975                 : {
     976             974 :     if (bAnalysedFile)
     977             948 :         return;
     978                 : 
     979              26 :     bAnalysedFile = TRUE;
     980                 : 
     981              26 :     AnalyseSettings();
     982                 : 
     983              26 :     oParser = OGRCreateExpatXMLParser();
     984              26 :     XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
     985              26 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
     986              26 :     XML_SetUserData(oParser, this);
     987                 : 
     988              26 :     nDepth = 0;
     989              26 :     nStackDepth = 0;
     990              26 :     stateStack[0].nBeginDepth = 0;
     991              26 :     bStopParsing = FALSE;
     992              26 :     nWithoutEventCounter = 0;
     993                 : 
     994              26 :     VSIFSeekL( fpContent, 0, SEEK_SET );
     995                 : 
     996                 :     char aBuf[BUFSIZ];
     997                 :     int nDone;
     998              76 :     do
     999                 :     {
    1000              76 :         nDataHandlerCounter = 0;
    1001                 :         unsigned int nLen =
    1002              76 :             (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpContent );
    1003              76 :         nDone = VSIFEofL(fpContent);
    1004              76 :         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              76 :         nWithoutEventCounter ++;
    1014                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1015                 : 
    1016              26 :     XML_ParserFree(oParser);
    1017              26 :     oParser = NULL;
    1018                 : 
    1019              26 :     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              26 :     VSIFCloseL(fpContent);
    1027              26 :     fpContent = NULL;
    1028                 : 
    1029              26 :     bUpdated = FALSE;
    1030                 : }
    1031                 : 
    1032                 : /************************************************************************/
    1033                 : /*                        startElementStylesCbk()                       */
    1034                 : /************************************************************************/
    1035                 : 
    1036            4120 : static void XMLCALL startElementStylesCbk(void *pUserData, const char *pszName,
    1037                 :                                     const char **ppszAttr)
    1038                 : {
    1039            4120 :     ((OGRODSDataSource*)pUserData)->startElementStylesCbk(pszName, ppszAttr);
    1040            4120 : }
    1041                 : 
    1042            4120 : void OGRODSDataSource::startElementStylesCbk(const char *pszName,
    1043                 :                                              const char **ppszAttr)
    1044                 : {
    1045            4120 :     if (bStopParsing) return;
    1046                 : 
    1047            4120 :     nWithoutEventCounter = 0;
    1048                 : 
    1049            4120 :     if (nStackDepth == 0 &&
    1050                 :         strcmp(pszName, "config:config-item-map-named") == 0 &&
    1051                 :         strcmp(GetAttributeValue(ppszAttr, "config:name", ""), "Tables") == 0)
    1052                 :     {
    1053              24 :         stateStack[++nStackDepth].nBeginDepth = nDepth;
    1054                 :     }
    1055            4280 :     else if (nStackDepth == 1 && strcmp(pszName, "config:config-item-map-entry") == 0)
    1056                 :     {
    1057             184 :         const char* pszTableName = GetAttributeValue(ppszAttr, "config:name", NULL);
    1058             184 :         if (pszTableName)
    1059                 :         {
    1060             184 :             osCurrentConfigTableName = pszTableName;
    1061             184 :             nFlags = 0;
    1062             184 :             stateStack[++nStackDepth].nBeginDepth = nDepth;
    1063                 :         }
    1064                 :     }
    1065            3912 :     else if (nStackDepth == 2 && strcmp(pszName, "config:config-item") == 0)
    1066                 :     {
    1067            2684 :         const char* pszConfigName = GetAttributeValue(ppszAttr, "config:name", NULL);
    1068            2684 :         if (pszConfigName)
    1069                 :         {
    1070            2684 :             osConfigName = pszConfigName;
    1071            2684 :             osValue = "";
    1072            2684 :             stateStack[++nStackDepth].nBeginDepth = nDepth;
    1073                 :         }
    1074                 :     }
    1075                 : 
    1076            4120 :     nDepth++;
    1077                 : }
    1078                 : 
    1079                 : /************************************************************************/
    1080                 : /*                        endElementStylesCbk()                         */
    1081                 : /************************************************************************/
    1082                 : 
    1083            4120 : static void XMLCALL endElementStylesCbk(void *pUserData, const char *pszName)
    1084                 : {
    1085            4120 :     ((OGRODSDataSource*)pUserData)->endElementStylesCbk(pszName);
    1086            4120 : }
    1087                 : 
    1088            4120 : void OGRODSDataSource::endElementStylesCbk(const char *pszName)
    1089                 : {
    1090            4120 :     if (bStopParsing) return;
    1091                 : 
    1092            4120 :     nWithoutEventCounter = 0;
    1093            4120 :     nDepth--;
    1094                 : 
    1095            4120 :     if (nStackDepth > 0 && stateStack[nStackDepth].nBeginDepth == nDepth)
    1096                 :     {
    1097            2892 :         if (nStackDepth == 2)
    1098                 :         {
    1099             184 :             if (nFlags == (1 | 2))
    1100               4 :                 osSetLayerHasSplitter.insert(osCurrentConfigTableName);
    1101                 :         }
    1102            2892 :         if (nStackDepth == 3)
    1103                 :         {
    1104            2684 :             if (osConfigName == "VerticalSplitMode" && osValue == "2")
    1105               4 :                 nFlags |= 1;
    1106            2680 :             else if (osConfigName == "VerticalSplitPosition" && osValue == "1")
    1107               4 :                 nFlags |= 2;
    1108                 :         }
    1109            2892 :         nStackDepth --;
    1110                 :     }
    1111                 : }
    1112                 : 
    1113                 : /************************************************************************/
    1114                 : /*                         dataHandlerStylesCbk()                       */
    1115                 : /************************************************************************/
    1116                 : 
    1117            4322 : static void XMLCALL dataHandlerStylesCbk(void *pUserData, const char *data, int nLen)
    1118                 : {
    1119            4322 :     ((OGRODSDataSource*)pUserData)->dataHandlerStylesCbk(data, nLen);
    1120            4322 : }
    1121                 : 
    1122            4322 : void OGRODSDataSource::dataHandlerStylesCbk(const char *data, int nLen)
    1123                 : {
    1124            4322 :     if (bStopParsing) return;
    1125                 : 
    1126            4322 :     nDataHandlerCounter ++;
    1127            4322 :     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            4322 :     nWithoutEventCounter = 0;
    1137                 : 
    1138            4322 :     if (nStackDepth == 3)
    1139                 :     {
    1140            2684 :         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              26 : void OGRODSDataSource::AnalyseSettings()
    1152                 : {
    1153              26 :     if (fpSettings == NULL)
    1154               2 :         return;
    1155                 : 
    1156              24 :     oParser = OGRCreateExpatXMLParser();
    1157              24 :     XML_SetElementHandler(oParser, ::startElementStylesCbk, ::endElementStylesCbk);
    1158              24 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerStylesCbk);
    1159              24 :     XML_SetUserData(oParser, this);
    1160                 : 
    1161              24 :     nDepth = 0;
    1162              24 :     nStackDepth = 0;
    1163              24 :     bStopParsing = FALSE;
    1164              24 :     nWithoutEventCounter = 0;
    1165                 : 
    1166              24 :     VSIFSeekL( fpSettings, 0, SEEK_SET );
    1167                 : 
    1168                 :     char aBuf[BUFSIZ];
    1169                 :     int nDone;
    1170              62 :     do
    1171                 :     {
    1172              62 :         nDataHandlerCounter = 0;
    1173                 :         unsigned int nLen =
    1174              62 :             (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpSettings );
    1175              62 :         nDone = VSIFEofL(fpSettings);
    1176              62 :         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              62 :         nWithoutEventCounter ++;
    1186                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1187                 : 
    1188              24 :     XML_ParserFree(oParser);
    1189              24 :     oParser = NULL;
    1190                 : 
    1191              24 :     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              24 :     VSIFCloseL(fpSettings);
    1199              24 :     fpSettings = NULL;
    1200                 : }
    1201                 : 
    1202                 : /************************************************************************/
    1203                 : /*                            CreateLayer()                             */
    1204                 : /************************************************************************/
    1205                 : 
    1206                 : OGRLayer *
    1207              16 : 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              16 :     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              16 :     AnalyseFile();
    1227                 : 
    1228                 : /* -------------------------------------------------------------------- */
    1229                 : /*      Do we already have this layer?  If so, should we blow it        */
    1230                 : /*      away?                                                           */
    1231                 : /* -------------------------------------------------------------------- */
    1232                 :     int iLayer;
    1233                 : 
    1234              72 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
    1235                 :     {
    1236              56 :         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              16 :     OGRLayer* poLayer = new OGRODSLayer(this, pszLayerName, TRUE);
    1259                 : 
    1260              16 :     papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
    1261              16 :     papoLayers[nLayers] = poLayer;
    1262              16 :     nLayers ++;
    1263                 : 
    1264              16 :     bUpdated = TRUE;
    1265                 : 
    1266              16 :     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              64 : static int HasHeaderLine(OGRLayer* poLayer)
    1347                 : {
    1348              64 :     OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
    1349              64 :     int bHasHeaders = FALSE;
    1350                 : 
    1351             304 :     for(int j=0;j<poFDefn->GetFieldCount();j++)
    1352                 :     {
    1353             240 :         if (strcmp(poFDefn->GetFieldDefn(j)->GetNameRef(),
    1354                 :                     CPLSPrintf("Field%d", j+1)) != 0)
    1355              96 :             bHasHeaders = TRUE;
    1356                 :     }
    1357                 : 
    1358              64 :     return bHasHeaders;
    1359                 : }
    1360                 : 
    1361                 : /************************************************************************/
    1362                 : /*                            WriteLayer()                              */
    1363                 : /************************************************************************/
    1364                 : 
    1365              32 : static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
    1366                 : {
    1367                 :     int j;
    1368              32 :     const char* pszLayerName = poLayer->GetName();
    1369              32 :     char* pszXML = OGRGetXML_UTF8_EscapedString(pszLayerName);
    1370              32 :     VSIFPrintfL(fp, "<table:table table:name=\"%s\">\n", pszXML);
    1371              32 :     CPLFree(pszXML);
    1372                 :     
    1373              32 :     poLayer->ResetReading();
    1374                 : 
    1375              32 :     OGRFeature* poFeature = poLayer->GetNextFeature();
    1376                 : 
    1377              32 :     OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
    1378              32 :     int bHasHeaders = HasHeaderLine(poLayer);
    1379                 : 
    1380             152 :     for(j=0;j<poFDefn->GetFieldCount();j++)
    1381                 :     {
    1382             120 :         int nStyleNumber = 1;
    1383             120 :         if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
    1384              12 :             nStyleNumber = 2;
    1385                 :         VSIFPrintfL(fp, "<table:table-column table:style-name=\"co%d\" "
    1386                 :                         "table:default-cell-style-name=\"Default\"/>\n",
    1387             120 :                     nStyleNumber);
    1388                 :     }
    1389                 : 
    1390              32 :     if (bHasHeaders && poFeature != NULL)
    1391                 :     {
    1392               4 :         VSIFPrintfL(fp, "<table:table-row>\n");
    1393              52 :         for(j=0;j<poFDefn->GetFieldCount();j++)
    1394                 :         {
    1395              48 :             const char* pszVal = poFDefn->GetFieldDefn(j)->GetNameRef();
    1396                 : 
    1397              48 :             VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
    1398              48 :             pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
    1399              48 :             VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
    1400              48 :             CPLFree(pszXML);
    1401              48 :             VSIFPrintfL(fp, "</table:table-cell>\n");
    1402                 :         }
    1403               4 :         VSIFPrintfL(fp, "</table:table-row>\n");
    1404                 :     }
    1405                 : 
    1406             236 :     while(poFeature != NULL)
    1407                 :     {
    1408             172 :         VSIFPrintfL(fp, "<table:table-row>\n");
    1409            1020 :         for(j=0;j<poFeature->GetFieldCount();j++)
    1410                 :         {
    1411             848 :             if (poFeature->IsFieldSet(j))
    1412                 :             {
    1413             220 :                 OGRFieldType eType = poFDefn->GetFieldDefn(j)->GetType();
    1414                 : 
    1415             220 :                 if (eType == OFTReal)
    1416                 :                 {
    1417                 :                     VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
    1418                 :                                 "office:value=\"%.16f\"/>\n",
    1419              32 :                                 poFeature->GetFieldAsDouble(j));
    1420                 :                 }
    1421             188 :                 else if (eType == OFTInteger)
    1422                 :                 {
    1423                 :                     VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
    1424                 :                                 "office:value=\"%d\"/>\n",
    1425              24 :                                 poFeature->GetFieldAsInteger(j));
    1426                 :                 }
    1427             164 :                 else if (eType == OFTDateTime)
    1428                 :                 {
    1429                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
    1430                 :                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
    1431              16 :                                                     &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              16 :                                 nYear, nMonth, nDay, nHour, nMinute, nSecond);
    1436                 :                     VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
    1437              16 :                                 nDay, nMonth, nYear, nHour, nMinute, nSecond);
    1438              16 :                     VSIFPrintfL(fp, "</table:table-cell>\n");
    1439                 :                 }
    1440             148 :                 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             148 :                 else if (eType == OFTTime)
    1454                 :                 {
    1455                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
    1456                 :                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
    1457               4 :                                                     &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               4 :                                 nHour, nMinute, nSecond);
    1462                 :                     VSIFPrintfL(fp, "<text:p>%02d:%02d:%02d</text:p>\n",
    1463               4 :                                 nHour, nMinute, nSecond);
    1464               4 :                     VSIFPrintfL(fp, "</table:table-cell>\n");
    1465                 :                 }
    1466                 :                 else
    1467                 :                 {
    1468             144 :                     const char* pszVal = poFeature->GetFieldAsString(j);
    1469             144 :                     pszXML = OGRGetXML_UTF8_EscapedString(pszVal);
    1470             144 :                     if (strncmp(pszVal, "of:=", 4) == 0)
    1471                 :                     {
    1472               0 :                         VSIFPrintfL(fp, "<table:table-cell table:formula=\"%s\"/>\n", pszXML);
    1473                 :                     }
    1474                 :                     else
    1475                 :                     {
    1476             144 :                         VSIFPrintfL(fp, "<table:table-cell office:value-type=\"string\">\n");
    1477             144 :                         VSIFPrintfL(fp, "<text:p>%s</text:p>\n", pszXML);
    1478             144 :                         VSIFPrintfL(fp, "</table:table-cell>\n");
    1479                 :                     }
    1480             144 :                     CPLFree(pszXML);
    1481                 :                 }
    1482                 :             }
    1483                 :             else
    1484                 :             {
    1485             628 :                 VSIFPrintfL(fp, "<table:table-cell/>\n");
    1486                 :             }
    1487                 :         }
    1488             172 :         VSIFPrintfL(fp, "</table:table-row>\n");
    1489                 : 
    1490             172 :         delete poFeature;
    1491             172 :         poFeature = poLayer->GetNextFeature();
    1492                 :     }
    1493                 : 
    1494              32 :     VSIFPrintfL(fp, "</table:table>\n");
    1495              32 : }
    1496                 : 
    1497                 : /************************************************************************/
    1498                 : /*                            SyncToDisk()                              */
    1499                 : /************************************************************************/
    1500                 : 
    1501              28 : OGRErr OGRODSDataSource::SyncToDisk()
    1502                 : {
    1503              28 :     if (!bUpdated)
    1504              24 :         return OGRERR_NONE;
    1505                 : 
    1506               4 :     CPLAssert(fpSettings == NULL);
    1507               4 :     CPLAssert(fpContent == NULL);
    1508                 : 
    1509                 :     VSIStatBufL sStat;
    1510               4 :     if (VSIStatL(pszName, &sStat) == 0)
    1511                 :     {
    1512               2 :         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               4 :     void *hZIP = CPLCreateZip(pszName, NULL);
    1522               4 :     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               4 :     char** papszOptions = CSLAddString(NULL, "COMPRESSED=NO");
    1531               4 :     CPLCreateFileInZip(hZIP, "mimetype", papszOptions );
    1532                 :     CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
    1533               4 :                       strlen("application/vnd.oasis.opendocument.spreadsheet"));
    1534               4 :     CPLCloseFileInZip(hZIP);
    1535               4 :     CSLDestroy(papszOptions);
    1536                 : 
    1537                 :     /* Now close ZIP file */
    1538               4 :     CPLCloseZip(hZIP);
    1539               4 :     hZIP = NULL;
    1540                 : 
    1541                 :     /* Re-open with VSILFILE */
    1542               4 :     VSILFILE* fpZIP = VSIFOpenL(CPLSPrintf("/vsizip/%s", pszName), "ab");
    1543               4 :     if (fpZIP == NULL)
    1544               0 :         return OGRERR_FAILURE;
    1545                 : 
    1546                 :     VSILFILE* fp;
    1547                 :     int i;
    1548                 : 
    1549               4 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/META-INF/manifest.xml", pszName), "wb");
    1550               4 :     VSIFPrintfL(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    1551               4 :     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               4 :                 "manifest:version=\"1.2\" manifest:full-path=\"/\"/>\n");
    1555                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1556               4 :                     "manifest:full-path=\"content.xml\"/>\n");
    1557                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1558               4 :                     "manifest:full-path=\"styles.xml\"/>\n");
    1559                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1560               4 :                     "manifest:full-path=\"meta.xml\"/>\n");
    1561                 :     VSIFPrintfL(fp, "<manifest:file-entry manifest:media-type=\"text/xml\" "
    1562               4 :                     "manifest:full-path=\"settings.xml\"/>\n");
    1563               4 :     VSIFPrintfL(fp, "</manifest:manifest>\n");
    1564               4 :     VSIFCloseL(fp);
    1565                 : 
    1566               4 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/meta.xml", pszName), "wb");
    1567               4 :     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               4 :                 "office:version=\"1.2\">\n");
    1571               4 :     VSIFPrintfL(fp, "</office:document-meta>\n");
    1572               4 :     VSIFCloseL(fp);
    1573                 : 
    1574               4 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/settings.xml", pszName), "wb");
    1575               4 :     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               4 :                 "office:version=\"1.2\">\n");
    1581               4 :     VSIFPrintfL(fp, "<office:settings>\n");
    1582               4 :     VSIFPrintfL(fp, "<config:config-item-set config:name=\"ooo:view-settings\">\n");
    1583               4 :     VSIFPrintfL(fp, "<config:config-item-map-indexed config:name=\"Views\">\n");
    1584               4 :     VSIFPrintfL(fp, "<config:config-item-map-entry>\n");
    1585               4 :     VSIFPrintfL(fp, "<config:config-item-map-named config:name=\"Tables\">\n");
    1586              36 :     for(i=0;i<nLayers;i++)
    1587                 :     {
    1588              32 :         OGRLayer* poLayer = GetLayer(i);
    1589              32 :         if (HasHeaderLine(poLayer))
    1590                 :         {
    1591                 :             /* Add vertical splitter */
    1592               4 :             char* pszXML = OGRGetXML_UTF8_EscapedString(GetLayer(i)->GetName());
    1593               4 :             VSIFPrintfL(fp, "<config:config-item-map-entry config:name=\"%s\">\n", pszXML);
    1594               4 :             CPLFree(pszXML);
    1595               4 :             VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitMode\" config:type=\"short\">2</config:config-item>\n");
    1596               4 :             VSIFPrintfL(fp, "<config:config-item config:name=\"VerticalSplitPosition\" config:type=\"int\">1</config:config-item>\n");
    1597               4 :             VSIFPrintfL(fp, "<config:config-item config:name=\"ActiveSplitRange\" config:type=\"short\">2</config:config-item>\n");
    1598               4 :             VSIFPrintfL(fp, "<config:config-item config:name=\"PositionTop\" config:type=\"int\">0</config:config-item>\n");
    1599               4 :             VSIFPrintfL(fp, "<config:config-item config:name=\"PositionBottom\" config:type=\"int\">1</config:config-item>\n");
    1600               4 :             VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
    1601                 :         }
    1602                 :     }
    1603               4 :     VSIFPrintfL(fp, "</config:config-item-map-named>\n");
    1604               4 :     VSIFPrintfL(fp, "</config:config-item-map-entry>\n");
    1605               4 :     VSIFPrintfL(fp, "</config:config-item-map-indexed>\n");
    1606               4 :     VSIFPrintfL(fp, "</config:config-item-set>\n");
    1607               4 :     VSIFPrintfL(fp, "</office:settings>\n");
    1608               4 :     VSIFPrintfL(fp, "</office:document-settings>\n");
    1609               4 :     VSIFCloseL(fp);
    1610                 : 
    1611               4 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/styles.xml", pszName), "wb");
    1612               4 :     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               4 :                 "office:version=\"1.2\">\n");
    1617               4 :     VSIFPrintfL(fp, "<office:styles>\n");
    1618                 :     VSIFPrintfL(fp, "<style:style style:name=\"Default\" "
    1619               4 :                     "style:family=\"table-cell\">\n");
    1620               4 :     VSIFPrintfL(fp, "</style:style>\n");
    1621               4 :     VSIFPrintfL(fp, "</office:styles>\n");
    1622               4 :     VSIFPrintfL(fp, "</office:document-styles>\n");
    1623               4 :     VSIFCloseL(fp);
    1624                 : 
    1625               4 :     fp = VSIFOpenL(CPLSPrintf("/vsizip/%s/content.xml", pszName), "wb");
    1626               4 :     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               4 :                 "office:version=\"1.2\">\n");
    1636               4 :     VSIFPrintfL(fp, "<office:scripts/>\n");
    1637               4 :     VSIFPrintfL(fp, "<office:automatic-styles>\n");
    1638                 :     VSIFPrintfL(fp, "<style:style style:name=\"co1\" "
    1639               4 :                     "style:family=\"table-column\">\n");
    1640                 :     VSIFPrintfL(fp, "<style:table-column-properties "
    1641                 :                     "fo:break-before=\"auto\" "
    1642               4 :                     "style:column-width=\"2.5cm\"/>\n");
    1643               4 :     VSIFPrintfL(fp, "</style:style>\n");
    1644                 :     VSIFPrintfL(fp, "<style:style style:name=\"co2\" "
    1645               4 :                     "style:family=\"table-column\">\n");
    1646                 :     VSIFPrintfL(fp, "<style:table-column-properties "
    1647                 :                     "fo:break-before=\"auto\" "
    1648               4 :                     "style:column-width=\"5cm\"/>\n");
    1649               4 :     VSIFPrintfL(fp, "</style:style>\n");
    1650                 :     VSIFPrintfL(fp, "<number:date-style style:name=\"nDate\" "
    1651               4 :                     "number:automatic-order=\"true\">\n");
    1652               4 :     VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
    1653               4 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1654               4 :     VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
    1655               4 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1656               4 :     VSIFPrintfL(fp, "<number:year/>\n");
    1657               4 :     VSIFPrintfL(fp, "</number:date-style>\n");
    1658               4 :     VSIFPrintfL(fp, "<number:time-style style:name=\"nTime\">\n");
    1659               4 :     VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
    1660               4 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1661               4 :     VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
    1662               4 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1663               4 :     VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
    1664               4 :     VSIFPrintfL(fp, "</number:time-style>\n");
    1665                 :     VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTime\" "
    1666               4 :                     "number:automatic-order=\"true\">\n");
    1667               4 :     VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
    1668               4 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1669               4 :     VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
    1670               4 :     VSIFPrintfL(fp, "<number:text>/</number:text>\n");
    1671               4 :     VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
    1672               4 :     VSIFPrintfL(fp, "<number:text> </number:text>\n");
    1673               4 :     VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
    1674               4 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1675               4 :     VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
    1676               4 :     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
    1677               4 :     VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
    1678               4 :     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               4 :                     "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               4 :                     "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               4 :                     "style:data-style-name=\"nDateTime\"/>\n");
    1691               4 :     VSIFPrintfL(fp, "</office:automatic-styles>\n");
    1692               4 :     VSIFPrintfL(fp, "<office:body>\n");
    1693               4 :     VSIFPrintfL(fp, "<office:spreadsheet>\n");
    1694              36 :     for(i=0;i<nLayers;i++)
    1695                 :     {
    1696              32 :         WriteLayer(fp, GetLayer(i));
    1697                 :     }
    1698               4 :     VSIFPrintfL(fp, "</office:spreadsheet>\n");
    1699               4 :     VSIFPrintfL(fp, "</office:body>\n");
    1700               4 :     VSIFPrintfL(fp, "</office:document-content>\n");
    1701               4 :     VSIFCloseL(fp);
    1702                 : 
    1703                 :     /* Now close ZIP file */
    1704               4 :     VSIFCloseL(fpZIP);
    1705                 : 
    1706                 :     /* Reset updated flag at datasource and layer level */
    1707               4 :     bUpdated = FALSE;
    1708              36 :     for(int i = 0; i<nLayers; i++)
    1709                 :     {
    1710              32 :         ((OGRODSLayer*)papoLayers[i])->SetUpdated(FALSE);
    1711                 :     }
    1712                 : 
    1713               4 :     return OGRERR_NONE;
    1714                 : }
    1715                 : 
    1716                 : /************************************************************************/
    1717                 : /*                          EvaluateRange()                             */
    1718                 : /************************************************************************/
    1719                 : 
    1720              68 : int ODSCellEvaluator::EvaluateRange(int nRow1, int nCol1, int nRow2, int nCol2,
    1721                 :                                     std::vector<ods_formula_node>& aoOutValues)
    1722                 : {
    1723             136 :     if (nRow1 < 0 || nRow1 >= poLayer->GetFeatureCount(FALSE) ||
    1724              68 :         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             136 :     if (nRow2 < 0 || nRow2 >= poLayer->GetFeatureCount(FALSE) ||
    1732              68 :         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              68 :     int nIndexBackup = poLayer->GetNextReadFID();
    1740                 : 
    1741              68 :     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             130 :     for(int nRow = nRow1; nRow <= nRow2; nRow ++)
    1749                 :     {
    1750              68 :         OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1751                 : 
    1752              68 :         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             166 :         for(int nCol = nCol1; nCol <= nCol2; nCol++)
    1761                 :         {
    1762             104 :             if (!poFeature->IsFieldSet(nCol))
    1763                 :             {
    1764              12 :                 aoOutValues.push_back(ods_formula_node());
    1765                 :             }
    1766              92 :             else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
    1767                 :             {
    1768               0 :                 aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
    1769                 :             }
    1770              92 :             else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
    1771                 :             {
    1772               0 :                 aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
    1773                 :             }
    1774                 :             else
    1775                 :             {
    1776              92 :                 std::string osVal(poFeature->GetFieldAsString(nCol));
    1777             184 :                 if (strncmp(osVal.c_str(), "of:=", 4) == 0)
    1778                 :                 {
    1779              20 :                     delete poFeature;
    1780              20 :                     poFeature = NULL;
    1781                 : 
    1782              20 :                     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               6 :                         poLayer->SetNextByIndex(nIndexBackup);
    1788               6 :                         return FALSE;
    1789                 :                     }
    1790                 : 
    1791              14 :                     poLayer->SetNextByIndex(nRow);
    1792              14 :                     poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1793                 : 
    1794              14 :                     if (!poFeature->IsFieldSet(nCol))
    1795                 :                     {
    1796               0 :                         aoOutValues.push_back(ods_formula_node());
    1797                 :                     }
    1798              14 :                     else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTInteger)
    1799                 :                     {
    1800               0 :                         aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsInteger(nCol)));
    1801                 :                     }
    1802              14 :                     else if (poFeature->GetFieldDefnRef(nCol)->GetType() == OFTReal)
    1803                 :                     {
    1804               0 :                         aoOutValues.push_back(ods_formula_node(poFeature->GetFieldAsDouble(nCol)));
    1805                 :                     }
    1806                 :                     else
    1807                 :                     {
    1808              14 :                         osVal = poFeature->GetFieldAsString(nCol);
    1809              14 :                         if (strncmp(osVal.c_str(), "of:=", 4) != 0)
    1810                 :                         {
    1811               2 :                             CPLValueType eType = CPLGetValueType(osVal.c_str());
    1812                 :                             /* Try to convert into numeric value if possible */
    1813               2 :                             if (eType != CPL_VALUE_STRING)
    1814               2 :                                 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              72 :                     CPLValueType eType = CPLGetValueType(osVal.c_str());
    1823                 :                     /* Try to convert into numeric value if possible */
    1824              72 :                     if (eType != CPL_VALUE_STRING)
    1825              26 :                         aoOutValues.push_back(ods_formula_node(CPLAtofM(osVal.c_str())));
    1826                 :                     else
    1827              46 :                         aoOutValues.push_back(ods_formula_node(osVal.c_str()));
    1828               0 :                 }
    1829                 :             }
    1830                 :         }
    1831                 : 
    1832              62 :         delete poFeature;
    1833                 :     }
    1834                 : 
    1835              62 :     poLayer->SetNextByIndex(nIndexBackup);
    1836                 : 
    1837              62 :     return TRUE;
    1838                 : }
    1839                 : 
    1840                 : /************************************************************************/
    1841                 : /*                            Evaluate()                                */
    1842                 : /************************************************************************/
    1843                 : 
    1844             240 : int ODSCellEvaluator::Evaluate(int nRow, int nCol)
    1845                 : {
    1846             240 :     if (oVisisitedCells.find(std::pair<int,int>(nRow, nCol)) != oVisisitedCells.end())
    1847                 :     {
    1848                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1849               6 :                 "Circular dependency with (row=%d, col=%d)", nRow + 1, nCol + 1);
    1850               6 :         return FALSE;
    1851                 :     }
    1852                 : 
    1853             234 :     oVisisitedCells.insert(std::pair<int,int>(nRow, nCol));
    1854                 : 
    1855             234 :     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             234 :     OGRFeature* poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1863             234 :     if (poFeature->IsFieldSet(nCol) &&
    1864                 :         poFeature->GetFieldDefnRef(nCol)->GetType() == OFTString)
    1865                 :     {
    1866             234 :         const char* pszVal = poFeature->GetFieldAsString(nCol);
    1867             234 :         if (strncmp(pszVal, "of:=", 4) == 0)
    1868                 :         {
    1869             232 :             ods_formula_node* expr_out = ods_formula_compile( pszVal + 4 );
    1870             232 :             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             212 :                 delete poFeature;
    1876             212 :                 poLayer->SetNextByIndex(nRow);
    1877             212 :                 poFeature = poLayer->GetNextFeatureWithoutFIDHack();
    1878                 : 
    1879             212 :                 if (expr_out->field_type == ODS_FIELD_TYPE_EMPTY)
    1880                 :                 {
    1881               0 :                     poFeature->UnsetField(nCol);
    1882               0 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1883                 :                 }
    1884             212 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_INTEGER)
    1885                 :                 {
    1886             166 :                     poFeature->SetField(nCol, expr_out->int_value);
    1887             166 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1888                 :                 }
    1889              46 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_FLOAT)
    1890                 :                 {
    1891              14 :                     poFeature->SetField(nCol, expr_out->float_value);
    1892              14 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1893                 :                 }
    1894              32 :                 else if (expr_out->field_type == ODS_FIELD_TYPE_STRING)
    1895                 :                 {
    1896              32 :                     poFeature->SetField(nCol, expr_out->string_value);
    1897              32 :                     poLayer->SetFeatureWithoutFIDHack(poFeature);
    1898                 :                 }
    1899                 :             }
    1900             232 :             delete expr_out;
    1901                 :         }
    1902                 :     }
    1903                 : 
    1904             234 :     delete poFeature;
    1905                 : 
    1906             234 :     return TRUE;
    1907                 : }

Generated by: LCOV version 1.7