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: 2025-09-10 17:48:50 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             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "include_freexl.h"
      14             : 
      15             : #include "ogr_xls.h"
      16             : #include "cpl_conv.h"
      17             : #include "cpl_string.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                            OGRXLSLayer()                             */
      21             : /************************************************************************/
      22             : 
      23           4 : OGRXLSLayer::OGRXLSLayer(OGRXLSDataSource *poDSIn, const char *pszSheetname,
      24           4 :                          int iSheetIn, int nRowsIn, unsigned short nColsIn)
      25           8 :     : poDS(poDSIn), poFeatureDefn(nullptr), pszName(CPLStrdup(pszSheetname)),
      26             :       iSheet(iSheetIn), bFirstLineIsHeaders(false), nRows(nRowsIn),
      27           4 :       nCols(nColsIn), nNextFID(0)
      28             : {
      29           4 :     SetDescription(pszName);
      30           4 : }
      31             : 
      32             : /************************************************************************/
      33             : /*                            ~OGRXLSLayer()                            */
      34             : /************************************************************************/
      35             : 
      36           8 : OGRXLSLayer::~OGRXLSLayer()
      37             : 
      38             : {
      39           4 :     CPLFree(pszName);
      40           4 :     if (poFeatureDefn)
      41           3 :         poFeatureDefn->Release();
      42           8 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                            ResetReading()                            */
      46             : /************************************************************************/
      47             : 
      48          60 : void OGRXLSLayer::ResetReading()
      49             : 
      50             : {
      51          60 :     if (poFeatureDefn != nullptr)
      52             :     {
      53          60 :         nNextFID = bFirstLineIsHeaders ? 1 : 0;
      54             :     }
      55          60 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                          DetectHeaderLine()                          */
      59             : /************************************************************************/
      60             : 
      61           3 : void OGRXLSLayer::DetectHeaderLine(const void *xlshandle)
      62             : 
      63             : {
      64             :     FreeXL_CellValue sCellValue;
      65           3 :     int nCountTextOnSecondLine = 0;
      66           3 :     unsigned short i = 0;  // Used after for.
      67          18 :     for (; i < nCols && nRows >= 2; i++)
      68             :     {
      69          15 :         if (freexl_get_cell_value(xlshandle, 0, i, &sCellValue) == FREEXL_OK)
      70             :         {
      71          15 :             if (sCellValue.type != FREEXL_CELL_TEXT &&
      72          15 :                 sCellValue.type != FREEXL_CELL_SST_TEXT)
      73             :             {
      74             :                 /* If the values in the first line are not text, then it is */
      75             :                 /* not a header line */
      76           0 :                 break;
      77             :             }
      78             :         }
      79          15 :         if (freexl_get_cell_value(xlshandle, 1, i, &sCellValue) == FREEXL_OK)
      80             :         {
      81          15 :             if (sCellValue.type == FREEXL_CELL_TEXT ||
      82          15 :                 sCellValue.type == FREEXL_CELL_SST_TEXT)
      83             :             {
      84             :                 /* If there are only text values on the second line, then we
      85             :                  * cannot */
      86             :                 /* know if it is a header line or just a regular line */
      87           0 :                 nCountTextOnSecondLine++;
      88             :             }
      89             :         }
      90             :     }
      91             : 
      92           3 :     const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
      93           3 :     if (EQUAL(pszXLSHeaders, "FORCE"))
      94           0 :         bFirstLineIsHeaders = true;
      95           3 :     else if (EQUAL(pszXLSHeaders, "DISABLE"))
      96           0 :         bFirstLineIsHeaders = false;
      97           3 :     else if (i == nCols && nCountTextOnSecondLine != nCols)
      98           3 :         bFirstLineIsHeaders = true;
      99           3 : }
     100             : 
     101             : /************************************************************************/
     102             : /*                         DetectColumnTypes()                          */
     103             : /************************************************************************/
     104             : 
     105           2 : void OGRXLSLayer::DetectColumnTypes(const void *xlshandle, int *paeFieldTypes)
     106             : 
     107             : {
     108             :     FreeXL_CellValue sCellValue;
     109           8 :     for (int j = bFirstLineIsHeaders ? 1 : 0; j < nRows; j++)
     110             :     {
     111          36 :         for (unsigned short i = 0; i < nCols; i++)
     112             :         {
     113          30 :             if (freexl_get_cell_value(xlshandle, j, i, &sCellValue) ==
     114             :                 FREEXL_OK)
     115             :             {
     116          30 :                 int eType = paeFieldTypes[i];
     117          30 :                 switch (sCellValue.type)
     118             :                 {
     119           8 :                     case FREEXL_CELL_INT:
     120           8 :                         eType = OFTInteger;
     121           8 :                         break;
     122           2 :                     case FREEXL_CELL_DOUBLE:
     123           2 :                         eType = OFTReal;
     124           2 :                         break;
     125           4 :                     case FREEXL_CELL_TEXT:
     126             :                     case FREEXL_CELL_SST_TEXT:
     127           4 :                         eType = OFTString;
     128           4 :                         break;
     129           6 :                     case FREEXL_CELL_DATE:
     130           6 :                         eType = OFTDate;
     131           6 :                         break;
     132           2 :                     case FREEXL_CELL_DATETIME:
     133           2 :                         eType = OFTDateTime;
     134           2 :                         break;
     135           2 :                     case FREEXL_CELL_TIME:
     136           2 :                         eType = OFTTime;
     137           2 :                         break;
     138           6 :                     case FREEXL_CELL_NULL:
     139           6 :                         break;
     140           0 :                     default:
     141           0 :                         break;
     142             :                 }
     143             : 
     144          30 :                 if (paeFieldTypes[i] < 0)
     145             :                 {
     146          12 :                     paeFieldTypes[i] = eType;
     147             :                 }
     148          18 :                 else if (eType != paeFieldTypes[i])
     149             :                 {
     150           8 :                     if ((paeFieldTypes[i] == OFTDate ||
     151           6 :                          paeFieldTypes[i] == OFTTime ||
     152           8 :                          paeFieldTypes[i] == OFTDateTime) &&
     153           4 :                         (eType == OFTDate || eType == OFTTime ||
     154             :                          eType == OFTDateTime))
     155           4 :                         paeFieldTypes[i] = OFTDateTime;
     156           4 :                     else if (paeFieldTypes[i] == OFTReal && eType == OFTInteger)
     157             :                         /* nothing */;
     158           2 :                     else if (paeFieldTypes[i] == OFTInteger && eType == OFTReal)
     159           2 :                         paeFieldTypes[i] = OFTReal;
     160             :                     else
     161           0 :                         paeFieldTypes[i] = OFTString;
     162             :                 }
     163             :             }
     164             :         }
     165             :     }
     166           2 : }
     167             : 
     168             : /************************************************************************/
     169             : /*                            GetLayerDefn()                            */
     170             : /************************************************************************/
     171             : 
     172         272 : const OGRFeatureDefn *OGRXLSLayer::GetLayerDefn() const
     173             : {
     174         272 :     if (poFeatureDefn)
     175         269 :         return poFeatureDefn;
     176             : 
     177           3 :     poFeatureDefn = new OGRFeatureDefn(pszName);
     178           3 :     poFeatureDefn->Reference();
     179           3 :     poFeatureDefn->SetGeomType(wkbNone);
     180             : 
     181           3 :     const void *xlshandle = poDS->GetXLSHandle();
     182           3 :     if (xlshandle == nullptr)
     183           0 :         return poFeatureDefn;
     184             : 
     185           3 :     freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
     186             : 
     187           3 :     if (nRows > 0)
     188             :     {
     189             : 
     190             :         FreeXL_CellValue sCellValue;
     191             : 
     192           3 :         const_cast<OGRXLSLayer *>(this)->DetectHeaderLine(xlshandle);
     193             : 
     194           3 :         int *paeFieldTypes = (int *)CPLMalloc(nCols * sizeof(int));
     195          18 :         for (unsigned short i = 0; i < nCols; i++)
     196             :         {
     197          15 :             paeFieldTypes[i] = -1;
     198             :         }
     199             : 
     200             :         const char *pszXLSFieldTypes =
     201           3 :             CPLGetConfigOption("OGR_XLS_FIELD_TYPES", "");
     202           3 :         if (!EQUAL(pszXLSFieldTypes, "STRING"))
     203           2 :             const_cast<OGRXLSLayer *>(this)->DetectColumnTypes(xlshandle,
     204             :                                                                paeFieldTypes);
     205             : 
     206          18 :         for (unsigned short i = 0; i < nCols; i++)
     207             :         {
     208          15 :             OGRFieldType eType = (OGRFieldType)paeFieldTypes[i];
     209          15 :             if (paeFieldTypes[i] < 0)
     210           5 :                 eType = OFTString;
     211          45 :             if (bFirstLineIsHeaders &&
     212          15 :                 freexl_get_cell_value(xlshandle, 0, i, &sCellValue) ==
     213          30 :                     FREEXL_OK &&
     214          15 :                 (sCellValue.type == FREEXL_CELL_TEXT ||
     215          15 :                  sCellValue.type == FREEXL_CELL_SST_TEXT))
     216             :             {
     217          30 :                 OGRFieldDefn oField(sCellValue.value.text_value, eType);
     218          15 :                 poFeatureDefn->AddFieldDefn(&oField);
     219             :             }
     220             :             else
     221             :             {
     222           0 :                 OGRFieldDefn oField(CPLSPrintf("Field%d", i + 1), eType);
     223           0 :                 poFeatureDefn->AddFieldDefn(&oField);
     224             :             }
     225             :         }
     226             : 
     227           3 :         CPLFree(paeFieldTypes);
     228             :     }
     229             : 
     230           3 :     const_cast<OGRXLSLayer *>(this)->ResetReading();
     231             : 
     232           3 :     return poFeatureDefn;
     233             : }
     234             : 
     235             : /************************************************************************/
     236             : /*                          GetFeatureCount()                           */
     237             : /************************************************************************/
     238             : 
     239          13 : GIntBig OGRXLSLayer::GetFeatureCount(int bForce)
     240             : {
     241          13 :     if (m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */)
     242             :     {
     243          11 :         const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
     244          11 :         if (EQUAL(pszXLSHeaders, "DISABLE"))
     245           1 :             return nRows;
     246             : 
     247          10 :         GetLayerDefn();
     248          10 :         return bFirstLineIsHeaders ? nRows - 1 : nRows;
     249             :     }
     250             : 
     251           2 :     return OGRLayer::GetFeatureCount(bForce);
     252             : }
     253             : 
     254             : /************************************************************************/
     255             : /*                         GetNextRawFeature()                          */
     256             : /************************************************************************/
     257             : 
     258          86 : OGRFeature *OGRXLSLayer::GetNextRawFeature()
     259             : {
     260          86 :     GetLayerDefn();
     261             : 
     262          86 :     if (nNextFID == nRows)
     263          21 :         return nullptr;
     264             : 
     265          65 :     const void *xlshandle = poDS->GetXLSHandle();
     266          65 :     if (xlshandle == nullptr)
     267           0 :         return nullptr;
     268             : 
     269          65 :     freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
     270             : 
     271          65 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     272             : 
     273             :     FreeXL_CellValue sCellValue;
     274         390 :     for (unsigned short i = 0;
     275         390 :          i < (unsigned short)poFeatureDefn->GetFieldCount(); i++)
     276             :     {
     277         325 :         if (freexl_get_cell_value(xlshandle, nNextFID, i, &sCellValue) ==
     278             :             FREEXL_OK)
     279             :         {
     280         325 :             switch (sCellValue.type)
     281             :             {
     282          94 :                 case FREEXL_CELL_INT:
     283          94 :                     poFeature->SetField(i, sCellValue.value.int_value);
     284          94 :                     break;
     285          18 :                 case FREEXL_CELL_DOUBLE:
     286          18 :                     poFeature->SetField(i, sCellValue.value.double_value);
     287          18 :                     break;
     288          36 :                 case FREEXL_CELL_TEXT:
     289             :                 case FREEXL_CELL_SST_TEXT:
     290          36 :                     poFeature->SetField(i, sCellValue.value.text_value);
     291          36 :                     break;
     292         112 :                 case FREEXL_CELL_DATE:
     293             :                 case FREEXL_CELL_DATETIME:
     294             :                 case FREEXL_CELL_TIME:
     295         112 :                     poFeature->SetField(i, sCellValue.value.text_value);
     296         112 :                     break;
     297          65 :                 case FREEXL_CELL_NULL:
     298          65 :                     break;
     299           0 :                 default:
     300           0 :                     CPLDebug("XLS", "Unknown cell type = %d", sCellValue.type);
     301           0 :                     break;
     302             :             }
     303             :         }
     304             :     }
     305             : 
     306          65 :     poFeature->SetFID(nNextFID + 1);
     307          65 :     nNextFID++;
     308             : 
     309          65 :     return poFeature;
     310             : }
     311             : 
     312             : /************************************************************************/
     313             : /*                           TestCapability()                           */
     314             : /************************************************************************/
     315             : 
     316          33 : int OGRXLSLayer::TestCapability(const char *pszCap) const
     317             : 
     318             : {
     319          33 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     320           0 :         return m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */;
     321          33 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     322          10 :         return TRUE;
     323             : 
     324          23 :     return FALSE;
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                             GetDataset()                             */
     329             : /************************************************************************/
     330             : 
     331           1 : GDALDataset *OGRXLSLayer::GetDataset()
     332             : {
     333           1 :     return poDS;
     334             : }

Generated by: LCOV version 1.14