LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlasutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 88 90 97.8 %
Date: 2025-07-09 17:50:03 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  OGR
       3             :  * Purpose:  OGRGMLASDriver implementation
       4             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       5             :  *
       6             :  * Initial development funded by the European Earth observation programme
       7             :  * Copernicus
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "ogr_gmlas.h"
      16             : 
      17             : #include <map>
      18             : #include <set>
      19             : 
      20             : /************************************************************************/
      21             : /*                  OGRGMLASTruncateIdentifier()                        */
      22             : /************************************************************************/
      23             : 
      24        4476 : CPLString OGRGMLASTruncateIdentifier(const CPLString &osName,
      25             :                                      int nIdentMaxLength)
      26             : {
      27        4476 :     int nExtra = static_cast<int>(osName.size()) - nIdentMaxLength;
      28        4476 :     CPLAssert(nExtra > 0);
      29             : 
      30             :     // Decompose in tokens
      31        4476 :     char **papszTokens = CSLTokenizeString2(osName, "_", CSLT_ALLOWEMPTYTOKENS);
      32        8952 :     std::vector<char> achDelimiters;
      33        8952 :     std::vector<CPLString> aosTokens;
      34       18250 :     for (int j = 0; papszTokens[j] != nullptr; ++j)
      35             :     {
      36       13774 :         const char *pszToken = papszTokens[j];
      37       13774 :         bool bIsCamelCase = false;
      38             :         // Split parts like camelCase or CamelCase into several tokens
      39       13774 :         if (pszToken[0] != '\0' && pszToken[1] >= 'a' && pszToken[1] <= 'z')
      40             :         {
      41       11952 :             bIsCamelCase = true;
      42       11952 :             bool bLastIsLower = true;
      43       23904 :             std::vector<CPLString> aoParts;
      44       23904 :             CPLString osCurrentPart;
      45       11952 :             osCurrentPart += pszToken[0];
      46       11952 :             osCurrentPart += pszToken[1];
      47      143704 :             for (int k = 2; pszToken[k]; ++k)
      48             :             {
      49      131943 :                 if (pszToken[k] >= 'A' && pszToken[k] <= 'Z')
      50             :                 {
      51       12552 :                     if (!bLastIsLower)
      52             :                     {
      53         191 :                         bIsCamelCase = false;
      54         191 :                         break;
      55             :                     }
      56       12361 :                     aoParts.push_back(osCurrentPart);
      57       12361 :                     osCurrentPart.clear();
      58       12361 :                     bLastIsLower = false;
      59             :                 }
      60             :                 else
      61             :                 {
      62      119391 :                     bLastIsLower = true;
      63             :                 }
      64      131752 :                 osCurrentPart += pszToken[k];
      65             :             }
      66       11952 :             if (bIsCamelCase)
      67             :             {
      68       11761 :                 if (!osCurrentPart.empty())
      69       11761 :                     aoParts.push_back(std::move(osCurrentPart));
      70       35685 :                 for (size_t k = 0; k < aoParts.size(); ++k)
      71             :                 {
      72       23924 :                     achDelimiters.push_back((j > 0 && k == 0) ? '_' : '\0');
      73       23924 :                     aosTokens.push_back(aoParts[k]);
      74             :                 }
      75             :             }
      76             :         }
      77       13774 :         if (!bIsCamelCase)
      78             :         {
      79        2013 :             achDelimiters.push_back((j > 0) ? '_' : '\0');
      80        2013 :             aosTokens.push_back(pszToken);
      81             :         }
      82             :     }
      83        4476 :     CSLDestroy(papszTokens);
      84             : 
      85             :     // Truncate identifier by removing last character of longest part
      86        8952 :     std::map<int, std::set<size_t>> oMapLengthToIdx;
      87             :     // Ignore last token in map creation
      88       25937 :     for (size_t j = 0; j + 1 < aosTokens.size(); ++j)
      89             :     {
      90       21461 :         const int nTokenLen = static_cast<int>(aosTokens[j].size());
      91       21461 :         oMapLengthToIdx[nTokenLen].insert(j);
      92             :     }
      93        4476 :     int nLastTokenSize = static_cast<int>(aosTokens.back().size());
      94        4476 :     if (oMapLengthToIdx.empty())
      95             :     {
      96          30 :         if (nLastTokenSize > nExtra)
      97             :         {
      98          30 :             aosTokens.back().resize(nLastTokenSize - nExtra);
      99          30 :             nExtra = 0;
     100             :         }
     101             :     }
     102             :     else
     103             :     {
     104        4446 :         bool bHasDoneSomething = true;
     105       87712 :         while (nExtra > 0 && bHasDoneSomething)
     106             :         {
     107       83266 :             bHasDoneSomething = false;
     108       83266 :             auto iter = oMapLengthToIdx.end();
     109       83266 :             --iter;
     110             :             // Avoid truncating last token unless it is excessively longer
     111             :             // than previous ones.
     112       83266 :             if (nLastTokenSize > 2 * iter->first)
     113             :             {
     114        6054 :                 aosTokens.back().resize(nLastTokenSize - 1);
     115        6054 :                 nLastTokenSize--;
     116        6054 :                 bHasDoneSomething = true;
     117        6054 :                 nExtra--;
     118             :             }
     119       77212 :             else if (iter->first > 1)
     120             :             {
     121             :                 // Reduce one token by one character
     122       76455 :                 const size_t j = *iter->second.begin();
     123       76455 :                 aosTokens[j].resize(iter->first - 1);
     124             : 
     125             :                 // Move it to a new bucket
     126       76455 :                 iter->second.erase(iter->second.begin());
     127       76455 :                 oMapLengthToIdx[iter->first - 1].insert(j);
     128             : 
     129             :                 // Remove this bucket if is empty
     130       76455 :                 if (iter->second.empty())
     131             :                 {
     132       29697 :                     oMapLengthToIdx.erase(iter);
     133             :                 }
     134             : 
     135       76455 :                 nExtra--;
     136       76455 :                 bHasDoneSomething = true;
     137             :             }
     138             :         }
     139             :     }
     140             : 
     141             :     // Reassemble truncated parts
     142        4476 :     CPLString osNewName;
     143       30413 :     for (size_t j = 0; j < aosTokens.size(); ++j)
     144             :     {
     145       25937 :         if (achDelimiters[j])
     146        9298 :             osNewName += achDelimiters[j];
     147       25937 :         osNewName += aosTokens[j];
     148             :     }
     149             : 
     150             :     // If we are still longer than max allowed, truncate beginning of name
     151        4476 :     if (nExtra > 0)
     152             :     {
     153         757 :         osNewName = osNewName.substr(nExtra);
     154             :     }
     155        4476 :     CPLAssert(static_cast<int>(osNewName.size()) == nIdentMaxLength);
     156        8952 :     return osNewName;
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                      OGRGMLASAddSerialNumber()                       */
     161             : /************************************************************************/
     162             : 
     163          90 : CPLString OGRGMLASAddSerialNumber(const CPLString &osNameIn, int iOccurrence,
     164             :                                   size_t nOccurrences, int nIdentMaxLength)
     165             : {
     166          90 :     CPLString osName(osNameIn);
     167         102 :     const int nDigitsSize = (nOccurrences < 10)    ? 1
     168          12 :                             : (nOccurrences < 100) ? 2
     169             :                                                    : 3;
     170             :     char szDigits[4];
     171          90 :     snprintf(szDigits, sizeof(szDigits), "%0*d", nDigitsSize, iOccurrence);
     172          90 :     if (nIdentMaxLength >= MIN_VALUE_OF_MAX_IDENTIFIER_LENGTH)
     173             :     {
     174          86 :         if (static_cast<int>(osName.size()) < nIdentMaxLength)
     175             :         {
     176           8 :             if (static_cast<int>(osName.size()) + nDigitsSize < nIdentMaxLength)
     177             :             {
     178           8 :                 osName += szDigits;
     179             :             }
     180             :             else
     181             :             {
     182           0 :                 osName.resize(nIdentMaxLength - nDigitsSize);
     183           0 :                 osName += szDigits;
     184             :             }
     185             :         }
     186             :         else
     187             :         {
     188             :             const int nTruncatedSize =
     189          78 :                 static_cast<int>(osName.size()) - nDigitsSize;
     190          78 :             if (nTruncatedSize >= 0)
     191          78 :                 osName.resize(nTruncatedSize);
     192          78 :             osName += szDigits;
     193             :         }
     194             :     }
     195             :     else
     196             :     {
     197           4 :         osName += szDigits;
     198             :     }
     199         180 :     return osName;
     200             : }

Generated by: LCOV version 1.14