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: 2024-11-21 22:18:42 Functions: 5 7 71.4 %

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

Generated by: LCOV version 1.14