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

Generated by: LCOV version 1.14