LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlasutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 86 90 95.6 %
Date: 2024-11-21 22:18:42 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        3709 : CPLString OGRGMLASTruncateIdentifier(const CPLString &osName,
      25             :                                      int nIdentMaxLength)
      26             : {
      27        3709 :     int nExtra = static_cast<int>(osName.size()) - nIdentMaxLength;
      28        3709 :     CPLAssert(nExtra > 0);
      29             : 
      30             :     // Decompose in tokens
      31        3709 :     char **papszTokens = CSLTokenizeString2(osName, "_", CSLT_ALLOWEMPTYTOKENS);
      32        7418 :     std::vector<char> achDelimiters;
      33        7418 :     std::vector<CPLString> aosTokens;
      34       14065 :     for (int j = 0; papszTokens[j] != nullptr; ++j)
      35             :     {
      36       10356 :         const char *pszToken = papszTokens[j];
      37       10356 :         bool bIsCamelCase = false;
      38             :         // Split parts like camelCase or CamelCase into several tokens
      39       10356 :         if (pszToken[0] != '\0' && pszToken[1] >= 'a' && pszToken[1] <= 'z')
      40             :         {
      41        9143 :             bIsCamelCase = true;
      42        9143 :             bool bLastIsLower = true;
      43       18286 :             std::vector<CPLString> aoParts;
      44       18286 :             CPLString osCurrentPart;
      45        9143 :             osCurrentPart += pszToken[0];
      46        9143 :             osCurrentPart += pszToken[1];
      47       93742 :             for (int k = 2; pszToken[k]; ++k)
      48             :             {
      49       84790 :                 if (pszToken[k] >= 'A' && pszToken[k] <= 'Z')
      50             :                 {
      51        7107 :                     if (!bLastIsLower)
      52             :                     {
      53         191 :                         bIsCamelCase = false;
      54         191 :                         break;
      55             :                     }
      56        6916 :                     aoParts.push_back(osCurrentPart);
      57        6916 :                     osCurrentPart.clear();
      58        6916 :                     bLastIsLower = false;
      59             :                 }
      60             :                 else
      61             :                 {
      62       77683 :                     bLastIsLower = true;
      63             :                 }
      64       84599 :                 osCurrentPart += pszToken[k];
      65             :             }
      66        9143 :             if (bIsCamelCase)
      67             :             {
      68        8952 :                 if (!osCurrentPart.empty())
      69        8952 :                     aoParts.push_back(osCurrentPart);
      70       24622 :                 for (size_t k = 0; k < aoParts.size(); ++k)
      71             :                 {
      72       15670 :                     achDelimiters.push_back((j > 0 && k == 0) ? '_' : '\0');
      73       15670 :                     aosTokens.push_back(aoParts[k]);
      74             :                 }
      75             :             }
      76             :         }
      77       10356 :         if (!bIsCamelCase)
      78             :         {
      79        1404 :             achDelimiters.push_back((j > 0) ? '_' : '\0');
      80        1404 :             aosTokens.push_back(pszToken);
      81             :         }
      82             :     }
      83        3709 :     CSLDestroy(papszTokens);
      84             : 
      85             :     // Truncate identifier by removing last character of longest part
      86        7418 :     std::map<int, std::set<size_t>> oMapLengthToIdx;
      87             :     // Ignore last token in map creation
      88       17074 :     for (size_t j = 0; j + 1 < aosTokens.size(); ++j)
      89             :     {
      90       13365 :         const int nTokenLen = static_cast<int>(aosTokens[j].size());
      91       13365 :         oMapLengthToIdx[nTokenLen].insert(j);
      92             :     }
      93        3709 :     int nLastTokenSize = static_cast<int>(aosTokens.back().size());
      94        3709 :     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        3679 :         bool bHasDoneSomething = true;
     105       77480 :         while (nExtra > 0 && bHasDoneSomething)
     106             :         {
     107       73801 :             bHasDoneSomething = false;
     108       73801 :             auto iter = oMapLengthToIdx.end();
     109       73801 :             --iter;
     110             :             // Avoid truncating last token unless it is excessively longer
     111             :             // than previous ones.
     112       73801 :             if (nLastTokenSize > 2 * iter->first)
     113             :             {
     114        6028 :                 aosTokens.back().resize(nLastTokenSize - 1);
     115        6028 :                 nLastTokenSize--;
     116        6028 :                 bHasDoneSomething = true;
     117        6028 :                 nExtra--;
     118             :             }
     119       67773 :             else if (iter->first > 1)
     120             :             {
     121             :                 // Reduce one token by one character
     122       67016 :                 const size_t j = *iter->second.begin();
     123       67016 :                 aosTokens[j].resize(iter->first - 1);
     124             : 
     125             :                 // Move it to a new bucket
     126       67016 :                 iter->second.erase(iter->second.begin());
     127       67016 :                 oMapLengthToIdx[iter->first - 1].insert(j);
     128             : 
     129             :                 // Remove this bucket if is empty
     130       67016 :                 if (iter->second.empty())
     131             :                 {
     132       26392 :                     oMapLengthToIdx.erase(iter);
     133             :                 }
     134             : 
     135       67016 :                 nExtra--;
     136       67016 :                 bHasDoneSomething = true;
     137             :             }
     138             :         }
     139             :     }
     140             : 
     141             :     // Reassemble truncated parts
     142        3709 :     CPLString osNewName;
     143       20783 :     for (size_t j = 0; j < aosTokens.size(); ++j)
     144             :     {
     145       17074 :         if (achDelimiters[j])
     146        6647 :             osNewName += achDelimiters[j];
     147       17074 :         osNewName += aosTokens[j];
     148             :     }
     149             : 
     150             :     // If we are still longer than max allowed, truncate beginning of name
     151        3709 :     if (nExtra > 0)
     152             :     {
     153         757 :         osNewName = osNewName.substr(nExtra);
     154             :     }
     155        3709 :     CPLAssert(static_cast<int>(osNewName.size()) == nIdentMaxLength);
     156        7418 :     return osNewName;
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                      OGRGMLASAddSerialNumber()                       */
     161             : /************************************************************************/
     162             : 
     163          82 : CPLString OGRGMLASAddSerialNumber(const CPLString &osNameIn, int iOccurrence,
     164             :                                   size_t nOccurrences, int nIdentMaxLength)
     165             : {
     166          82 :     CPLString osName(osNameIn);
     167          94 :     const int nDigitsSize = (nOccurrences < 10)    ? 1
     168          12 :                             : (nOccurrences < 100) ? 2
     169             :                                                    : 3;
     170             :     char szDigits[4];
     171          82 :     snprintf(szDigits, sizeof(szDigits), "%0*d", nDigitsSize, iOccurrence);
     172          82 :     if (nIdentMaxLength >= MIN_VALUE_OF_MAX_IDENTIFIER_LENGTH)
     173             :     {
     174          78 :         if (static_cast<int>(osName.size()) < nIdentMaxLength)
     175             :         {
     176           0 :             if (static_cast<int>(osName.size()) + nDigitsSize < nIdentMaxLength)
     177             :             {
     178           0 :                 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         164 :     return osName;
     200             : }

Generated by: LCOV version 1.14