LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - avc_misc.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 52 145 35.9 %
Date: 2025-01-18 12:42:00 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     avc_misc.c
       4             :  * Project:  Arc/Info vector coverage (AVC)  BIN<->E00 conversion library
       5             :  * Language: ANSI C
       6             :  * Purpose:  Misc. functions used by several parts of the library
       7             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       8             :  *
       9             :  **********************************************************************
      10             :  * Copyright (c) 1999-2005, Daniel Morissette
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  **********************************************************************
      14             :  *
      15             :  * $Log: avc_misc.c,v $
      16             :  * Revision 1.9  2005/06/03 03:49:59  daniel
      17             :  * Update email address, website url, and copyright dates
      18             :  *
      19             :  * Revision 1.8  2004/08/31 21:00:20  warmerda
      20             :  * Applied Carl Anderson's patch to reduce the amount of stating while
      21             :  * trying to discover filename "case" on Unix in AVCAdjustCaseSensitiveFilename.
      22             :  * http://bugzilla.remotesensing.org/show_bug.cgi?id=314
      23             :  *
      24             :  * Revision 1.7  2001/11/25 21:38:01  daniel
      25             :  * Remap '\\' to '/' in AVCAdjustCaseSensitiveFilename() on Unix.
      26             :  *
      27             :  * Revision 1.6  2001/11/25 21:15:23  daniel
      28             :  * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
      29             :  * digits to double precision as we generate E00 output (bug599)
      30             :  *
      31             :  * Revision 1.5  2000/09/26 20:21:04  daniel
      32             :  * Added AVCCoverPC write
      33             :  *
      34             :  * Revision 1.4  2000/09/22 19:45:21  daniel
      35             :  * Switch to MIT-style license
      36             :  *
      37             :  * Revision 1.3  2000/01/10 02:53:21  daniel
      38             :  * Added AVCAdjustCaseSensitiveFilename() and AVCFileExists()
      39             :  *
      40             :  * Revision 1.2  1999/08/23 18:24:27  daniel
      41             :  * Fixed support for attribute fields of type 40
      42             :  *
      43             :  * Revision 1.1  1999/05/11 02:34:46  daniel
      44             :  * Initial revision
      45             :  *
      46             :  **********************************************************************/
      47             : 
      48             : #include "avc.h"
      49             : 
      50             : /**********************************************************************
      51             :  *                          AVCE00ComputeRecSize()
      52             :  *
      53             :  * Computes the number of chars required to generate a E00 attribute
      54             :  * table record.
      55             :  *
      56             :  * Returns -1 on error, i.e. if it encounters an unsupported field type.
      57             :  **********************************************************************/
      58          55 : int _AVCE00ComputeRecSize(int numFields, AVCFieldInfo *pasDef,
      59             :                           GBool bMapType40ToDouble)
      60             : {
      61          55 :     int i, nType, nBufSize = 0;
      62             : 
      63             :     /*-------------------------------------------------------------
      64             :      * Add up the nbr of chars used by each field
      65             :      *------------------------------------------------------------*/
      66         338 :     for (i = 0; i < numFields; i++)
      67             :     {
      68         283 :         nType = pasDef[i].nType1 * 10;
      69         283 :         if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
      70             :             nType == AVC_FT_FIXINT)
      71             :         {
      72          22 :             nBufSize += pasDef[i].nSize;
      73             :         }
      74         261 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
      75          87 :             nBufSize += 11;
      76         174 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
      77           0 :             nBufSize += 6;
      78         174 :         else if (bMapType40ToDouble && nType == AVC_FT_FIXNUM &&
      79           0 :                  pasDef[i].nSize > 8)
      80             :         {
      81             :             /* See explanation in AVCE00GenTableHdr() about this hack to remap
      82             :              * type 40 fields to double precision floats.
      83             :              */
      84           0 :             nBufSize += 24; /* Remap to double float */
      85             :         }
      86         174 :         else if ((nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4) ||
      87             :                  nType == AVC_FT_FIXNUM)
      88         174 :             nBufSize += 14;
      89           0 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
      90           0 :             nBufSize += 24;
      91             :         else
      92             :         {
      93             :             /*-----------------------------------------------------
      94             :              * Hummm... unsupported field type...
      95             :              *----------------------------------------------------*/
      96           0 :             CPLError(CE_Failure, CPLE_NotSupported,
      97             :                      "_AVCE00ComputeRecSize(): Unsupported field type: "
      98             :                      "(type=%d, size=%d)",
      99           0 :                      nType, pasDef[i].nSize);
     100           0 :             return -1;
     101             :         }
     102             :     }
     103             : 
     104          55 :     return nBufSize;
     105             : }
     106             : 
     107             : /**********************************************************************
     108             :  *                          _AVCDestroyTableFields()
     109             :  *
     110             :  * Release all memory associated with an array of AVCField structures.
     111             :  **********************************************************************/
     112          62 : void _AVCDestroyTableFields(AVCTableDef *psTableDef, AVCField *pasFields)
     113             : {
     114             :     int i, nFieldType;
     115             : 
     116          62 :     if (pasFields)
     117             :     {
     118         376 :         for (i = 0; i < psTableDef->numFields; i++)
     119             :         {
     120         314 :             nFieldType = psTableDef->pasFieldDef[i].nType1 * 10;
     121         314 :             if (nFieldType == AVC_FT_DATE || nFieldType == AVC_FT_CHAR ||
     122         289 :                 nFieldType == AVC_FT_FIXINT || nFieldType == AVC_FT_FIXNUM)
     123             :             {
     124          25 :                 CPLFree(pasFields[i].pszStr);
     125             :             }
     126             :         }
     127          62 :         CPLFree(pasFields);
     128             :     }
     129          62 : }
     130             : 
     131             : /**********************************************************************
     132             :  *                          _AVCDestroyTableDef()
     133             :  *
     134             :  * Release all memory associated with a AVCTableDef structure.
     135             :  *
     136             :  **********************************************************************/
     137          62 : void _AVCDestroyTableDef(AVCTableDef *psTableDef)
     138             : {
     139          62 :     if (psTableDef)
     140             :     {
     141          62 :         CPLFree(psTableDef->pasFieldDef);
     142          62 :         CPLFree(psTableDef);
     143             :     }
     144          62 : }
     145             : 
     146             : /**********************************************************************
     147             :  *                          _AVCDupTableDef()
     148             :  *
     149             :  * Create a new copy of a AVCTableDef structure.
     150             :  **********************************************************************/
     151           0 : AVCTableDef *_AVCDupTableDef(AVCTableDef *psSrcDef)
     152             : {
     153             :     AVCTableDef *psNewDef;
     154             : 
     155           0 :     if (psSrcDef == nullptr)
     156           0 :         return nullptr;
     157             : 
     158           0 :     psNewDef = (AVCTableDef *)CPLMalloc(1 * sizeof(AVCTableDef));
     159             : 
     160           0 :     memcpy(psNewDef, psSrcDef, sizeof(AVCTableDef));
     161             : 
     162           0 :     psNewDef->pasFieldDef =
     163           0 :         (AVCFieldInfo *)CPLMalloc(psSrcDef->numFields * sizeof(AVCFieldInfo));
     164             : 
     165           0 :     memcpy(psNewDef->pasFieldDef, psSrcDef->pasFieldDef,
     166           0 :            psSrcDef->numFields * sizeof(AVCFieldInfo));
     167             : 
     168           0 :     return psNewDef;
     169             : }
     170             : 
     171             : /**********************************************************************
     172             :  *                          AVCFileExists()
     173             :  *
     174             :  * Returns TRUE if a file with the specified name exists in the
     175             :  * specified directory.
     176             :  *
     177             :  * For now I simply try to fopen() the file ... would it be more
     178             :  * efficient to use stat() ???
     179             :  **********************************************************************/
     180          10 : GBool AVCFileExists(const char *pszPath, const char *pszName)
     181             : {
     182             :     char *pszBuf;
     183          10 :     GBool bFileExists = FALSE;
     184             :     VSILFILE *fp;
     185             : 
     186          10 :     pszBuf = (char *)CPLMalloc(strlen(pszPath) + strlen(pszName) + 1);
     187          10 :     snprintf(pszBuf, strlen(pszPath) + strlen(pszName) + 1, "%s%s", pszPath,
     188             :              pszName);
     189             : 
     190          10 :     AVCAdjustCaseSensitiveFilename(pszBuf);
     191             : 
     192          10 :     if ((fp = VSIFOpenL(pszBuf, "rb")) != nullptr)
     193             :     {
     194          10 :         bFileExists = TRUE;
     195          10 :         VSIFCloseL(fp);
     196             :     }
     197             : 
     198          10 :     CPLFree(pszBuf);
     199             : 
     200          10 :     return bFileExists;
     201             : }
     202             : 
     203             : /**********************************************************************
     204             :  *                     AVCAdjustCaseSensitiveFilename()
     205             :  *
     206             :  * Scan a filename and its path, adjust uppercase/lowercases if
     207             :  * necessary, and return a reference to that filename.
     208             :  *
     209             :  * This function works on the original buffer and returns a reference to it.
     210             :  *
     211             :  * NFW: It seems like this could be made somewhat more efficient by
     212             :  * getting a directory listing and doing a case insensitive search in
     213             :  * that list rather than all this stating that can be very expensive
     214             :  * in some circumstances.  However, at least with Carl's fix this is
     215             :  * somewhat faster.
     216             :  * see: http://bugzilla.remotesensing.org/show_bug.cgi?id=314
     217             :  **********************************************************************/
     218         105 : char *AVCAdjustCaseSensitiveFilename(char *pszFname)
     219             : {
     220             :     VSIStatBufL sStatBuf;
     221         105 :     char *pszTmpPath = nullptr;
     222             :     int nTotalLen, iTmpPtr;
     223             :     GBool bValidPath;
     224             : 
     225             :     /*-----------------------------------------------------------------
     226             :      * First check if the filename is OK as is.
     227             :      *----------------------------------------------------------------*/
     228         105 :     if (VSIStatL(pszFname, &sStatBuf) == 0)
     229             :     {
     230          61 :         return pszFname;
     231             :     }
     232             : 
     233          44 :     pszTmpPath = CPLStrdup(pszFname);
     234          44 :     nTotalLen = (int)strlen(pszTmpPath);
     235             : 
     236             :     /*-----------------------------------------------------------------
     237             :      * Remap '\\' to '/'
     238             :      *----------------------------------------------------------------*/
     239        2336 :     for (iTmpPtr = 0; iTmpPtr < nTotalLen; iTmpPtr++)
     240             :     {
     241        2292 :         if (pszTmpPath[iTmpPtr] == '\\')
     242           0 :             pszTmpPath[iTmpPtr] = '/';
     243             :     }
     244             : 
     245             :     /*-----------------------------------------------------------------
     246             :      * Try all lower case, check if the filename is OK as that.
     247             :      *----------------------------------------------------------------*/
     248        2336 :     for (iTmpPtr = 0; iTmpPtr < nTotalLen; iTmpPtr++)
     249             :     {
     250        2292 :         if (pszTmpPath[iTmpPtr] >= 'A' && pszTmpPath[iTmpPtr] <= 'Z')
     251         132 :             pszTmpPath[iTmpPtr] += 32;
     252             :     }
     253             : 
     254          44 :     if (VSIStatL(pszTmpPath, &sStatBuf) == 0)
     255             :     {
     256          44 :         strcpy(pszFname, pszTmpPath);
     257          44 :         CPLFree(pszTmpPath);
     258          44 :         return pszFname;
     259             :     }
     260             : 
     261             :     /*-----------------------------------------------------------------
     262             :      * Try all upper case, check if the filename is OK as that.
     263             :      *----------------------------------------------------------------*/
     264           0 :     for (iTmpPtr = 0; iTmpPtr < nTotalLen; iTmpPtr++)
     265             :     {
     266           0 :         if (pszTmpPath[iTmpPtr] >= 'a' && pszTmpPath[iTmpPtr] <= 'z')
     267           0 :             pszTmpPath[iTmpPtr] -= 32;
     268             :     }
     269             : 
     270           0 :     if (VSIStatL(pszTmpPath, &sStatBuf) == 0)
     271             :     {
     272           0 :         strcpy(pszFname, pszTmpPath);
     273           0 :         CPLFree(pszTmpPath);
     274           0 :         return pszFname;
     275             :     }
     276             : 
     277             :     /*-----------------------------------------------------------------
     278             :      * OK, file either does not exist or has the wrong cases... we'll
     279             :      * go backwards until we find a portion of the path that is valid.
     280             :      *----------------------------------------------------------------*/
     281           0 :     strcpy(pszTmpPath, pszFname);
     282             : 
     283             :     /*-----------------------------------------------------------------
     284             :      * Remap '\\' to '/'
     285             :      *----------------------------------------------------------------*/
     286           0 :     for (iTmpPtr = 0; iTmpPtr < nTotalLen; iTmpPtr++)
     287             :     {
     288           0 :         if (pszTmpPath[iTmpPtr] == '\\')
     289           0 :             pszTmpPath[iTmpPtr] = '/';
     290             :     }
     291             : 
     292           0 :     bValidPath = FALSE;
     293           0 :     while (iTmpPtr > 0 && !bValidPath)
     294             :     {
     295             :         /*-------------------------------------------------------------
     296             :          * Move back to the previous '/' separator
     297             :          *------------------------------------------------------------*/
     298           0 :         pszTmpPath[--iTmpPtr] = '\0';
     299           0 :         while (iTmpPtr > 0 && pszTmpPath[iTmpPtr - 1] != '/')
     300             :         {
     301           0 :             pszTmpPath[--iTmpPtr] = '\0';
     302             :         }
     303             : 
     304           0 :         if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) == 0)
     305           0 :             bValidPath = TRUE;
     306             :     }
     307             : 
     308           0 :     CPLAssert(iTmpPtr >= 0);
     309             : 
     310             :     /*-----------------------------------------------------------------
     311             :      * Assume that CWD is valid... so an empty path is a valid path
     312             :      *----------------------------------------------------------------*/
     313           0 :     if (iTmpPtr == 0)
     314           0 :         bValidPath = TRUE;
     315             : 
     316             :     /*-----------------------------------------------------------------
     317             :      * OK, now that we have a valid base, reconstruct the whole path
     318             :      * by scanning all the sub-directories.
     319             :      * If we get to a point where a path component does not exist then
     320             :      * we simply return the rest of the path as is.
     321             :      *----------------------------------------------------------------*/
     322           0 :     while (bValidPath && strlen(pszTmpPath) < (size_t)nTotalLen)
     323             :     {
     324           0 :         char **papszDir = VSIReadDir(pszTmpPath);
     325             :         int iEntry, iLastPartStart;
     326             : 
     327           0 :         iLastPartStart = iTmpPtr;
     328             : 
     329             :         /*-------------------------------------------------------------
     330             :          * Add one component to the current path
     331             :          *------------------------------------------------------------*/
     332           0 :         pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     333           0 :         iTmpPtr++;
     334           0 :         for (; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr] != '/'; iTmpPtr++)
     335             :         {
     336           0 :             pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     337             :         }
     338             : 
     339           0 :         while (iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/')
     340           0 :             iLastPartStart++;
     341             : 
     342             :         /*-------------------------------------------------------------
     343             :          * And do a case insensitive search in the current dir...
     344             :          *------------------------------------------------------------*/
     345           0 :         for (iEntry = 0; papszDir && papszDir[iEntry]; iEntry++)
     346             :         {
     347           0 :             if (EQUAL(pszTmpPath + iLastPartStart, papszDir[iEntry]))
     348             :             {
     349             :                 /* Fount it! */
     350             : #ifdef CSA_BUILD
     351             :                 // Silence false positive warning about overlapping buffers
     352             :                 memmove(pszTmpPath + iLastPartStart, papszDir[iEntry],
     353             :                         strlen(papszDir[iEntry]) + 1);
     354             : #else
     355           0 :                 strcpy(pszTmpPath + iLastPartStart, papszDir[iEntry]);
     356             : #endif
     357           0 :                 break;
     358             :             }
     359             :         }
     360             : 
     361           0 :         if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) != 0)
     362           0 :             bValidPath = FALSE;
     363             : 
     364           0 :         CSLDestroy(papszDir);
     365             :     }
     366             : 
     367             :     /*-----------------------------------------------------------------
     368             :      * We reached the last valid path component... just copy the rest
     369             :      * of the path as is.
     370             :      *----------------------------------------------------------------*/
     371           0 :     if (iTmpPtr < nTotalLen - 1)
     372             :     {
     373           0 :         strncpy(pszTmpPath + iTmpPtr, pszFname + iTmpPtr, nTotalLen - iTmpPtr);
     374             :     }
     375             : 
     376             :     /*-----------------------------------------------------------------
     377             :      * Update the source buffer and return.
     378             :      *----------------------------------------------------------------*/
     379           0 :     strcpy(pszFname, pszTmpPath);
     380           0 :     CPLFree(pszTmpPath);
     381             : 
     382           0 :     return pszFname;
     383             : }
     384             : 
     385             : /**********************************************************************
     386             :  *                          AVCPrintRealValue()
     387             :  *
     388             :  * Format a floating point value according to the specified coverage
     389             :  * precision (AVC_SINGLE/DOUBLE_PREC),  and append the formatted value
     390             :  * to the end of the pszBuf buffer.
     391             :  *
     392             :  * The function returns the number of characters added to the buffer.
     393             :  **********************************************************************/
     394           0 : int AVCPrintRealValue(char *pszBuf, size_t nBufLen, int nPrecision,
     395             :                       AVCFileType eType, double dValue)
     396             : {
     397             :     static int numExpDigits = -1;
     398           0 :     int nLen = 0;
     399             : 
     400             :     /* WIN32 systems' printf() for floating point output generates 3
     401             :      * digits exponents (ex: 1.23E+012), but E00 files must have 2 digits
     402             :      * exponents (ex: 1.23E+12).
     403             :      * Run a test (only once per prg execution) to establish the number
     404             :      * of exponent digits on the current platform.
     405             :      */
     406           0 :     if (numExpDigits == -1)
     407             :     {
     408             :         char szBuf[50];
     409             :         int i;
     410             : 
     411           0 :         CPLsnprintf(szBuf, sizeof(szBuf), "%10.7E", 123.45);
     412           0 :         numExpDigits = 0;
     413           0 :         for (i = (int)strlen(szBuf) - 1; i > 0; i--)
     414             :         {
     415           0 :             if (szBuf[i] == '+' || szBuf[i] == '-')
     416             :                 break;
     417           0 :             numExpDigits++;
     418             :         }
     419             :     }
     420             : 
     421             :     /* We will append the value at the end of the current buffer contents.
     422             :      */
     423           0 :     nBufLen -= strlen(pszBuf);
     424           0 :     pszBuf = pszBuf + strlen(pszBuf);
     425             : 
     426           0 :     if (dValue < 0.0)
     427             :     {
     428           0 :         *pszBuf = '-';
     429           0 :         dValue = -1.0 * dValue;
     430             :     }
     431             :     else
     432           0 :         *pszBuf = ' ';
     433             : 
     434             :     /* Just to make things more complicated, double values are
     435             :      * output in a different format in attribute tables than in
     436             :      * the other files!
     437             :      */
     438           0 :     if (nPrecision == AVC_FORMAT_DBF_FLOAT)
     439             :     {
     440             :         /* Float stored in DBF table in PC coverages */
     441           0 :         CPLsnprintf(pszBuf + 1, nBufLen - 1, "%9.6E", dValue);
     442           0 :         nLen = 13;
     443             :     }
     444           0 :     else if (nPrecision == AVC_DOUBLE_PREC && eType == AVCFileTABLE)
     445             :     {
     446           0 :         CPLsnprintf(pszBuf + 1, nBufLen - 1, "%20.17E", dValue);
     447           0 :         nLen = 24;
     448             :     }
     449           0 :     else if (nPrecision == AVC_DOUBLE_PREC)
     450             :     {
     451           0 :         CPLsnprintf(pszBuf + 1, nBufLen - 1, "%17.14E", dValue);
     452           0 :         nLen = 21;
     453             :     }
     454             :     else
     455             :     {
     456           0 :         CPLsnprintf(pszBuf + 1, nBufLen - 1, "%10.7E", dValue);
     457           0 :         nLen = 14;
     458             :     }
     459             : 
     460             :     /* Adjust number of exponent digits if necessary
     461             :      */
     462           0 :     if (numExpDigits > 2)
     463             :     {
     464             :         int n;
     465           0 :         n = (int)strlen(pszBuf);
     466             : 
     467           0 :         pszBuf[n - numExpDigits] = pszBuf[n - 2];
     468           0 :         pszBuf[n - numExpDigits + 1] = pszBuf[n - 1];
     469           0 :         pszBuf[n - numExpDigits + 2] = '\0';
     470             :     }
     471             : 
     472             :     /* Just make sure that the actual output length is what we expected.
     473             :      */
     474           0 :     CPLAssert(strlen(pszBuf) == (size_t)nLen);
     475             : 
     476           0 :     return nLen;
     477             : }

Generated by: LCOV version 1.14