LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_utils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 130 185 70.3 %
Date: 2024-05-05 22:37:24 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     mitab_utils.cpp
       4             :  * Project:  MapInfo TAB Read/Write library
       5             :  * Language: C++
       6             :  * Purpose:  Misc. util. functions for the library
       7             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       8             :  *
       9             :  **********************************************************************
      10             :  * Copyright (c) 1999-2001, Daniel Morissette
      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 OR
      23             :  * 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_port.h"
      32             : #include "mitab_utils.h"
      33             : 
      34             : #include <cctype>
      35             : #include <climits>
      36             : #include <cmath>
      37             : #include <cstring>
      38             : #include <limits>
      39             : 
      40             : #include "mitab.h"
      41             : #include "cpl_conv.h"
      42             : #include "cpl_error.h"
      43             : #include "cpl_string.h"
      44             : #include "cpl_vsi.h"
      45             : 
      46             : /**********************************************************************
      47             :  *                       TABGenerateArc()
      48             :  *
      49             :  * Generate the coordinates for an arc and ADD the coordinates to the
      50             :  * geometry object.  If the geometry already contains some points then
      51             :  * these won't be lost.
      52             :  *
      53             :  * poLine can be a OGRLineString or one of its derived classes, such as
      54             :  *        OGRLinearRing
      55             :  * numPoints is the number of points to generate.
      56             :  * Angles are specified in radians, valid values are in the range [0..2*PI]
      57             :  *
      58             :  * Arcs are always generated counterclockwise, even if StartAngle > EndAngle
      59             :  *
      60             :  * Returns 0 on success, -1 on error.
      61             :  **********************************************************************/
      62        2793 : int TABGenerateArc(OGRLineString *poLine, int numPoints, double dCenterX,
      63             :                    double dCenterY, double dXRadius, double dYRadius,
      64             :                    double dStartAngle, double dEndAngle)
      65             : {
      66             :     // Adjust angles to go counterclockwise
      67        2793 :     if (dEndAngle < dStartAngle)
      68           0 :         dEndAngle += 2.0 * M_PI;
      69             : 
      70        2793 :     const double dAngleStep = (dEndAngle - dStartAngle) / (numPoints - 1.0);
      71             : 
      72        2793 :     double dAngle = 0.0;
      73      268981 :     for (int i = 0; i < numPoints; i++)
      74             :     {
      75      266188 :         dAngle = dStartAngle + i * dAngleStep;
      76      266188 :         const double dX = dCenterX + dXRadius * cos(dAngle);
      77      266188 :         const double dY = dCenterY + dYRadius * sin(dAngle);
      78      266188 :         poLine->addPoint(dX, dY);
      79             :     }
      80             : 
      81             :     // Complete the arc with the last EndAngle, to make sure that
      82             :     // the arc is correctly closed.
      83        2793 :     const double dX = dCenterX + dXRadius * cos(dAngle);
      84        2793 :     const double dY = dCenterY + dYRadius * sin(dAngle);
      85        2793 :     poLine->addPoint(dX, dY);
      86             : 
      87        2793 :     return 0;
      88             : }
      89             : 
      90             : /**********************************************************************
      91             :  *                       TABCloseRing()
      92             :  *
      93             :  * Check if a ring is closed, and add a point to close it if necessary.
      94             :  *
      95             :  * Returns 0 on success, -1 on error.
      96             :  **********************************************************************/
      97         829 : int TABCloseRing(OGRLineString *poRing)
      98             : {
      99         829 :     if (poRing->getNumPoints() > 0 && !poRing->get_IsClosed())
     100             :     {
     101         829 :         poRing->addPoint(poRing->getX(0), poRing->getY(0));
     102             :     }
     103             : 
     104         829 :     return 0;
     105             : }
     106             : 
     107             : /**********************************************************************
     108             :  *                     TABAdjustCaseSensitiveFilename()
     109             :  *
     110             :  * Scan a filename and its path, adjust uppercase/lowercases if
     111             :  * necessary.
     112             :  *
     113             :  * Returns TRUE if file found, or FALSE if it could not be located with
     114             :  * a case-insensitive search.
     115             :  *
     116             :  * This function works on the original buffer and returns a reference to it.
     117             :  * It does nothing on Windows systems where filenames are not case sensitive.
     118             :  **********************************************************************/
     119             : #ifdef _WIN32
     120             : static bool TABAdjustCaseSensitiveFilename(char * /* pszFname */)
     121             : {
     122             :     // Nothing to do on Windows.
     123             :     return true;
     124             : }
     125             : #else
     126             : // Unix case.
     127         658 : static bool TABAdjustCaseSensitiveFilename(char *pszFname)
     128             : {
     129             :     VSIStatBufL sStatBuf;
     130             : 
     131             :     // First check if the filename is OK as is.
     132         658 :     if (VSIStatL(pszFname, &sStatBuf) == 0)
     133             :     {
     134           0 :         return true;
     135             :     }
     136             : 
     137             :     // File either does not exist or has the wrong cases.
     138             :     // Go backwards until we find a portion of the path that is valid.
     139         658 :     char *pszTmpPath = CPLStrdup(pszFname);
     140         658 :     const int nTotalLen = static_cast<int>(strlen(pszTmpPath));
     141         658 :     int iTmpPtr = nTotalLen;
     142         658 :     bool bValidPath = false;
     143             : 
     144        1316 :     while (iTmpPtr > 0 && !bValidPath)
     145             :     {
     146             :         // Move back to the previous '/' separator.
     147         658 :         pszTmpPath[--iTmpPtr] = '\0';
     148        8874 :         while (iTmpPtr > 0 && pszTmpPath[iTmpPtr - 1] != '/')
     149             :         {
     150        8216 :             pszTmpPath[--iTmpPtr] = '\0';
     151             :         }
     152             : 
     153         658 :         if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) == 0)
     154         641 :             bValidPath = true;
     155             :     }
     156             : 
     157         658 :     CPLAssert(iTmpPtr >= 0);
     158             : 
     159             :     // Assume that CWD is valid.  Therefore an empty path is a valid.
     160         658 :     if (iTmpPtr == 0)
     161          17 :         bValidPath = true;
     162             : 
     163             :     // Now that we have a valid base, reconstruct the whole path
     164             :     // by scanning all the sub-directories.
     165             :     // If we get to a point where a path component does not exist then
     166             :     // we simply return the rest of the path as is.
     167        1316 :     while (bValidPath && static_cast<int>(strlen(pszTmpPath)) < nTotalLen)
     168             :     {
     169         658 :         int iLastPartStart = iTmpPtr;
     170         658 :         char **papszDir = VSIReadDir(pszTmpPath);
     171             : 
     172             :         // Add one component to the current path.
     173         658 :         pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     174         658 :         iTmpPtr++;
     175        8874 :         for (; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr] != '/'; iTmpPtr++)
     176             :         {
     177        8216 :             pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     178             :         }
     179             : 
     180         658 :         while (iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/')
     181           0 :             iLastPartStart++;
     182             : 
     183             :         // And do a case insensitive search in the current dir.
     184        4120 :         for (int iEntry = 0; papszDir && papszDir[iEntry]; iEntry++)
     185             :         {
     186        3462 :             if (EQUAL(pszTmpPath + iLastPartStart, papszDir[iEntry]))
     187             :             {
     188             :                 // Fount it.
     189           0 :                 strcpy(pszTmpPath + iLastPartStart, papszDir[iEntry]);
     190           0 :                 break;
     191             :             }
     192             :         }
     193             : 
     194         658 :         if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) != 0)
     195         658 :             bValidPath = false;
     196             : 
     197         658 :         CSLDestroy(papszDir);
     198             :     }
     199             : 
     200             :     // We reached the last valid path component... just copy the rest
     201             :     // of the path as is.
     202         658 :     if (iTmpPtr < nTotalLen - 1)
     203             :     {
     204           0 :         strncpy(pszTmpPath + iTmpPtr, pszFname + iTmpPtr, nTotalLen - iTmpPtr);
     205             :     }
     206             : 
     207             :     // Update the source buffer and return.
     208         658 :     strcpy(pszFname, pszTmpPath);
     209         658 :     CPLFree(pszTmpPath);
     210             : 
     211         658 :     return bValidPath;
     212             : }
     213             : #endif  // Not win32.
     214             : 
     215             : /**********************************************************************
     216             :  *                       TABAdjustFilenameExtension()
     217             :  *
     218             :  * Because Unix filenames are case sensitive and MapInfo datasets often have
     219             :  * mixed cases filenames, we use this function to find the right filename
     220             :  * to use to open a specific file.
     221             :  *
     222             :  * This function works directly on the source string, so the filename it
     223             :  * contains at the end of the call is the one that should be used.
     224             :  *
     225             :  * Returns TRUE if one of the extensions worked, and FALSE otherwise.
     226             :  * If none of the extensions worked then the original extension will NOT be
     227             :  * restored.
     228             :  **********************************************************************/
     229        8142 : GBool TABAdjustFilenameExtension(char *pszFname)
     230             : {
     231             :     VSIStatBufL sStatBuf;
     232             : 
     233             :     // First try using filename as provided
     234        8142 :     if (VSIStatL(pszFname, &sStatBuf) == 0)
     235             :     {
     236        7484 :         return TRUE;
     237             :     }
     238             : 
     239             :     // Try using uppercase extension (we assume that fname contains a '.')
     240         658 :     for (int i = static_cast<int>(strlen(pszFname)) - 1;
     241        2516 :          i >= 0 && pszFname[i] != '.'; i--)
     242             :     {
     243        1858 :         pszFname[i] = static_cast<char>(
     244        1858 :             CPLToupper(static_cast<unsigned char>(pszFname[i])));
     245             :     }
     246             : 
     247         658 :     if (VSIStatL(pszFname, &sStatBuf) == 0)
     248             :     {
     249           0 :         return TRUE;
     250             :     }
     251             : 
     252             :     // Try using lowercase extension.
     253         658 :     for (int i = static_cast<int>(strlen(pszFname)) - 1;
     254        2516 :          i >= 0 && pszFname[i] != '.'; i--)
     255             :     {
     256        1858 :         pszFname[i] = static_cast<char>(
     257        1858 :             CPLTolower(static_cast<unsigned char>(pszFname[i])));
     258             :     }
     259             : 
     260         658 :     if (VSIStatL(pszFname, &sStatBuf) == 0)
     261             :     {
     262           0 :         return TRUE;
     263             :     }
     264             : 
     265             :     // None of the extensions worked.
     266             :     // Try adjusting cases in the whole path and filename.
     267         658 :     return TABAdjustCaseSensitiveFilename(pszFname);
     268             : }
     269             : 
     270             : /**********************************************************************
     271             :  *                       TABGetBasename()
     272             :  *
     273             :  * Extract the basename part of a complete file path.
     274             :  *
     275             :  * Returns a newly allocated string without the leading path (dirs) and
     276             :  * the extension.  The returned string should be freed using CPLFree().
     277             :  **********************************************************************/
     278        2373 : char *TABGetBasename(const char *pszFname)
     279             : {
     280             :     // Skip leading path or use whole name if no path dividers are encountered.
     281        2373 :     const char *pszTmp = pszFname + strlen(pszFname) - 1;
     282       39165 :     while (pszTmp != pszFname && *pszTmp != '/' && *pszTmp != '\\')
     283       36792 :         pszTmp--;
     284             : 
     285        2373 :     if (pszTmp != pszFname)
     286        2367 :         pszTmp++;
     287             : 
     288             :     // Now allocate our own copy and remove extension.
     289        2373 :     char *pszBasename = CPLStrdup(pszTmp);
     290        9492 :     for (int i = static_cast<int>(strlen(pszBasename)) - 1; i >= 0; i--)
     291             :     {
     292        9492 :         if (pszBasename[i] == '.')
     293             :         {
     294        2373 :             pszBasename[i] = '\0';
     295        2373 :             break;
     296             :         }
     297             :     }
     298             : 
     299        2373 :     return pszBasename;
     300             : }
     301             : 
     302             : /**********************************************************************
     303             :  *                       TAB_CSLLoad()
     304             :  *
     305             :  * Same as CSLLoad(), but does not produce an error if it fails... it
     306             :  * just returns NULL silently instead.
     307             :  *
     308             :  * Load a test file into a stringlist.
     309             :  *
     310             :  * Lines are limited in length by the size of the CPLReadLine() buffer.
     311             :  **********************************************************************/
     312        1304 : char **TAB_CSLLoad(const char *pszFname)
     313             : {
     314        2608 :     CPLStringList oList;
     315             : 
     316        1304 :     VSILFILE *fp = VSIFOpenL(pszFname, "rt");
     317             : 
     318        1304 :     if (fp)
     319             :     {
     320       12044 :         while (!VSIFEofL(fp))
     321             :         {
     322       10740 :             const char *pszLine = nullptr;
     323       10740 :             if ((pszLine = CPLReadLineL(fp)) != nullptr)
     324             :             {
     325       10740 :                 oList.AddString(pszLine);
     326             :             }
     327             :         }
     328             : 
     329        1304 :         VSIFCloseL(fp);
     330             :     }
     331             : 
     332        2608 :     return oList.StealList();
     333             : }
     334             : 
     335             : /**********************************************************************
     336             :  *                       TABUnEscapeString()
     337             :  *
     338             :  * Convert a string that can possibly contain escaped "\n" chars in
     339             :  * into into a new one with binary newlines in it.
     340             :  *
     341             :  * Tries to work on the original buffer unless bSrcIsConst=TRUE, in
     342             :  * which case the original is always untouched and a copy is allocated
     343             :  * ONLY IF NECESSARY.  This means that the caller should compare the
     344             :  * return value and the source (pszString) to see if a copy was returned,
     345             :  * in which case the caller becomes responsible of freeing both the
     346             :  * source and the copy.
     347             :  **********************************************************************/
     348         297 : char *TABUnEscapeString(char *pszString, GBool bSrcIsConst)
     349             : {
     350             :     // First check if we need to do any replacement.
     351         297 :     if (pszString == nullptr || strstr(pszString, "\\n") == nullptr)
     352             :     {
     353         297 :         return pszString;
     354             :     }
     355             : 
     356             :     // Yes, we need to replace at least one "\n".
     357             :     // We try to work on the original buffer unless we have bSrcIsConst=TRUE.
     358             :     //
     359             :     // Note that we do not worry about freeing the source buffer when we
     360             :     // return a copy.  It is up to the caller to decide if the source needs
     361             :     // to be freed based on context and by comparing pszString with
     362             :     // the returned pointer (pszWorkString) to see if they are identical.
     363           0 :     char *pszWorkString = nullptr;
     364           0 :     if (bSrcIsConst)
     365             :     {
     366             :         // We have to create a copy to work on.
     367             :         pszWorkString = static_cast<char *>(
     368           0 :             CPLMalloc(sizeof(char) * (strlen(pszString) + 1)));
     369             :     }
     370             :     else
     371             :     {
     372             :         // Work on the original.
     373           0 :         pszWorkString = pszString;
     374             :     }
     375             : 
     376           0 :     int i = 0;
     377           0 :     int j = 0;
     378           0 :     while (pszString[i])
     379             :     {
     380           0 :         if (pszString[i] == '\\' && pszString[i + 1] == 'n')
     381             :         {
     382           0 :             pszWorkString[j++] = '\n';
     383           0 :             i += 2;
     384             :         }
     385           0 :         else if (pszString[i] == '\\' && pszString[i + 1] == '\\')
     386             :         {
     387           0 :             pszWorkString[j++] = '\\';
     388           0 :             i += 2;
     389             :         }
     390             :         else
     391             :         {
     392           0 :             pszWorkString[j++] = pszString[i++];
     393             :         }
     394             :     }
     395           0 :     pszWorkString[j++] = '\0';
     396             : 
     397           0 :     return pszWorkString;
     398             : }
     399             : 
     400             : /**********************************************************************
     401             :  *                       TABEscapeString()
     402             :  *
     403             :  * Convert a string that can possibly contain binary "\n" chars in
     404             :  * into into a new one with escaped newlines ("\\" + "n") in it.
     405             :  *
     406             :  * The function returns the original string pointer if it did not need to
     407             :  * be modified, or a copy that has to be freed by the caller if the
     408             :  * string had to be modified.
     409             :  *
     410             :  * It is up to the caller to decide if the returned string needs to be
     411             :  * freed by comparing the source (pszString) pointer with the returned
     412             :  * pointer (pszWorkString) to see if they are identical.
     413             :  **********************************************************************/
     414           0 : char *TABEscapeString(char *pszString)
     415             : {
     416             :     // First check if we need to do any replacement
     417           0 :     if (pszString == nullptr || strchr(pszString, '\n') == nullptr)
     418             :     {
     419           0 :         return pszString;
     420             :     }
     421             : 
     422             :     // Need to do some replacements.  Alloc a copy big enough
     423             :     // to hold the worst possible case.
     424             :     char *pszWorkString = static_cast<char *>(
     425           0 :         CPLMalloc(2 * sizeof(char) * (strlen(pszString) + 1)));
     426             : 
     427           0 :     int i = 0;
     428           0 :     int j = 0;
     429             : 
     430           0 :     while (pszString[i])
     431             :     {
     432           0 :         if (pszString[i] == '\n')
     433             :         {
     434           0 :             pszWorkString[j++] = '\\';
     435           0 :             pszWorkString[j++] = 'n';
     436           0 :             i++;
     437             :         }
     438           0 :         else if (pszString[i] == '\\')
     439             :         {
     440           0 :             pszWorkString[j++] = '\\';
     441           0 :             pszWorkString[j++] = '\\';
     442           0 :             i++;
     443             :         }
     444             :         else
     445             :         {
     446           0 :             pszWorkString[j++] = pszString[i++];
     447             :         }
     448             :     }
     449           0 :     pszWorkString[j++] = '\0';
     450             : 
     451           0 :     return pszWorkString;
     452             : }
     453             : 
     454             : /**********************************************************************
     455             :  *                       TABCleanFieldName()
     456             :  *
     457             :  * Return a copy of pszSrcName that contains only valid characters for a
     458             :  * TAB field name.  All invalid characters are replaced by '_'.
     459             :  *
     460             :  * The returned string should be freed by the caller.
     461             :  **********************************************************************/
     462         392 : char *TABCleanFieldName(const char *pszSrcName)
     463             : {
     464         392 :     char *pszNewName = CPLStrdup(pszSrcName);
     465         392 :     if (strlen(pszNewName) > 31)
     466             :     {
     467           0 :         pszNewName[31] = '\0';
     468           0 :         CPLError(CE_Warning,
     469             :                  static_cast<CPLErrorNum>(TAB_WarningInvalidFieldName),
     470             :                  "Field name '%s' is longer than the max of 31 characters. "
     471             :                  "'%s' will be used instead.",
     472             :                  pszSrcName, pszNewName);
     473             :     }
     474             : 
     475             :     // According to the MapInfo User's Guide (p. 240, v5.5).
     476             :     // New Table Command:
     477             :     //  Name:
     478             :     // Displays the field name in the name box. You can also enter new field
     479             :     // names here. Defaults are Field1, Field2, etc. A field name can contain
     480             :     // up to 31 alphanumeric characters. Use letters, numbers, and the
     481             :     // underscore. Do not use spaces; instead, use the underscore character
     482             :     // (_) to separate words in a field name. Use upper and lower case for
     483             :     // legibility, but MapInfo is not case-sensitive.
     484             :     //
     485             :     // It was also verified that extended chars with accents are also
     486             :     // accepted.
     487         392 :     int numInvalidChars = 0;
     488        2277 :     for (int i = 0; pszSrcName && pszSrcName[i] != '\0'; i++)
     489             :     {
     490        1885 :         if (pszSrcName[i] == '#')
     491             :         {
     492           0 :             if (i == 0)
     493             :             {
     494           0 :                 pszNewName[i] = '_';
     495           0 :                 numInvalidChars++;
     496             :             }
     497             :         }
     498        1885 :         else if (!(pszSrcName[i] == '_' ||
     499        1479 :                    (i != 0 && pszSrcName[i] >= '0' && pszSrcName[i] <= '9') ||
     500        1692 :                    (pszSrcName[i] >= 'a' && pszSrcName[i] <= 'z') ||
     501         463 :                    (pszSrcName[i] >= 'A' && pszSrcName[i] <= 'Z') ||
     502         187 :                    static_cast<GByte>(pszSrcName[i]) >= 192))
     503             :         {
     504           1 :             pszNewName[i] = '_';
     505           1 :             numInvalidChars++;
     506             :         }
     507             :     }
     508             : 
     509         392 :     if (numInvalidChars > 0)
     510             :     {
     511           1 :         CPLError(CE_Warning,
     512             :                  static_cast<CPLErrorNum>(TAB_WarningInvalidFieldName),
     513             :                  "Field name '%s' contains invalid characters. "
     514             :                  "'%s' will be used instead.",
     515             :                  pszSrcName, pszNewName);
     516             :     }
     517             : 
     518         392 :     return pszNewName;
     519             : }
     520             : 
     521             : /**********************************************************************
     522             :  * MapInfo Units string to numeric ID conversion
     523             :  **********************************************************************/
     524             : typedef struct
     525             : {
     526             :     int nUnitId;
     527             :     const char *pszAbbrev;
     528             : } MapInfoUnitsInfo;
     529             : 
     530             : static const MapInfoUnitsInfo gasUnitsList[] = {
     531             :     {0, "mi"},        {1, "km"},          {2, "in"},  {3, "ft"},
     532             :     {4, "yd"},        {5, "mm"},          {6, "cm"},  {7, "m"},
     533             :     {8, "survey ft"}, {8, "survey foot"},  // alternate
     534             :     {13, nullptr},    {9, "nmi"},         {30, "li"}, {31, "ch"},
     535             :     {32, "rd"},       {-1, nullptr}};
     536             : 
     537             : /**********************************************************************
     538             :  *                       TABUnitIdToString()
     539             :  *
     540             :  * Return the MIF units name for specified units id.
     541             :  * Return "" if no match found.
     542             :  *
     543             :  * The returned string should not be freed by the caller.
     544             :  **********************************************************************/
     545          81 : const char *TABUnitIdToString(int nId)
     546             : {
     547          81 :     const MapInfoUnitsInfo *psList = gasUnitsList;
     548             : 
     549         674 :     while (psList->nUnitId != -1)
     550             :     {
     551         674 :         if (psList->nUnitId == nId)
     552          81 :             return psList->pszAbbrev;
     553         593 :         psList++;
     554             :     }
     555             : 
     556           0 :     return "";
     557             : }
     558             : 
     559             : /**********************************************************************
     560             :  *                       TABUnitIdFromString()
     561             :  *
     562             :  * Return the units ID for specified MIF units name
     563             :  *
     564             :  * Returns -1 if no match found.
     565             :  **********************************************************************/
     566         166 : int TABUnitIdFromString(const char *pszName)
     567             : {
     568         166 :     if (pszName == nullptr)
     569           0 :         return 13;
     570             : 
     571         166 :     const MapInfoUnitsInfo *psList = gasUnitsList;
     572             : 
     573        1314 :     while (psList->nUnitId != -1)
     574             :     {
     575        1314 :         if (psList->pszAbbrev != nullptr && EQUAL(psList->pszAbbrev, pszName))
     576         166 :             return psList->nUnitId;
     577        1148 :         psList++;
     578             :     }
     579             : 
     580           0 :     return -1;
     581             : }
     582             : 
     583             : /**********************************************************************
     584             :  *                       TABSaturatedAdd()
     585             :  ***********************************************************************/
     586             : 
     587       70184 : void TABSaturatedAdd(GInt32 &nVal, GInt32 nAdd)
     588             : {
     589       70184 :     const GInt32 int_max = std::numeric_limits<GInt32>::max();
     590       70184 :     const GInt32 int_min = std::numeric_limits<GInt32>::min();
     591             : 
     592       70184 :     if (nAdd >= 0 && nVal > int_max - nAdd)
     593           0 :         nVal = int_max;
     594       70184 :     else if (nAdd == int_min && nVal < 0)
     595           0 :         nVal = int_min;
     596       70184 :     else if (nAdd != int_min && nAdd < 0 && nVal < int_min - nAdd)
     597           0 :         nVal = int_min;
     598             :     else
     599       70184 :         nVal += nAdd;
     600       70184 : }
     601             : 
     602             : /**********************************************************************
     603             :  *                           TABInt16Diff()
     604             :  **********************************************************************/
     605             : 
     606       10316 : GInt16 TABInt16Diff(int a, int b)
     607             : {
     608       10316 :     GIntBig nDiff = static_cast<GIntBig>(a) - b;
     609             :     // Maybe we should error out instead of saturating ???
     610       10316 :     if (nDiff < -32768)
     611           0 :         return -32768;
     612       10316 :     if (nDiff > 32767)
     613           0 :         return 32767;
     614       10316 :     return static_cast<GInt16>(nDiff);
     615             : }

Generated by: LCOV version 1.14