LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/pds - ogrpdsdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 109 171 63.7 %
Date: 2024-04-29 15:10:10 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  PDS Translator
       4             :  * Purpose:  Implements OGRPDSDataSource class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2011, 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 "cpl_conv.h"
      30             : #include "cpl_string.h"
      31             : #include "ogr_pds.h"
      32             : 
      33             : using namespace OGRPDS;
      34             : 
      35             : /************************************************************************/
      36             : /*                           OGRPDSDataSource()                         */
      37             : /************************************************************************/
      38             : 
      39           2 : OGRPDSDataSource::OGRPDSDataSource()
      40           2 :     : pszName(nullptr), papoLayers(nullptr), nLayers(0)
      41             : {
      42           2 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                        ~OGRPDSDataSource()                           */
      46             : /************************************************************************/
      47             : 
      48           4 : OGRPDSDataSource::~OGRPDSDataSource()
      49             : 
      50             : {
      51           4 :     for (int i = 0; i < nLayers; i++)
      52           2 :         delete papoLayers[i];
      53           2 :     CPLFree(papoLayers);
      54             : 
      55           2 :     CPLFree(pszName);
      56           4 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                           TestCapability()                           */
      60             : /************************************************************************/
      61             : 
      62           0 : int OGRPDSDataSource::TestCapability(const char * /* pszCap */)
      63             : {
      64           0 :     return FALSE;
      65             : }
      66             : 
      67             : /************************************************************************/
      68             : /*                              GetLayer()                              */
      69             : /************************************************************************/
      70             : 
      71           2 : OGRLayer *OGRPDSDataSource::GetLayer(int iLayer)
      72             : 
      73             : {
      74           2 :     if (iLayer < 0 || iLayer >= nLayers)
      75           0 :         return nullptr;
      76             : 
      77           2 :     return papoLayers[iLayer];
      78             : }
      79             : 
      80             : /************************************************************************/
      81             : /*                          GetKeywordSub()                             */
      82             : /************************************************************************/
      83             : 
      84           2 : const char *OGRPDSDataSource::GetKeywordSub(const char *pszPath, int iSubscript,
      85             :                                             const char *pszDefault)
      86             : 
      87             : {
      88           2 :     const char *pszResult = oKeywords.GetKeyword(pszPath, nullptr);
      89             : 
      90           2 :     if (pszResult == nullptr)
      91           0 :         return pszDefault;
      92             : 
      93           2 :     if (pszResult[0] != '(')
      94           0 :         return pszDefault;
      95             : 
      96             :     char **papszTokens =
      97           2 :         CSLTokenizeString2(pszResult, "(,)", CSLT_HONOURSTRINGS);
      98             : 
      99           2 :     if (iSubscript <= CSLCount(papszTokens))
     100             :     {
     101           2 :         osTempResult = papszTokens[iSubscript - 1];
     102           2 :         CSLDestroy(papszTokens);
     103           2 :         return osTempResult.c_str();
     104             :     }
     105             : 
     106           0 :     CSLDestroy(papszTokens);
     107           0 :     return pszDefault;
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                            CleanString()                             */
     112             : /*                                                                      */
     113             : /* Removes single or double quotes, and converts spaces to underscores. */
     114             : /* The change is made in-place to CPLString.                            */
     115             : /************************************************************************/
     116             : 
     117         126 : void OGRPDSDataSource::CleanString(CPLString &osInput)
     118             : 
     119             : {
     120         252 :     if ((osInput.size() < 2) ||
     121         126 :         ((osInput.at(0) != '"' || osInput.at(osInput.size() - 1) != '"') &&
     122          65 :          (osInput.at(0) != '\'' || osInput.at(osInput.size() - 1) != '\'')))
     123          65 :         return;
     124             : 
     125          61 :     char *pszWrk = CPLStrdup(osInput.c_str() + 1);
     126             : 
     127          61 :     pszWrk[strlen(pszWrk) - 1] = '\0';
     128             : 
     129         956 :     for (int i = 0; pszWrk[i] != '\0'; i++)
     130             :     {
     131         895 :         if (pszWrk[i] == ' ')
     132           0 :             pszWrk[i] = '_';
     133             :     }
     134             : 
     135          61 :     osInput = pszWrk;
     136          61 :     CPLFree(pszWrk);
     137             : }
     138             : 
     139             : /************************************************************************/
     140             : /*                           LoadTable()                                */
     141             : /************************************************************************/
     142             : 
     143           8 : static CPLString MakeAttr(CPLString os1, CPLString os2)
     144             : {
     145          16 :     return os1 + "." + os2;
     146             : }
     147             : 
     148           2 : bool OGRPDSDataSource::LoadTable(const char *pszFilename, int nRecordSize,
     149             :                                  CPLString osTableID)
     150             : {
     151           4 :     CPLString osTableFilename;
     152           2 :     int nStartBytes = 0;
     153             : 
     154           4 :     CPLString osTableLink = "^";
     155           2 :     osTableLink += osTableID;
     156             : 
     157           4 :     CPLString osTable = oKeywords.GetKeyword(osTableLink, "");
     158           2 :     if (osTable[0] == '(')
     159             :     {
     160           1 :         osTableFilename = GetKeywordSub(osTableLink, 1, "");
     161           1 :         CPLString osStartRecord = GetKeywordSub(osTableLink, 2, "");
     162           1 :         nStartBytes = atoi(osStartRecord.c_str());
     163           1 :         if (nStartBytes <= 0 ||
     164           1 :             ((nRecordSize > 0 && nStartBytes > INT_MAX / nRecordSize)))
     165             :         {
     166           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Invalid StartBytes value");
     167           0 :             return false;
     168             :         }
     169           1 :         nStartBytes--;
     170           1 :         nStartBytes *= nRecordSize;
     171           1 :         if (osTableFilename.empty() || osStartRecord.empty() || nStartBytes < 0)
     172             :         {
     173           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Cannot parse %s line",
     174             :                      osTableLink.c_str());
     175           0 :             return false;
     176             :         }
     177           1 :         CPLString osTPath = CPLGetPath(pszFilename);
     178           1 :         CleanString(osTableFilename);
     179           1 :         osTableFilename = CPLFormCIFilename(osTPath, osTableFilename, nullptr);
     180             :     }
     181             :     else
     182             :     {
     183           1 :         osTableFilename = oKeywords.GetKeyword(osTableLink, "");
     184           1 :         if (!osTableFilename.empty() && osTableFilename[0] >= '0' &&
     185           0 :             osTableFilename[0] <= '9')
     186             :         {
     187           0 :             nStartBytes = atoi(osTableFilename.c_str());
     188           0 :             if (nStartBytes <= 1)
     189             :             {
     190           0 :                 CPLError(CE_Failure, CPLE_NotSupported, "Cannot parse %s line",
     191             :                          osTableFilename.c_str());
     192           0 :                 return false;
     193             :             }
     194           0 :             nStartBytes = nStartBytes - 1;
     195           0 :             if (strstr(osTableFilename.c_str(), "<BYTES>") == nullptr)
     196             :             {
     197           0 :                 if (nRecordSize > 0 && nStartBytes > INT_MAX / nRecordSize)
     198             :                 {
     199           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
     200             :                              "Too big StartBytes value");
     201           0 :                     return false;
     202             :                 }
     203           0 :                 nStartBytes *= nRecordSize;
     204             :             }
     205           0 :             osTableFilename = pszFilename;
     206             :         }
     207             :         else
     208             :         {
     209           1 :             CPLString osTPath = CPLGetPath(pszFilename);
     210           1 :             CleanString(osTableFilename);
     211             :             osTableFilename =
     212           1 :                 CPLFormCIFilename(osTPath, osTableFilename, nullptr);
     213           1 :             nStartBytes = 0;
     214             :         }
     215             :     }
     216             : 
     217             :     CPLString osTableName =
     218           6 :         oKeywords.GetKeyword(MakeAttr(osTableID, "NAME"), "");
     219           2 :     if (osTableName.empty())
     220             :     {
     221           1 :         if (GetLayerByName(osTableID.c_str()) == nullptr)
     222           1 :             osTableName = osTableID;
     223             :         else
     224           0 :             osTableName = CPLSPrintf("Layer_%d", nLayers + 1);
     225             :     }
     226           2 :     CleanString(osTableName);
     227             :     CPLString osTableInterchangeFormat =
     228           6 :         oKeywords.GetKeyword(MakeAttr(osTableID, "INTERCHANGE_FORMAT"), "");
     229             :     CPLString osTableRows =
     230           6 :         oKeywords.GetKeyword(MakeAttr(osTableID, "ROWS"), "");
     231           2 :     const int nRecords = atoi(osTableRows);
     232           2 :     if (osTableInterchangeFormat.empty() || osTableRows.empty() || nRecords < 0)
     233             :     {
     234           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     235             :                  "One of TABLE.INTERCHANGE_FORMAT or TABLE.ROWS is missing");
     236           0 :         return false;
     237             :     }
     238             : 
     239           2 :     CleanString(osTableInterchangeFormat);
     240           3 :     if (osTableInterchangeFormat.compare("ASCII") != 0 &&
     241           1 :         osTableInterchangeFormat.compare("BINARY") != 0)
     242             :     {
     243           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     244             :                  "Only INTERCHANGE_FORMAT=ASCII or BINARY is supported");
     245           0 :         return false;
     246             :     }
     247             : 
     248           2 :     VSILFILE *fp = VSIFOpenL(osTableFilename, "rb");
     249           2 :     if (fp == nullptr)
     250             :     {
     251           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s",
     252             :                  osTableFilename.c_str());
     253           0 :         return false;
     254             :     }
     255             : 
     256             :     CPLString osTableStructure =
     257           6 :         oKeywords.GetKeyword(MakeAttr(osTableID, "^STRUCTURE"), "");
     258           2 :     if (!osTableStructure.empty())
     259             :     {
     260           2 :         CPLString osTPath = CPLGetPath(pszFilename);
     261           2 :         CleanString(osTableStructure);
     262             :         osTableStructure =
     263           2 :             CPLFormCIFilename(osTPath, osTableStructure, nullptr);
     264             :     }
     265             : 
     266           2 :     GByte *pabyRecord = (GByte *)VSI_MALLOC_VERBOSE(nRecordSize + 1);
     267           2 :     if (pabyRecord == nullptr)
     268             :     {
     269           0 :         VSIFCloseL(fp);
     270           0 :         return false;
     271             :     }
     272           2 :     pabyRecord[nRecordSize] = 0;
     273             : 
     274           2 :     papoLayers = static_cast<OGRLayer **>(
     275           2 :         CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer *)));
     276           4 :     papoLayers[nLayers] = new OGRPDSLayer(
     277             :         osTableID, osTableName, fp, pszFilename, osTableStructure, nRecords,
     278             :         nStartBytes, nRecordSize, pabyRecord,
     279           4 :         osTableInterchangeFormat.compare("ASCII") == 0);
     280           2 :     nLayers++;
     281             : 
     282           2 :     return true;
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                                Open()                                */
     287             : /************************************************************************/
     288             : 
     289           2 : int OGRPDSDataSource::Open(const char *pszFilename)
     290             : 
     291             : {
     292           2 :     pszName = CPLStrdup(pszFilename);
     293             : 
     294             :     // --------------------------------------------------------------------
     295             :     //      Does this appear to be a .PDS table file?
     296             :     // --------------------------------------------------------------------
     297             : 
     298           2 :     VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
     299           2 :     if (fp == nullptr)
     300           0 :         return FALSE;
     301             : 
     302             :     char szBuffer[512];
     303             :     int nbRead =
     304           2 :         static_cast<int>(VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp));
     305           2 :     szBuffer[nbRead] = '\0';
     306             : 
     307           2 :     const char *pszPos = strstr(szBuffer, "PDS_VERSION_ID");
     308           2 :     const bool bIsPDS = pszPos != nullptr;
     309             : 
     310           2 :     if (!bIsPDS)
     311             :     {
     312           0 :         VSIFCloseL(fp);
     313           0 :         return FALSE;
     314             :     }
     315             : 
     316           2 :     if (!oKeywords.Ingest(fp, static_cast<int>(pszPos - szBuffer)))
     317             :     {
     318           0 :         VSIFCloseL(fp);
     319           0 :         return FALSE;
     320             :     }
     321             : 
     322           2 :     VSIFCloseL(fp);
     323           4 :     CPLString osRecordType = oKeywords.GetKeyword("RECORD_TYPE", "");
     324           4 :     CPLString osFileRecords = oKeywords.GetKeyword("FILE_RECORDS", "");
     325           4 :     CPLString osRecordBytes = oKeywords.GetKeyword("RECORD_BYTES", "");
     326           2 :     int nRecordSize = atoi(osRecordBytes);
     327           6 :     if (osRecordType.empty() || osFileRecords.empty() ||
     328           6 :         osRecordBytes.empty() || nRecordSize <= 0 ||
     329             :         nRecordSize > 10 * 1024 * 1024)
     330             :     {
     331           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     332             :                  "One of RECORD_TYPE, FILE_RECORDS or RECORD_BYTES is missing");
     333           0 :         return FALSE;
     334             :     }
     335           2 :     CleanString(osRecordType);
     336           2 :     if (osRecordType.compare("FIXED_LENGTH") != 0)
     337             :     {
     338           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     339             :                  "Only RECORD_TYPE=FIXED_LENGTH is supported");
     340           0 :         return FALSE;
     341             :     }
     342             : 
     343           4 :     CPLString osTable = oKeywords.GetKeyword("^TABLE", "");
     344           2 :     if (!osTable.empty())
     345             :     {
     346           2 :         LoadTable(pszFilename, nRecordSize, "TABLE");
     347             :     }
     348             :     else
     349             :     {
     350           0 :         fp = VSIFOpenL(pszFilename, "rb");
     351           0 :         if (fp == nullptr)
     352           0 :             return FALSE;
     353             : 
     354             :         // To avoid performance issues with datasets generated by oss-fuzz
     355           0 :         int nErrors = 0;
     356           0 :         while (nErrors < 10)
     357             :         {
     358           0 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     359           0 :             const char *pszLine = CPLReadLine2L(fp, 256, nullptr);
     360           0 :             CPLPopErrorHandler();
     361           0 :             CPLErrorReset();
     362           0 :             if (pszLine == nullptr)
     363           0 :                 break;
     364             :             char **papszTokens =
     365           0 :                 CSLTokenizeString2(pszLine, " =", CSLT_HONOURSTRINGS);
     366           0 :             int nTokens = CSLCount(papszTokens);
     367           0 :             if (nTokens == 2 && papszTokens[0][0] == '^' &&
     368           0 :                 strstr(papszTokens[0], "TABLE") != nullptr)
     369             :             {
     370           0 :                 if (!LoadTable(pszFilename, nRecordSize, papszTokens[0] + 1))
     371             :                 {
     372           0 :                     nErrors++;
     373             :                 }
     374             :             }
     375           0 :             CSLDestroy(papszTokens);
     376           0 :             papszTokens = nullptr;
     377             :         }
     378           0 :         VSIFCloseL(fp);
     379             :     }
     380             : 
     381           2 :     return nLayers != 0;
     382             : }

Generated by: LCOV version 1.14