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-11-21 22:18:42 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          58 : void OGRXLSLayer::ResetReading()
      49             : 
      50             : {
      51          58 :     if (poFeatureDefn != nullptr)
      52             :     {
      53          58 :         nNextFID = bFirstLineIsHeaders ? 1 : 0;
      54             :     }
      55          58 : }
      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         265 : OGRFeatureDefn *OGRXLSLayer::GetLayerDefn()
     173             : {
     174         265 :     if (poFeatureDefn)
     175         262 :         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 :         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 :             DetectColumnTypes(xlshandle, paeFieldTypes);
     204             : 
     205          18 :         for (unsigned short i = 0; i < nCols; i++)
     206             :         {
     207          15 :             OGRFieldType eType = (OGRFieldType)paeFieldTypes[i];
     208          15 :             if (paeFieldTypes[i] < 0)
     209           5 :                 eType = OFTString;
     210          45 :             if (bFirstLineIsHeaders &&
     211          15 :                 freexl_get_cell_value(xlshandle, 0, i, &sCellValue) ==
     212          30 :                     FREEXL_OK &&
     213          15 :                 (sCellValue.type == FREEXL_CELL_TEXT ||
     214          15 :                  sCellValue.type == FREEXL_CELL_SST_TEXT))
     215             :             {
     216          30 :                 OGRFieldDefn oField(sCellValue.value.text_value, eType);
     217          15 :                 poFeatureDefn->AddFieldDefn(&oField);
     218             :             }
     219             :             else
     220             :             {
     221           0 :                 OGRFieldDefn oField(CPLSPrintf("Field%d", i + 1), eType);
     222           0 :                 poFeatureDefn->AddFieldDefn(&oField);
     223             :             }
     224             :         }
     225             : 
     226           3 :         CPLFree(paeFieldTypes);
     227             :     }
     228             : 
     229           3 :     ResetReading();
     230             : 
     231           3 :     return poFeatureDefn;
     232             : }
     233             : 
     234             : /************************************************************************/
     235             : /*                          GetFeatureCount()                           */
     236             : /************************************************************************/
     237             : 
     238          13 : GIntBig OGRXLSLayer::GetFeatureCount(int bForce)
     239             : {
     240          13 :     if (m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */)
     241             :     {
     242          11 :         const char *pszXLSHeaders = CPLGetConfigOption("OGR_XLS_HEADERS", "");
     243          11 :         if (EQUAL(pszXLSHeaders, "DISABLE"))
     244           1 :             return nRows;
     245             : 
     246          10 :         GetLayerDefn();
     247          10 :         return bFirstLineIsHeaders ? nRows - 1 : nRows;
     248             :     }
     249             : 
     250           2 :     return OGRLayer::GetFeatureCount(bForce);
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                         GetNextRawFeature()                          */
     255             : /************************************************************************/
     256             : 
     257          79 : OGRFeature *OGRXLSLayer::GetNextRawFeature()
     258             : {
     259          79 :     GetLayerDefn();
     260             : 
     261          79 :     if (nNextFID == nRows)
     262          18 :         return nullptr;
     263             : 
     264          61 :     const void *xlshandle = poDS->GetXLSHandle();
     265          61 :     if (xlshandle == nullptr)
     266           0 :         return nullptr;
     267             : 
     268          61 :     freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
     269             : 
     270          61 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     271             : 
     272             :     FreeXL_CellValue sCellValue;
     273         366 :     for (unsigned short i = 0;
     274         366 :          i < (unsigned short)poFeatureDefn->GetFieldCount(); i++)
     275             :     {
     276         305 :         if (freexl_get_cell_value(xlshandle, nNextFID, i, &sCellValue) ==
     277             :             FREEXL_OK)
     278             :         {
     279         305 :             switch (sCellValue.type)
     280             :             {
     281          88 :                 case FREEXL_CELL_INT:
     282          88 :                     poFeature->SetField(i, sCellValue.value.int_value);
     283          88 :                     break;
     284          17 :                 case FREEXL_CELL_DOUBLE:
     285          17 :                     poFeature->SetField(i, sCellValue.value.double_value);
     286          17 :                     break;
     287          34 :                 case FREEXL_CELL_TEXT:
     288             :                 case FREEXL_CELL_SST_TEXT:
     289          34 :                     poFeature->SetField(i, sCellValue.value.text_value);
     290          34 :                     break;
     291         105 :                 case FREEXL_CELL_DATE:
     292             :                 case FREEXL_CELL_DATETIME:
     293             :                 case FREEXL_CELL_TIME:
     294         105 :                     poFeature->SetField(i, sCellValue.value.text_value);
     295         105 :                     break;
     296          61 :                 case FREEXL_CELL_NULL:
     297          61 :                     break;
     298           0 :                 default:
     299           0 :                     CPLDebug("XLS", "Unknown cell type = %d", sCellValue.type);
     300           0 :                     break;
     301             :             }
     302             :         }
     303             :     }
     304             : 
     305          61 :     poFeature->SetFID(nNextFID + 1);
     306          61 :     nNextFID++;
     307             : 
     308          61 :     return poFeature;
     309             : }
     310             : 
     311             : /************************************************************************/
     312             : /*                           TestCapability()                           */
     313             : /************************************************************************/
     314             : 
     315          32 : int OGRXLSLayer::TestCapability(const char *pszCap)
     316             : 
     317             : {
     318          32 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     319           0 :         return m_poAttrQuery == nullptr /* && m_poFilterGeom == NULL */;
     320          32 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     321          10 :         return TRUE;
     322             : 
     323          22 :     return FALSE;
     324             : }
     325             : 
     326             : /************************************************************************/
     327             : /*                             GetDataset()                             */
     328             : /************************************************************************/
     329             : 
     330           1 : GDALDataset *OGRXLSLayer::GetDataset()
     331             : {
     332           1 :     return poDS;
     333             : }

Generated by: LCOV version 1.14