LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/xls - ogrxlslayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 144 159 90.6 %
Date: 2024-05-03 15:49:35 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  XLS Translator
       4             :  * Purpose:  Implements OGRXLSLayer class.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011-2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "include_freexl.h"
      30             : 
      31             : #include "ogr_xls.h"
      32             : #include "cpl_conv.h"
      33             : #include "cpl_string.h"
      34             : 
      35             : /************************************************************************/
      36             : /*                            OGRXLSLayer()                             */
      37             : /************************************************************************/
      38             : 
      39           4 : OGRXLSLayer::OGRXLSLayer(OGRXLSDataSource *poDSIn, const char *pszSheetname,
      40           4 :                          int iSheetIn, int nRowsIn, unsigned short nColsIn)
      41           8 :     : poDS(poDSIn), poFeatureDefn(nullptr), pszName(CPLStrdup(pszSheetname)),
      42             :       iSheet(iSheetIn), bFirstLineIsHeaders(false), nRows(nRowsIn),
      43           4 :       nCols(nColsIn), nNextFID(0)
      44             : {
      45           4 :     SetDescription(pszName);
      46           4 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                            ~OGRXLSLayer()                            */
      50             : /************************************************************************/
      51             : 
      52           8 : OGRXLSLayer::~OGRXLSLayer()
      53             : 
      54             : {
      55           4 :     CPLFree(pszName);
      56           4 :     if (poFeatureDefn)
      57           3 :         poFeatureDefn->Release();
      58           8 : }
      59             : 
      60             : /************************************************************************/
      61             : /*                            ResetReading()                            */
      62             : /************************************************************************/
      63             : 
      64          58 : void OGRXLSLayer::ResetReading()
      65             : 
      66             : {
      67          58 :     if (poFeatureDefn != nullptr)
      68             :     {
      69          58 :         nNextFID = bFirstLineIsHeaders ? 1 : 0;
      70             :     }
      71          58 : }
      72             : 
      73             : /************************************************************************/
      74             : /*                          DetectHeaderLine()                          */
      75             : /************************************************************************/
      76             : 
      77           3 : void OGRXLSLayer::DetectHeaderLine(const void *xlshandle)
      78             : 
      79             : {
      80             :     FreeXL_CellValue sCellValue;
      81           3 :     int nCountTextOnSecondLine = 0;
      82           3 :     unsigned short i = 0;  // Used after for.
      83          18 :     for (; i < nCols && nRows >= 2; i++)
      84             :     {
      85          15 :         if (freexl_get_cell_value(xlshandle, 0, i, &sCellValue) == FREEXL_OK)
      86             :         {
      87          15 :             if (sCellValue.type != FREEXL_CELL_TEXT &&
      88          15 :                 sCellValue.type != FREEXL_CELL_SST_TEXT)
      89             :             {
      90             :                 /* If the values in the first line are not text, then it is */
      91             :                 /* not a header line */
      92           0 :                 break;
      93             :             }
      94             :         }
      95          15 :         if (freexl_get_cell_value(xlshandle, 1, i, &sCellValue) == FREEXL_OK)
      96             :         {
      97          15 :             if (sCellValue.type == FREEXL_CELL_TEXT ||
      98          15 :                 sCellValue.type == FREEXL_CELL_SST_TEXT)
      99             :             {
     100             :                 /* If there are only text values on the second line, then we
     101             :                  * cannot */
     102             :                 /* know if it is a header line or just a regular line */
     103           0 :                 nCountTextOnSecondLine++;
     104             :             }
     105             :         }
     106             :     }
     107             : 
     108           3 :     const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
     109           3 :     if (EQUAL(pszXLSHeaders, "FORCE"))
     110           0 :         bFirstLineIsHeaders = true;
     111           3 :     else if (EQUAL(pszXLSHeaders, "DISABLE"))
     112           0 :         bFirstLineIsHeaders = false;
     113           3 :     else if (i == nCols && nCountTextOnSecondLine != nCols)
     114           3 :         bFirstLineIsHeaders = true;
     115           3 : }
     116             : 
     117             : /************************************************************************/
     118             : /*                         DetectColumnTypes()                          */
     119             : /************************************************************************/
     120             : 
     121           2 : void OGRXLSLayer::DetectColumnTypes(const void *xlshandle, int *paeFieldTypes)
     122             : 
     123             : {
     124             :     FreeXL_CellValue sCellValue;
     125           8 :     for (int j = bFirstLineIsHeaders ? 1 : 0; j < nRows; j++)
     126             :     {
     127          36 :         for (unsigned short i = 0; i < nCols; i++)
     128             :         {
     129          30 :             if (freexl_get_cell_value(xlshandle, j, i, &sCellValue) ==
     130             :                 FREEXL_OK)
     131             :             {
     132          30 :                 int eType = paeFieldTypes[i];
     133          30 :                 switch (sCellValue.type)
     134             :                 {
     135           8 :                     case FREEXL_CELL_INT:
     136           8 :                         eType = OFTInteger;
     137           8 :                         break;
     138           2 :                     case FREEXL_CELL_DOUBLE:
     139           2 :                         eType = OFTReal;
     140           2 :                         break;
     141           4 :                     case FREEXL_CELL_TEXT:
     142             :                     case FREEXL_CELL_SST_TEXT:
     143           4 :                         eType = OFTString;
     144           4 :                         break;
     145           6 :                     case FREEXL_CELL_DATE:
     146           6 :                         eType = OFTDate;
     147           6 :                         break;
     148           2 :                     case FREEXL_CELL_DATETIME:
     149           2 :                         eType = OFTDateTime;
     150           2 :                         break;
     151           2 :                     case FREEXL_CELL_TIME:
     152           2 :                         eType = OFTTime;
     153           2 :                         break;
     154           6 :                     case FREEXL_CELL_NULL:
     155           6 :                         break;
     156           0 :                     default:
     157           0 :                         break;
     158             :                 }
     159             : 
     160          30 :                 if (paeFieldTypes[i] < 0)
     161             :                 {
     162          12 :                     paeFieldTypes[i] = eType;
     163             :                 }
     164          18 :                 else if (eType != paeFieldTypes[i])
     165             :                 {
     166           8 :                     if ((paeFieldTypes[i] == OFTDate ||
     167           6 :                          paeFieldTypes[i] == OFTTime ||
     168           8 :                          paeFieldTypes[i] == OFTDateTime) &&
     169           4 :                         (eType == OFTDate || eType == OFTTime ||
     170             :                          eType == OFTDateTime))
     171           4 :                         paeFieldTypes[i] = OFTDateTime;
     172           4 :                     else if (paeFieldTypes[i] == OFTReal && eType == OFTInteger)
     173             :                         /* nothing */;
     174           2 :                     else if (paeFieldTypes[i] == OFTInteger && eType == OFTReal)
     175           2 :                         paeFieldTypes[i] = OFTReal;
     176             :                     else
     177           0 :                         paeFieldTypes[i] = OFTString;
     178             :                 }
     179             :             }
     180             :         }
     181             :     }
     182           2 : }
     183             : 
     184             : /************************************************************************/
     185             : /*                            GetLayerDefn()                            */
     186             : /************************************************************************/
     187             : 
     188         286 : OGRFeatureDefn *OGRXLSLayer::GetLayerDefn()
     189             : {
     190         286 :     if (poFeatureDefn)
     191         283 :         return poFeatureDefn;
     192             : 
     193           3 :     poFeatureDefn = new OGRFeatureDefn(pszName);
     194           3 :     poFeatureDefn->Reference();
     195           3 :     poFeatureDefn->SetGeomType(wkbNone);
     196             : 
     197           3 :     const void *xlshandle = poDS->GetXLSHandle();
     198           3 :     if (xlshandle == nullptr)
     199           0 :         return poFeatureDefn;
     200             : 
     201           3 :     freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
     202             : 
     203           3 :     if (nRows > 0)
     204             :     {
     205             : 
     206             :         FreeXL_CellValue sCellValue;
     207             : 
     208           3 :         DetectHeaderLine(xlshandle);
     209             : 
     210           3 :         int *paeFieldTypes = (int *)CPLMalloc(nCols * sizeof(int));
     211          18 :         for (unsigned short i = 0; i < nCols; i++)
     212             :         {
     213          15 :             paeFieldTypes[i] = -1;
     214             :         }
     215             : 
     216             :         const char *pszXLSFieldTypes =
     217           3 :             CPLGetConfigOption("OGR_XLS_FIELD_TYPES", "");
     218           3 :         if (!EQUAL(pszXLSFieldTypes, "STRING"))
     219           2 :             DetectColumnTypes(xlshandle, paeFieldTypes);
     220             : 
     221          18 :         for (unsigned short i = 0; i < nCols; i++)
     222             :         {
     223          15 :             OGRFieldType eType = (OGRFieldType)paeFieldTypes[i];
     224          15 :             if (paeFieldTypes[i] < 0)
     225           5 :                 eType = OFTString;
     226          45 :             if (bFirstLineIsHeaders &&
     227          15 :                 freexl_get_cell_value(xlshandle, 0, i, &sCellValue) ==
     228          30 :                     FREEXL_OK &&
     229          15 :                 (sCellValue.type == FREEXL_CELL_TEXT ||
     230          15 :                  sCellValue.type == FREEXL_CELL_SST_TEXT))
     231             :             {
     232          30 :                 OGRFieldDefn oField(sCellValue.value.text_value, eType);
     233          15 :                 poFeatureDefn->AddFieldDefn(&oField);
     234             :             }
     235             :             else
     236             :             {
     237           0 :                 OGRFieldDefn oField(CPLSPrintf("Field%d", i + 1), eType);
     238           0 :                 poFeatureDefn->AddFieldDefn(&oField);
     239             :             }
     240             :         }
     241             : 
     242           3 :         CPLFree(paeFieldTypes);
     243             :     }
     244             : 
     245           3 :     ResetReading();
     246             : 
     247           3 :     return poFeatureDefn;
     248             : }
     249             : 
     250             : /************************************************************************/
     251             : /*                          GetFeatureCount()                           */
     252             : /************************************************************************/
     253             : 
     254          13 : GIntBig OGRXLSLayer::GetFeatureCount(int bForce)
     255             : {
     256          13 :     if (m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */)
     257             :     {
     258          11 :         const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
     259          11 :         if (EQUAL(pszXLSHeaders, "DISABLE"))
     260           1 :             return nRows;
     261             : 
     262          10 :         GetLayerDefn();
     263          10 :         return bFirstLineIsHeaders ? nRows - 1 : nRows;
     264             :     }
     265             : 
     266           2 :     return OGRLayer::GetFeatureCount(bForce);
     267             : }
     268             : 
     269             : /************************************************************************/
     270             : /*                         GetNextRawFeature()                          */
     271             : /************************************************************************/
     272             : 
     273          79 : OGRFeature *OGRXLSLayer::GetNextRawFeature()
     274             : {
     275          79 :     GetLayerDefn();
     276             : 
     277          79 :     if (nNextFID == nRows)
     278          18 :         return nullptr;
     279             : 
     280          61 :     const void *xlshandle = poDS->GetXLSHandle();
     281          61 :     if (xlshandle == nullptr)
     282           0 :         return nullptr;
     283             : 
     284          61 :     freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
     285             : 
     286          61 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     287             : 
     288             :     FreeXL_CellValue sCellValue;
     289         366 :     for (unsigned short i = 0;
     290         366 :          i < (unsigned short)poFeatureDefn->GetFieldCount(); i++)
     291             :     {
     292         305 :         if (freexl_get_cell_value(xlshandle, nNextFID, i, &sCellValue) ==
     293             :             FREEXL_OK)
     294             :         {
     295         305 :             switch (sCellValue.type)
     296             :             {
     297          88 :                 case FREEXL_CELL_INT:
     298          88 :                     poFeature->SetField(i, sCellValue.value.int_value);
     299          88 :                     break;
     300          17 :                 case FREEXL_CELL_DOUBLE:
     301          17 :                     poFeature->SetField(i, sCellValue.value.double_value);
     302          17 :                     break;
     303          34 :                 case FREEXL_CELL_TEXT:
     304             :                 case FREEXL_CELL_SST_TEXT:
     305          34 :                     poFeature->SetField(i, sCellValue.value.text_value);
     306          34 :                     break;
     307         105 :                 case FREEXL_CELL_DATE:
     308             :                 case FREEXL_CELL_DATETIME:
     309             :                 case FREEXL_CELL_TIME:
     310         105 :                     poFeature->SetField(i, sCellValue.value.text_value);
     311         105 :                     break;
     312          61 :                 case FREEXL_CELL_NULL:
     313          61 :                     break;
     314           0 :                 default:
     315           0 :                     CPLDebug("XLS", "Unknown cell type = %d", sCellValue.type);
     316           0 :                     break;
     317             :             }
     318             :         }
     319             :     }
     320             : 
     321          61 :     poFeature->SetFID(nNextFID + 1);
     322          61 :     nNextFID++;
     323             : 
     324          61 :     return poFeature;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                           TestCapability()                           */
     329             : /************************************************************************/
     330             : 
     331          32 : int OGRXLSLayer::TestCapability(const char *pszCap)
     332             : 
     333             : {
     334          32 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     335           0 :         return m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */;
     336          32 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     337          10 :         return TRUE;
     338             : 
     339          22 :     return FALSE;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                             GetDataset()                             */
     344             : /************************************************************************/
     345             : 
     346           1 : GDALDataset *OGRXLSLayer::GetDataset()
     347             : {
     348           1 :     return poDS;
     349             : }

Generated by: LCOV version 1.14