LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/s57 - s57classregistrar.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 159 221 71.9 %
Date: 2024-04-28 23:18:46 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  S-57 Translator
       4             :  * Purpose:  Implements S57ClassRegistrar class for keeping track of
       5             :  *           information on S57 object classes.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_conv.h"
      32             : #include "cpl_string.h"
      33             : #include "s57.h"
      34             : 
      35             : #ifdef S57_BUILTIN_CLASSES
      36             : #include "s57tables.h"
      37             : #endif
      38             : 
      39             : /************************************************************************/
      40             : /*                         S57ClassRegistrar()                          */
      41             : /************************************************************************/
      42             : 
      43           3 : S57ClassRegistrar::S57ClassRegistrar()
      44           3 :     : nClasses(0), nAttrCount(0), papszNextLine(nullptr)
      45             : {
      46           3 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                         ~S57ClassRegistrar()                         */
      50             : /************************************************************************/
      51             : 
      52           2 : S57ClassRegistrar::~S57ClassRegistrar()
      53             : 
      54             : {
      55           2 :     nClasses = 0;
      56       80004 :     for (size_t i = 0; i < aoAttrInfos.size(); i++)
      57       80002 :         delete aoAttrInfos[i];
      58           2 :     aoAttrInfos.resize(0);
      59           2 :     nAttrCount = 0;
      60           2 : }
      61             : 
      62             : /************************************************************************/
      63             : /*                        S57ClassContentExplorer()                     */
      64             : /************************************************************************/
      65             : 
      66          55 : S57ClassContentExplorer::S57ClassContentExplorer(
      67          55 :     S57ClassRegistrar *poRegistrarIn)
      68             :     : poRegistrar(poRegistrarIn), papapszClassesFields(nullptr),
      69          55 :       iCurrentClass(-1), papszCurrentFields(nullptr), papszTempResult(nullptr)
      70             : {
      71          55 : }
      72             : 
      73             : /************************************************************************/
      74             : /*                        ~S57ClassContentExplorer()                    */
      75             : /************************************************************************/
      76             : 
      77         110 : S57ClassContentExplorer::~S57ClassContentExplorer()
      78             : {
      79          55 :     CSLDestroy(papszTempResult);
      80             : 
      81          55 :     if (papapszClassesFields != nullptr)
      82             :     {
      83       15675 :         for (int i = 0; i < poRegistrar->nClasses; i++)
      84       15620 :             CSLDestroy(papapszClassesFields[i]);
      85          55 :         CPLFree(papapszClassesFields);
      86             :     }
      87          55 : }
      88             : 
      89             : /************************************************************************/
      90             : /*                              FindFile()                              */
      91             : /************************************************************************/
      92             : 
      93           6 : bool S57ClassRegistrar::FindFile(const char *pszTarget,
      94             :                                  const char *pszDirectory, bool bReportErr,
      95             :                                  VSILFILE **pfp)
      96             : 
      97             : {
      98           6 :     const char *pszFilename = nullptr;
      99             : 
     100           6 :     if (pszDirectory == nullptr)
     101             :     {
     102           6 :         pszFilename = CPLFindFile("s57", pszTarget);
     103           6 :         if (pszFilename == nullptr)
     104           0 :             pszFilename = pszTarget;
     105             :     }
     106             :     else
     107             :     {
     108           0 :         pszFilename = CPLFormFilename(pszDirectory, pszTarget, nullptr);
     109             :     }
     110             : 
     111           6 :     *pfp = VSIFOpenL(pszFilename, "rb");
     112             : 
     113             : #ifdef S57_BUILTIN_CLASSES
     114             :     if (*pfp == NULL)
     115             :     {
     116             :         if (EQUAL(pszTarget, "s57objectclasses.csv"))
     117             :             papszNextLine = gpapszS57Classes;
     118             :         else
     119             :             papszNextLine = gpapszS57attributes;
     120             :     }
     121             : #else
     122           6 :     if (*pfp == nullptr)
     123             :     {
     124           0 :         if (bReportErr)
     125           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open %s.\n",
     126             :                      pszFilename);
     127           0 :         return FALSE;
     128             :     }
     129             : #endif
     130             : 
     131           6 :     return TRUE;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                              ReadLine()                              */
     136             : /*                                                                      */
     137             : /*      Read a line from the provided file, or from the "built-in"      */
     138             : /*      configuration file line list if the file is NULL.               */
     139             : /************************************************************************/
     140             : 
     141        2319 : const char *S57ClassRegistrar::ReadLine(VSILFILE *fp)
     142             : 
     143             : {
     144        2319 :     if (fp != nullptr)
     145        2319 :         return CPLReadLineL(fp);
     146             : 
     147           0 :     if (papszNextLine == nullptr)
     148           0 :         return nullptr;
     149             : 
     150           0 :     if (*papszNextLine == nullptr)
     151             :     {
     152           0 :         papszNextLine = nullptr;
     153           0 :         return nullptr;
     154             :     }
     155             : 
     156           0 :     return *(papszNextLine++);
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                              LoadInfo()                              */
     161             : /************************************************************************/
     162             : 
     163           3 : bool S57ClassRegistrar::LoadInfo(const char *pszDirectory,
     164             :                                  const char *pszProfile, bool bReportErr)
     165             : 
     166             : {
     167           3 :     if (pszDirectory == nullptr)
     168           3 :         pszDirectory = CPLGetConfigOption("S57_CSV", nullptr);
     169             : 
     170             :     /* ==================================================================== */
     171             :     /*      Read the s57objectclasses file.                                 */
     172             :     /* ==================================================================== */
     173           3 :     if (pszProfile == nullptr)
     174           3 :         pszProfile = CPLGetConfigOption("S57_PROFILE", "");
     175             : 
     176             :     char szTargetFile[1024];  // TODO: Get this off of the stack.
     177           3 :     if (EQUAL(pszProfile, "Additional_Military_Layers"))
     178             :     {
     179             :         // Has been suppressed in GDAL data/
     180           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57objectclasses_%s.csv",
     181             :                  "aml");
     182             :     }
     183           3 :     else if (EQUAL(pszProfile, "Inland_Waterways"))
     184             :     {
     185             :         // Has been suppressed in GDAL data/
     186           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57objectclasses_%s.csv",
     187             :                  "iw");
     188             :     }
     189           3 :     else if (strlen(pszProfile) > 0)
     190             :     {
     191           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57objectclasses_%s.csv",
     192             :                  pszProfile);
     193             :     }
     194             :     else
     195             :     {
     196           3 :         strcpy(szTargetFile, "s57objectclasses.csv");
     197             :     }
     198             : 
     199           3 :     VSILFILE *fp = nullptr;
     200           3 :     if (!FindFile(szTargetFile, pszDirectory, bReportErr, &fp))
     201             :     {
     202           0 :         if (EQUAL(pszProfile, "Additional_Military_Layers") ||
     203           0 :             EQUAL(pszProfile, "Inland_Waterways"))
     204             :         {
     205           0 :             strcpy(szTargetFile, "s57objectclasses.csv");
     206           0 :             if (!FindFile(szTargetFile, pszDirectory, bReportErr, &fp))
     207           0 :                 return false;
     208             :         }
     209           0 :         return false;
     210             :     }
     211             : 
     212             :     /* -------------------------------------------------------------------- */
     213             :     /*      Skip the line defining the column titles.                       */
     214             :     /* -------------------------------------------------------------------- */
     215           3 :     const char *pszLine = ReadLine(fp);
     216             : 
     217           3 :     if (!EQUAL(pszLine,
     218             :                "\"Code\",\"ObjectClass\",\"Acronym\",\"Attribute_A\","
     219             :                "\"Attribute_B\",\"Attribute_C\",\"Class\",\"Primitives\""))
     220             :     {
     221           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     222             :                  "s57objectclasses columns don't match expected format!\n");
     223           0 :         if (fp != nullptr)
     224           0 :             VSIFCloseL(fp);
     225           0 :         return false;
     226             :     }
     227             : 
     228             :     /* -------------------------------------------------------------------- */
     229             :     /*      Read and form string list.                                      */
     230             :     /* -------------------------------------------------------------------- */
     231           3 :     apszClassesInfo.Clear();
     232         861 :     while ((pszLine = ReadLine(fp)) != nullptr)
     233             :     {
     234         858 :         if (strstr(pszLine, "###") != nullptr)
     235           6 :             continue;
     236         852 :         apszClassesInfo.AddString(pszLine);
     237             :     }
     238             : 
     239             :     /* -------------------------------------------------------------------- */
     240             :     /*      Cleanup, and establish state.                                   */
     241             :     /* -------------------------------------------------------------------- */
     242           3 :     if (fp != nullptr)
     243           3 :         VSIFCloseL(fp);
     244             : 
     245           3 :     nClasses = apszClassesInfo.size();
     246           3 :     if (nClasses == 0)
     247           0 :         return false;
     248             : 
     249             :     /* ==================================================================== */
     250             :     /*      Read the attributes list.                                       */
     251             :     /* ==================================================================== */
     252             : 
     253           3 :     if (EQUAL(pszProfile, "Additional_Military_Layers"))
     254             :     {
     255             :         // Has been suppressed in GDAL data/
     256           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57attributes_%s.csv",
     257             :                  "aml");
     258             :     }
     259           3 :     else if (EQUAL(pszProfile, "Inland_Waterways"))
     260             :     {
     261             :         // Has been suppressed in GDAL data/
     262           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57attributes_%s.csv",
     263             :                  "iw");
     264             :     }
     265           3 :     else if (strlen(pszProfile) > 0)
     266             :     {
     267           0 :         snprintf(szTargetFile, sizeof(szTargetFile), "s57attributes_%s.csv",
     268             :                  pszProfile);
     269             :     }
     270             :     else
     271             :     {
     272           3 :         strcpy(szTargetFile, "s57attributes.csv");
     273             :     }
     274             : 
     275           3 :     if (!FindFile(szTargetFile, pszDirectory, bReportErr, &fp))
     276             :     {
     277           0 :         if (EQUAL(pszProfile, "Additional_Military_Layers") ||
     278           0 :             EQUAL(pszProfile, "Inland_Waterways"))
     279             :         {
     280           0 :             strcpy(szTargetFile, "s57attributes.csv");
     281           0 :             if (!FindFile(szTargetFile, pszDirectory, bReportErr, &fp))
     282           0 :                 return false;
     283             :         }
     284           0 :         return false;
     285             :     }
     286             : 
     287             :     /* -------------------------------------------------------------------- */
     288             :     /*      Skip the line defining the column titles.                       */
     289             :     /* -------------------------------------------------------------------- */
     290           3 :     pszLine = ReadLine(fp);
     291             : 
     292           3 :     if (!EQUAL(
     293             :             pszLine,
     294             :             "\"Code\",\"Attribute\",\"Acronym\",\"Attributetype\",\"Class\""))
     295             :     {
     296           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     297             :                  "s57attributes columns don't match expected format!\n");
     298           0 :         if (fp != nullptr)
     299           0 :             VSIFCloseL(fp);
     300           0 :         return false;
     301             :     }
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Read and form string list.                                      */
     305             :     /* -------------------------------------------------------------------- */
     306        1452 :     while ((pszLine = ReadLine(fp)) != nullptr)
     307             :     {
     308        1449 :         if (strstr(pszLine, "###") != nullptr)
     309           9 :             continue;
     310             : 
     311        1440 :         char **papszTokens = CSLTokenizeStringComplex(pszLine, ",", TRUE, TRUE);
     312             : 
     313        1440 :         if (CSLCount(papszTokens) < 5)
     314             :         {
     315           0 :             CSLDestroy(papszTokens);
     316           0 :             continue;
     317             :         }
     318             : 
     319        1440 :         int iAttr = atoi(papszTokens[0]);
     320        1440 :         if (iAttr >= (int)aoAttrInfos.size())
     321        1440 :             aoAttrInfos.resize(iAttr + 1);
     322             : 
     323        1440 :         if (iAttr < 0 || aoAttrInfos[iAttr] != nullptr)
     324             :         {
     325           0 :             CPLDebug("S57", "Duplicate/corrupt definition for attribute %d:%s",
     326           0 :                      iAttr, papszTokens[2]);
     327           0 :             CSLDestroy(papszTokens);
     328           0 :             continue;
     329             :         }
     330             : 
     331        1440 :         aoAttrInfos[iAttr] = new S57AttrInfo();
     332        1440 :         aoAttrInfos[iAttr]->osName = papszTokens[1];
     333        1440 :         aoAttrInfos[iAttr]->osAcronym = papszTokens[2];
     334        1440 :         aoAttrInfos[iAttr]->chType = papszTokens[3][0];
     335        1440 :         aoAttrInfos[iAttr]->chClass = papszTokens[4][0];
     336        1440 :         anAttrIndex.push_back(iAttr);
     337        1440 :         CSLDestroy(papszTokens);
     338             :     }
     339             : 
     340           3 :     if (fp != nullptr)
     341           3 :         VSIFCloseL(fp);
     342             : 
     343           3 :     nAttrCount = static_cast<int>(anAttrIndex.size());
     344             : 
     345             :     /* -------------------------------------------------------------------- */
     346             :     /*      Sort index by acronym.                                          */
     347             :     /* -------------------------------------------------------------------- */
     348           3 :     bool bModified = false;
     349        1050 :     do
     350             :     {
     351        1050 :         bModified = false;
     352      504000 :         for (int iAttr = 0; iAttr < nAttrCount - 1; iAttr++)
     353             :         {
     354      502950 :             if (strcmp(aoAttrInfos[anAttrIndex[iAttr]]->osAcronym,
     355     1005900 :                        aoAttrInfos[anAttrIndex[iAttr + 1]]->osAcronym) > 0)
     356             :             {
     357       51513 :                 int nTemp = anAttrIndex[iAttr];
     358       51513 :                 anAttrIndex[iAttr] = anAttrIndex[iAttr + 1];
     359       51513 :                 anAttrIndex[iAttr + 1] = nTemp;
     360       51513 :                 bModified = true;
     361             :             }
     362             :         }
     363             :     } while (bModified);
     364             : 
     365           3 :     return true;
     366             : }
     367             : 
     368             : /************************************************************************/
     369             : /*                         SelectClassByIndex()                         */
     370             : /************************************************************************/
     371             : 
     372       46851 : bool S57ClassContentExplorer::SelectClassByIndex(int nNewIndex)
     373             : 
     374             : {
     375       46851 :     if (nNewIndex < 0 || nNewIndex >= poRegistrar->nClasses)
     376          18 :         return false;
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Do we have our cache of class information field lists?          */
     380             :     /* -------------------------------------------------------------------- */
     381       46833 :     if (papapszClassesFields == nullptr)
     382             :     {
     383          55 :         papapszClassesFields =
     384          55 :             (char ***)CPLCalloc(sizeof(void *), poRegistrar->nClasses);
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      Has this info been parsed yet?                                  */
     389             :     /* -------------------------------------------------------------------- */
     390       46833 :     if (papapszClassesFields[nNewIndex] == nullptr)
     391       15620 :         papapszClassesFields[nNewIndex] = CSLTokenizeStringComplex(
     392       15620 :             poRegistrar->apszClassesInfo[nNewIndex], ",", TRUE, TRUE);
     393             : 
     394       46833 :     papszCurrentFields = papapszClassesFields[nNewIndex];
     395             : 
     396       46833 :     iCurrentClass = nNewIndex;
     397             : 
     398       46833 :     return true;
     399             : }
     400             : 
     401             : /************************************************************************/
     402             : /*                             SelectClass()                            */
     403             : /************************************************************************/
     404             : 
     405        5281 : bool S57ClassContentExplorer::SelectClass(int nOBJL)
     406             : 
     407             : {
     408      748695 :     for (int i = 0; i < poRegistrar->nClasses; i++)
     409             :     {
     410      748695 :         if (atoi(poRegistrar->apszClassesInfo[i]) == nOBJL)
     411        5281 :             return SelectClassByIndex(i);
     412             :     }
     413             : 
     414           0 :     return FALSE;
     415             : }
     416             : 
     417             : /************************************************************************/
     418             : /*                            SelectClass()                             */
     419             : /************************************************************************/
     420             : 
     421         260 : bool S57ClassContentExplorer::SelectClass(const char *pszAcronym)
     422             : 
     423             : {
     424       36489 :     for (int i = 0; i < poRegistrar->nClasses; i++)
     425             :     {
     426       36440 :         if (!SelectClassByIndex(i))
     427           0 :             continue;
     428             : 
     429       36440 :         const char *pszClassAcronym = GetAcronym();
     430       36440 :         if (pszClassAcronym != nullptr &&
     431       36440 :             strcmp(pszClassAcronym, pszAcronym) == 0)
     432         211 :             return true;
     433             :     }
     434             : 
     435          49 :     return false;
     436             : }
     437             : 
     438             : /************************************************************************/
     439             : /*                              GetOBJL()                               */
     440             : /************************************************************************/
     441             : 
     442        5281 : int S57ClassContentExplorer::GetOBJL()
     443             : 
     444             : {
     445        5281 :     if (iCurrentClass >= 0)
     446        5281 :         return atoi(poRegistrar->apszClassesInfo[iCurrentClass]);
     447             : 
     448           0 :     return -1;
     449             : }
     450             : 
     451             : /************************************************************************/
     452             : /*                           GetDescription()                           */
     453             : /************************************************************************/
     454             : 
     455          54 : const char *S57ClassContentExplorer::GetDescription() const
     456             : 
     457             : {
     458          54 :     if (iCurrentClass >= 0 && papszCurrentFields[0] != nullptr)
     459          54 :         return papszCurrentFields[1];
     460             : 
     461           0 :     return nullptr;
     462             : }
     463             : 
     464             : /************************************************************************/
     465             : /*                             GetAcronym()                             */
     466             : /************************************************************************/
     467             : 
     468       48074 : const char *S57ClassContentExplorer::GetAcronym() const
     469             : 
     470             : {
     471       48074 :     if (iCurrentClass >= 0 && papszCurrentFields[0] != nullptr &&
     472       48074 :         papszCurrentFields[1] != nullptr)
     473       48074 :         return papszCurrentFields[2];
     474             : 
     475           0 :     return nullptr;
     476             : }
     477             : 
     478             : /************************************************************************/
     479             : /*                          GetAttributeList()                          */
     480             : /*                                                                      */
     481             : /*      The passed string can be "a", "b", "c" or NULL for all.  The    */
     482             : /*      returned list remained owned by this object, not the caller.    */
     483             : /************************************************************************/
     484             : 
     485        5305 : char **S57ClassContentExplorer::GetAttributeList(const char *pszType)
     486             : 
     487             : {
     488        5305 :     if (iCurrentClass < 0)
     489           0 :         return nullptr;
     490             : 
     491        5305 :     CSLDestroy(papszTempResult);
     492        5305 :     papszTempResult = nullptr;
     493             : 
     494       21220 :     for (int iColumn = 3; iColumn < 6; iColumn++)
     495             :     {
     496       15915 :         if (pszType != nullptr && iColumn == 3 && !EQUAL(pszType, "a"))
     497           0 :             continue;
     498             : 
     499       15915 :         if (pszType != nullptr && iColumn == 4 && !EQUAL(pszType, "b"))
     500           0 :             continue;
     501             : 
     502       15915 :         if (pszType != nullptr && iColumn == 5 && !EQUAL(pszType, "c"))
     503           0 :             continue;
     504             : 
     505       31830 :         char **papszTokens = CSLTokenizeStringComplex(
     506       15915 :             papszCurrentFields[iColumn], ";", TRUE, FALSE);
     507             : 
     508       15915 :         papszTempResult = CSLInsertStrings(papszTempResult, -1, papszTokens);
     509             : 
     510       15915 :         CSLDestroy(papszTokens);
     511             :     }
     512             : 
     513        5305 :     return papszTempResult;
     514             : }
     515             : 
     516             : /************************************************************************/
     517             : /*                            GetClassCode()                            */
     518             : /************************************************************************/
     519             : 
     520           0 : char S57ClassContentExplorer::GetClassCode() const
     521             : 
     522             : {
     523           0 :     if (iCurrentClass >= 0 && papszCurrentFields[0] != nullptr &&
     524           0 :         papszCurrentFields[1] != nullptr && papszCurrentFields[2] != nullptr &&
     525           0 :         papszCurrentFields[3] != nullptr && papszCurrentFields[4] != nullptr &&
     526           0 :         papszCurrentFields[5] != nullptr && papszCurrentFields[6] != nullptr)
     527           0 :         return papszCurrentFields[6][0];
     528             : 
     529           0 :     return '\0';
     530             : }
     531             : 
     532             : /************************************************************************/
     533             : /*                           GetPrimitives()                            */
     534             : /************************************************************************/
     535             : 
     536        5281 : char **S57ClassContentExplorer::GetPrimitives()
     537             : 
     538             : {
     539        5281 :     if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 7)
     540             :     {
     541        5281 :         CSLDestroy(papszTempResult);
     542        5281 :         papszTempResult =
     543        5281 :             CSLTokenizeStringComplex(papszCurrentFields[7], ";", TRUE, FALSE);
     544        5281 :         return papszTempResult;
     545             :     }
     546             : 
     547           0 :     return nullptr;
     548             : }
     549             : 
     550             : /************************************************************************/
     551             : /*                            GetAttrInfo()                             */
     552             : /************************************************************************/
     553             : 
     554      109511 : const S57AttrInfo *S57ClassRegistrar::GetAttrInfo(int iAttr)
     555             : {
     556      109511 :     if (iAttr < 0 || iAttr >= (int)aoAttrInfos.size())
     557           0 :         return nullptr;
     558             : 
     559      109511 :     return aoAttrInfos[iAttr];
     560             : }
     561             : 
     562             : /************************************************************************/
     563             : /*                         FindAttrByAcronym()                          */
     564             : /************************************************************************/
     565             : 
     566      108045 : int S57ClassRegistrar::FindAttrByAcronym(const char *pszName)
     567             : 
     568             : {
     569      108045 :     int iStart = 0;
     570      108045 :     int iEnd = nAttrCount - 1;
     571             : 
     572      842530 :     while (iStart <= iEnd)
     573             :     {
     574      842476 :         const int iCandidate = (iStart + iEnd) / 2;
     575             :         int nCompareValue =
     576      842476 :             strcmp(pszName, aoAttrInfos[anAttrIndex[iCandidate]]->osAcronym);
     577             : 
     578      842476 :         if (nCompareValue < 0)
     579             :         {
     580      393427 :             iEnd = iCandidate - 1;
     581             :         }
     582      449049 :         else if (nCompareValue > 0)
     583             :         {
     584      341058 :             iStart = iCandidate + 1;
     585             :         }
     586             :         else
     587      107991 :             return anAttrIndex[iCandidate];
     588             :     }
     589             : 
     590          54 :     return -1;
     591             : }

Generated by: LCOV version 1.14