LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_utils.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 165 78 47.3 %
Date: 2012-12-26 Functions: 11 5 45.5 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_utils.cpp,v 1.26 2011-06-16 15:53:12 fwarmerdam Exp $
       3                 :  *
       4                 :  * Name:     mitab_utils.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Misc. util. functions for the library
       8                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9                 :  *
      10                 :  **********************************************************************
      11                 :  * Copyright (c) 1999-2001, 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: mitab_utils.cpp,v $
      33                 :  * Revision 1.26  2011-06-16 15:53:12  fwarmerdam
      34                 :  * improve TABBasename() for filenames with an embedded dot (gdal #4123)
      35                 :  *
      36                 :  * Revision 1.25  2010-07-07 19:00:15  aboudreault
      37                 :  * Cleanup Win32 Compile Warnings (GDAL bug #2930)
      38                 :  *
      39                 :  * Revision 1.24  2010-07-05 17:41:07  aboudreault
      40                 :  * Fixed TABCleanFieldName() function should allow char '#' in field name (bug 2231)
      41                 :  *
      42                 :  * Revision 1.23  2010-01-07 20:39:12  aboudreault
      43                 :  * Added support to handle duplicate field names, Added validation to check if a field name start with a number (bug 2141)
      44                 :  *
      45                 :  * Revision 1.22  2008-07-21 16:04:58  dmorissette
      46                 :  * Fixed const char * warnings with GCC 4.3 (GDAL ticket #2325)
      47                 :  *
      48                 :  * Revision 1.21  2006/12/01 16:53:15  dmorissette
      49                 :  * Wrapped <mbctype.h> stuff with !defined(WIN32CE) (done by mloskot in OGR)
      50                 :  *
      51                 :  * Revision 1.20  2005/08/07 21:02:14  fwarmerdam
      52                 :  * avoid warnings about testing for characters > 255.
      53                 :  *
      54                 :  * Revision 1.19  2004/06/30 20:29:04  dmorissette
      55                 :  * Fixed refs to old address danmo@videotron.ca
      56                 :  *
      57                 :  * Revision 1.18  2002/08/28 14:19:22  warmerda
      58                 :  * fix TABGetBasename() for mixture of path divider types like 'mi/abc\def.tab'
      59                 :  *
      60                 :  * Revision 1.17  2001/06/27 19:52:54  warmerda
      61                 :  * avoid multi byte support if _WIN32 and unix defined for cygwin support
      62                 :  *
      63                 :  * Revision 1.16  2001/01/23 21:23:42  daniel
      64                 :  * Added projection bounds lookup table, called from TABFile::SetProjInfo()
      65                 :  *
      66                 :  * Revision 1.15  2001/01/19 06:06:18  daniel
      67                 :  * Don't filter chars in TABCleanFieldName() if we're on a DBCS system
      68                 :  *
      69                 :  * Revision 1.14  2000/09/28 16:39:44  warmerda
      70                 :  * avoid warnings for unused, and unitialized variables
      71                 :  *
      72                 :  * Revision 1.13  2000/09/20 18:35:51  daniel
      73                 :  * Fixed TABAdjustFilenameExtension() to also handle basename and path
      74                 :  * using TABAdjustCaseSensitiveFilename()
      75                 :  *
      76                 :  * Revision 1.12  2000/04/18 04:19:22  daniel
      77                 :  * Now accept extended chars with accents in TABCleanFieldName()
      78                 :  *
      79                 :  * Revision 1.11  2000/02/28 17:08:56  daniel
      80                 :  * Avoid using isalnum() in TABCleanFieldName
      81                 :  *
      82                 :  * Revision 1.10  2000/02/18 20:46:35  daniel
      83                 :  * Added TABCleanFieldName()
      84                 :  *
      85                 :  * Revision 1.9  2000/01/15 22:30:45  daniel
      86                 :  * Switch to MIT/X-Consortium OpenSource license
      87                 :  *
      88                 :  * Revision 1.8  2000/01/14 23:46:59  daniel
      89                 :  * Added TABEscapeString()/TABUnEscapeString()
      90                 :  *
      91                 :  * Revision 1.7  1999/12/16 06:10:24  daniel
      92                 :  * TABGetBasename(): make sure last '/' of path is removed
      93                 :  *
      94                 :  * Revision 1.6  1999/12/14 02:08:37  daniel
      95                 :  * Added TABGetBasename() + TAB_CSLLoad()
      96                 :  *
      97                 :  * Revision 1.5  1999/11/08 04:30:59  stephane
      98                 :  * Modify TABGenerateArc()
      99                 :  *
     100                 :  * Revision 1.4  1999/09/29 17:59:21  daniel
     101                 :  * Definition for PI was gone on Windows
     102                 :  *
     103                 :  * Revision 1.3  1999/09/16 02:39:17  daniel
     104                 :  * Completed read support for most feature types
     105                 :  *
     106                 :  * Revision 1.2  1999/07/12 05:44:59  daniel
     107                 :  * Added include math.h for VC++
     108                 :  *
     109                 :  * Revision 1.1  1999/07/12 04:18:25  daniel
     110                 :  * Initial checkin
     111                 :  *
     112                 :  **********************************************************************/
     113                 : 
     114                 : #include "mitab.h"
     115                 : #include "mitab_utils.h"
     116                 : #include "cpl_conv.h"
     117                 : 
     118                 : #include <math.h>       /* sin()/cos() */
     119                 : #include <ctype.h>      /* toupper()/tolower() */
     120                 : 
     121                 : #if defined(_WIN32) && !defined(unix) && !defined(WIN32CE)
     122                 : #  include <mbctype.h>  /* Multibyte chars stuff */
     123                 : #endif
     124                 : 
     125                 : 
     126                 : /**********************************************************************
     127                 :  *                       TABGenerateArc()
     128                 :  *
     129                 :  * Generate the coordinates for an arc and ADD the coordinates to the 
     130                 :  * geometry object.  If the geometry already contains some points then
     131                 :  * these won't be lost.
     132                 :  *
     133                 :  * poLine can be a OGRLineString or one of its derived classes, such as 
     134                 :  *        OGRLinearRing
     135                 :  * numPoints is the number of points to generate.
     136                 :  * Angles are specified in radians, valid values are in the range [0..2*PI]
     137                 :  *
     138                 :  * Arcs are always generated counterclockwise, even if StartAngle > EndAngle
     139                 :  *
     140                 :  * Returns 0 on success, -1 on error.
     141                 :  **********************************************************************/
     142               0 : int TABGenerateArc(OGRLineString *poLine, int numPoints, 
     143                 :                    double dCenterX, double dCenterY,
     144                 :                    double dXRadius, double dYRadius,
     145                 :                    double dStartAngle, double dEndAngle)
     146                 : {
     147               0 :     double dX, dY, dAngleStep, dAngle=0.0;
     148                 :     int i;
     149                 : 
     150                 :     // Adjust angles to go counterclockwise
     151               0 :     if (dEndAngle < dStartAngle)
     152               0 :         dEndAngle += 2.0*PI;
     153                 : 
     154               0 :     dAngleStep = (dEndAngle-dStartAngle)/(numPoints-1.0);
     155                 : 
     156               0 :     for(i=0; i<numPoints; i++)
     157                 :     {
     158               0 :         dAngle = (dStartAngle + (double)i*dAngleStep);
     159               0 :         dX = dCenterX + dXRadius*cos(dAngle);
     160               0 :         dY = dCenterY + dYRadius*sin(dAngle);
     161               0 :         poLine->addPoint(dX, dY);
     162                 :     }
     163                 : 
     164                 :     // Complete the arc with the last EndAngle, to make sure that 
     165                 :     // the arc is correcly close.
     166                 : 
     167               0 :     dX = dCenterX + dXRadius*cos(dAngle);
     168               0 :     dY = dCenterY + dYRadius*sin(dAngle);
     169               0 :     poLine->addPoint(dX,dY);
     170                 : 
     171                 : 
     172               0 :     return 0;
     173                 : }
     174                 : 
     175                 : 
     176                 : /**********************************************************************
     177                 :  *                       TABCloseRing()
     178                 :  *
     179                 :  * Check if a ring is closed, and add a point to close it if necessary.
     180                 :  *
     181                 :  * Returns 0 on success, -1 on error.
     182                 :  **********************************************************************/
     183               0 : int TABCloseRing(OGRLineString *poRing)
     184                 : {
     185               0 :     if ( poRing->getNumPoints() > 0 && !poRing->get_IsClosed() )
     186                 :     {
     187               0 :         poRing->addPoint(poRing->getX(0), poRing->getY(0));
     188                 :     }
     189                 : 
     190               0 :     return 0;
     191                 : }
     192                 : 
     193                 : /**********************************************************************
     194                 :  *                     TABAdjustCaseSensitiveFilename()
     195                 :  *
     196                 :  * Scan a filename and its path, adjust uppercase/lowercases if
     197                 :  * necessary.
     198                 :  *
     199                 :  * Returns TRUE if file found, or FALSE if it could not be located with
     200                 :  * a case-insensitive search.
     201                 :  *
     202                 :  * This function works on the original buffer and returns a reference to it.
     203                 :  * It does nothing on Windows systems where filenames are not case sensitive.
     204                 :  **********************************************************************/
     205              32 : GBool TABAdjustCaseSensitiveFilename(char *pszFname)
     206                 : {
     207                 : 
     208                 : #ifdef _WIN32
     209                 :     /*-----------------------------------------------------------------
     210                 :      * Nothing to do on Windows
     211                 :      *----------------------------------------------------------------*/
     212                 :     return TRUE;
     213                 : 
     214                 : #else
     215                 :     /*-----------------------------------------------------------------
     216                 :      * Unix case.
     217                 :      *----------------------------------------------------------------*/
     218                 :     VSIStatBuf  sStatBuf;
     219              32 :     char        *pszTmpPath = NULL;
     220                 :     int         nTotalLen, iTmpPtr;
     221                 :     GBool       bValidPath;
     222                 : 
     223                 :     /*-----------------------------------------------------------------
     224                 :      * First check if the filename is OK as is.
     225                 :      *----------------------------------------------------------------*/
     226              32 :     if (VSIStat(pszFname, &sStatBuf) == 0)
     227                 :     {
     228               0 :         return TRUE;
     229                 :     }
     230                 : 
     231                 :     /*-----------------------------------------------------------------
     232                 :      * OK, file either does not exist or has the wrong cases... we'll
     233                 :      * go backwards until we find a portion of the path that is valid.
     234                 :      *----------------------------------------------------------------*/
     235              32 :     pszTmpPath = CPLStrdup(pszFname);
     236              32 :     nTotalLen = strlen(pszTmpPath);
     237              32 :     iTmpPtr = nTotalLen;
     238              32 :     bValidPath = FALSE;
     239                 : 
     240              96 :     while(iTmpPtr > 0 && !bValidPath)
     241                 :     {
     242                 :         /*-------------------------------------------------------------
     243                 :          * Move back to the previous '/' separator
     244                 :          *------------------------------------------------------------*/
     245              32 :         pszTmpPath[--iTmpPtr] = '\0';
     246             437 :         while( iTmpPtr > 0 && pszTmpPath[iTmpPtr-1] != '/' )
     247                 :         {
     248             373 :             pszTmpPath[--iTmpPtr] = '\0';
     249                 :         }
     250                 : 
     251              32 :         if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) == 0)
     252              28 :             bValidPath = TRUE;
     253                 :     }
     254                 : 
     255              32 :     CPLAssert(iTmpPtr >= 0);
     256                 : 
     257                 :     /*-----------------------------------------------------------------
     258                 :      * Assume that CWD is valid... so an empty path is a valid path
     259                 :      *----------------------------------------------------------------*/
     260              32 :     if (iTmpPtr == 0)
     261               4 :         bValidPath = TRUE;
     262                 : 
     263                 :     /*-----------------------------------------------------------------
     264                 :      * OK, now that we have a valid base, reconstruct the whole path
     265                 :      * by scanning all the sub-directories.  
     266                 :      * If we get to a point where a path component does not exist then
     267                 :      * we simply return the rest of the path as is.
     268                 :      *----------------------------------------------------------------*/
     269              96 :     while(bValidPath && (int)strlen(pszTmpPath) < nTotalLen)
     270                 :     {
     271              32 :         char    **papszDir=NULL;
     272                 :         int     iEntry, iLastPartStart;
     273                 : 
     274              32 :         iLastPartStart = iTmpPtr;
     275              32 :         papszDir = CPLReadDir(pszTmpPath);
     276                 : 
     277                 :         /*-------------------------------------------------------------
     278                 :          * Add one component to the current path
     279                 :          *------------------------------------------------------------*/
     280              32 :         pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     281              32 :         iTmpPtr++;
     282             405 :         for( ; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr]!='/'; iTmpPtr++)
     283                 :         {
     284             373 :             pszTmpPath[iTmpPtr] = pszFname[iTmpPtr];
     285                 :         }
     286                 : 
     287              64 :         while(iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/')
     288               0 :             iLastPartStart++;
     289                 : 
     290                 :         /*-------------------------------------------------------------
     291                 :          * And do a case insensitive search in the current dir...
     292                 :          *------------------------------------------------------------*/
     293             956 :         for(iEntry=0; papszDir && papszDir[iEntry]; iEntry++)
     294                 :         {
     295             924 :             if (EQUAL(pszTmpPath+iLastPartStart, papszDir[iEntry]))
     296                 :             {
     297                 :                 /* Fount it! */
     298               0 :                 strcpy(pszTmpPath+iLastPartStart, papszDir[iEntry]);
     299               0 :                 break;
     300                 :             }
     301                 :         }
     302                 : 
     303              32 :         if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) != 0)
     304              32 :             bValidPath = FALSE;
     305                 : 
     306              32 :         CSLDestroy(papszDir);
     307                 :     }
     308                 : 
     309                 :     /*-----------------------------------------------------------------
     310                 :      * We reached the last valid path component... just copy the rest
     311                 :      * of the path as is.
     312                 :      *----------------------------------------------------------------*/
     313              32 :     if (iTmpPtr < nTotalLen-1)
     314                 :     {
     315               0 :         strncpy(pszTmpPath+iTmpPtr, pszFname+iTmpPtr, nTotalLen-iTmpPtr);
     316                 :     }
     317                 : 
     318                 :     /*-----------------------------------------------------------------
     319                 :      * Update the source buffer and return.
     320                 :      *----------------------------------------------------------------*/
     321              32 :     strcpy(pszFname, pszTmpPath);
     322              32 :     CPLFree(pszTmpPath);
     323                 : 
     324              32 :     return bValidPath;
     325                 : 
     326                 : #endif
     327                 : }
     328                 : 
     329                 : 
     330                 : 
     331                 : 
     332                 : /**********************************************************************
     333                 :  *                       TABAdjustFilenameExtension()
     334                 :  *
     335                 :  * Because Unix filenames are case sensitive and MapInfo datasets often have
     336                 :  * mixed cases filenames, we use this function to find the right filename
     337                 :  * to use ot open a specific file.
     338                 :  *
     339                 :  * This function works directly on the source string, so the filename it
     340                 :  * contains at the end of the call is the one that should be used.
     341                 :  *
     342                 :  * Returns TRUE if one of the extensions worked, and FALSE otherwise.
     343                 :  * If none of the extensions worked then the original extension will NOT be
     344                 :  * restored.
     345                 :  **********************************************************************/
     346              78 : GBool TABAdjustFilenameExtension(char *pszFname)
     347                 : {
     348                 :     VSIStatBuf  sStatBuf;
     349                 :     int         i;
     350                 :     
     351                 :     /*-----------------------------------------------------------------
     352                 :      * First try using filename as provided
     353                 :      *----------------------------------------------------------------*/
     354              78 :     if (VSIStat(pszFname, &sStatBuf) == 0)
     355                 :     {
     356              46 :         return TRUE;
     357                 :     }     
     358                 : 
     359                 :     /*-----------------------------------------------------------------
     360                 :      * Try using uppercase extension (we assume that fname contains a '.')
     361                 :      *----------------------------------------------------------------*/
     362             125 :     for(i = strlen(pszFname)-1; i >= 0 && pszFname[i] != '.'; i--)
     363                 :     {
     364              93 :         pszFname[i] = (char)toupper(pszFname[i]);
     365                 :     }
     366                 : 
     367              32 :     if (VSIStat(pszFname, &sStatBuf) == 0)
     368                 :     {
     369               0 :         return TRUE;
     370                 :     }     
     371                 :     
     372                 :     /*-----------------------------------------------------------------
     373                 :      * Try using lowercase extension
     374                 :      *----------------------------------------------------------------*/
     375             125 :     for(i = strlen(pszFname)-1; i >= 0 && pszFname[i] != '.'; i--)
     376                 :     {
     377              93 :         pszFname[i] = (char)tolower(pszFname[i]);
     378                 :     }
     379                 : 
     380              32 :     if (VSIStat(pszFname, &sStatBuf) == 0)
     381                 :     {
     382               0 :         return TRUE;
     383                 :     }     
     384                 : 
     385                 :     /*-----------------------------------------------------------------
     386                 :      * None of the extensions worked!  
     387                 :      * Try adjusting cases in the whole path and filename 
     388                 :      *----------------------------------------------------------------*/
     389              32 :     return TABAdjustCaseSensitiveFilename(pszFname);
     390                 : }
     391                 : 
     392                 : 
     393                 : 
     394                 : /**********************************************************************
     395                 :  *                       TABGetBasename()
     396                 :  *
     397                 :  * Extract the basename part of a complete file path.
     398                 :  *
     399                 :  * Returns a newly allocated string without the leading path (dirs) and
     400                 :  * the extenstion.  The returned string should be freed using CPLFree().
     401                 :  **********************************************************************/
     402              26 : char *TABGetBasename(const char *pszFname)
     403                 : {
     404              26 :     const char *pszTmp = NULL;
     405                 : 
     406                 :     /*-----------------------------------------------------------------
     407                 :      * Skip leading path or use whole name if no path dividers are
     408                 :      * encountered.
     409                 :      *----------------------------------------------------------------*/
     410              26 :     pszTmp = pszFname + strlen(pszFname) - 1;
     411             377 :     while ( pszTmp != pszFname 
     412                 :             && *pszTmp != '/' && *pszTmp != '\\' ) 
     413             325 :         pszTmp--;
     414                 : 
     415              26 :     if( pszTmp != pszFname )
     416              24 :         pszTmp++;
     417                 : 
     418                 :     /*-----------------------------------------------------------------
     419                 :      * Now allocate our own copy and remove extension
     420                 :      *----------------------------------------------------------------*/
     421              26 :     char *pszBasename = CPLStrdup(pszTmp);
     422                 :     int i;
     423             104 :     for(i=strlen(pszBasename)-1; i >= 0; i-- )
     424                 :     {
     425             104 :         if (pszBasename[i] == '.')
     426                 :         {
     427              26 :             pszBasename[i] = '\0';
     428              26 :             break;
     429                 :         }
     430                 :     }
     431                 : 
     432              26 :     return pszBasename;
     433                 : }
     434                 : 
     435                 : 
     436                 : 
     437                 : /**********************************************************************
     438                 :  *                       TAB_CSLLoad()
     439                 :  *
     440                 :  * Same as CSLLoad(), but does not produce an error if it fails... it
     441                 :  * just returns NULL silently instead.
     442                 :  *
     443                 :  * Load a test file into a stringlist.
     444                 :  *
     445                 :  * Lines are limited in length by the size fo the CPLReadLine() buffer.
     446                 :  **********************************************************************/
     447               3 : char **TAB_CSLLoad(const char *pszFname)
     448                 : {
     449                 :     FILE        *fp;
     450                 :     const char  *pszLine;
     451               3 :     char        **papszStrList=NULL;
     452                 : 
     453               3 :     fp = VSIFOpen(pszFname, "rt");
     454                 : 
     455               3 :     if (fp)
     456                 :     {
     457              38 :         while(!VSIFEof(fp))
     458                 :         {
     459              32 :             if ( (pszLine = CPLReadLine(fp)) != NULL )
     460                 :             {
     461              29 :                 papszStrList = CSLAddString(papszStrList, pszLine);
     462                 :             }
     463                 :         }
     464                 : 
     465               3 :         VSIFClose(fp);
     466                 :     }
     467                 : 
     468               3 :     return papszStrList;
     469                 : }
     470                 : 
     471                 : 
     472                 : 
     473                 : /**********************************************************************
     474                 :  *                       TABUnEscapeString()
     475                 :  *
     476                 :  * Convert a string that can possibly contain escaped "\n" chars in
     477                 :  * into into a new one with binary newlines in it.
     478                 :  *
     479                 :  * Tries to work on hte original buffer unless bSrcIsConst=TRUE, in
     480                 :  * which case the original is always untouched and a copy is allocated
     481                 :  * ONLY IF NECESSARY.  This means that the caller should compare the
     482                 :  * return value and the source (pszString) to see if a copy was returned,
     483                 :  * in which case the caller becomes responsible of freeing both the
     484                 :  * source and the copy.
     485                 :  **********************************************************************/
     486               0 : char *TABUnEscapeString(char *pszString, GBool bSrcIsConst)
     487                 : {
     488                 : 
     489                 :     /*-----------------------------------------------------------------
     490                 :      * First check if we need to do any replacement
     491                 :      *----------------------------------------------------------------*/
     492               0 :     if (pszString == NULL || strstr(pszString, "\\n") == NULL)
     493                 :     {
     494               0 :         return pszString;
     495                 :     }
     496                 : 
     497                 :     /*-----------------------------------------------------------------
     498                 :      * Yes, we need to replace at least one "\n"
     499                 :      * We try to work on the original buffer unless we have bSrcIsConst=TRUE
     500                 :      *
     501                 :      * Note that we do not worry about freeing the source buffer when we
     502                 :      * return a copy... it is up to the caller to decide if he needs to 
     503                 :      * free the source based on context and by comparing pszString with 
     504                 :      * the returned pointer (pszWorkString) to see if they are identical.
     505                 :      *----------------------------------------------------------------*/
     506               0 :     char *pszWorkString = NULL;
     507               0 :     int i =0;
     508               0 :     int j =0;
     509                 : 
     510               0 :     if (bSrcIsConst)
     511                 :     {
     512                 :         // We have to create a copy to work on.
     513                 :         pszWorkString = (char *)CPLMalloc(sizeof(char) * 
     514               0 :                                           (strlen(pszString) +1));
     515                 :     }
     516                 :     else
     517                 :     {
     518                 :         // We'll work on the original.
     519               0 :         pszWorkString = pszString;
     520                 :     }
     521                 : 
     522                 : 
     523               0 :     while (pszString[i])
     524                 :     {
     525               0 :         if (pszString[i] =='\\' && 
     526               0 :             pszString[i+1] == 'n')
     527                 :         {
     528               0 :             pszWorkString[j++] = '\n';
     529               0 :             i+= 2;
     530                 :         }
     531               0 :         else if (pszString[i] =='\\' && 
     532               0 :                  pszString[i+1] == '\\')
     533                 :         {
     534               0 :             pszWorkString[j++] = '\\';
     535               0 :             i+= 2;
     536                 :         }
     537                 :         else
     538                 :         {
     539               0 :             pszWorkString[j++] = pszString[i++];
     540                 :         }
     541                 :     }
     542               0 :     pszWorkString[j++] = '\0';
     543                 :    
     544               0 :     return pszWorkString;
     545                 : }
     546                 : 
     547                 : /**********************************************************************
     548                 :  *                       TABEscapeString()
     549                 :  *
     550                 :  * Convert a string that can possibly contain binary "\n" chars in
     551                 :  * into into a new one with escaped newlines ("\\" + "n") in it.
     552                 :  *
     553                 :  * The function returns the original string pointer if it did not need to
     554                 :  * be modified, or a copy that has to be freed by the caller if the
     555                 :  * string had to be modified.
     556                 :  *
     557                 :  * It is up to the caller to decide if he needs to free the returned 
     558                 :  * string by comparing the source (pszString) pointer with the returned
     559                 :  * pointer (pszWorkString) to see if they are identical.
     560                 :  **********************************************************************/
     561               0 : char *TABEscapeString(char *pszString)
     562                 : {
     563                 :     /*-----------------------------------------------------------------
     564                 :      * First check if we need to do any replacement
     565                 :      *----------------------------------------------------------------*/
     566               0 :     if (pszString == NULL || strchr(pszString, '\n') == NULL)
     567                 :     {
     568               0 :         return pszString;
     569                 :     }
     570                 : 
     571                 :     /*-----------------------------------------------------------------
     572                 :      * OK, we need to do some replacements... alloc a copy big enough
     573                 :      * to hold the worst possible case
     574                 :      *----------------------------------------------------------------*/
     575                 :     char *pszWorkString = (char *)CPLMalloc(2*sizeof(char) * 
     576               0 :                                             (strlen(pszString) +1));
     577                 : 
     578               0 :     int i =0;
     579               0 :     int j =0;
     580                 : 
     581               0 :     while (pszString[i])
     582                 :     {
     583               0 :         if (pszString[i] =='\n')
     584                 :         {
     585               0 :             pszWorkString[j++] = '\\';
     586               0 :             pszWorkString[j++] = 'n';
     587               0 :             i++;
     588                 :         }
     589               0 :         else if (pszString[i] =='\\')
     590                 :         {
     591               0 :             pszWorkString[j++] = '\\';
     592               0 :             pszWorkString[j++] = '\\';
     593               0 :             i++;
     594                 :         }
     595                 :         else
     596                 :         {
     597               0 :             pszWorkString[j++] = pszString[i++];
     598                 :         }
     599                 :     }
     600               0 :     pszWorkString[j++] = '\0';
     601                 : 
     602               0 :     return pszWorkString;
     603                 : }
     604                 : 
     605                 : /**********************************************************************
     606                 :  *                       TABCleanFieldName()
     607                 :  *
     608                 :  * Return a copy of pszSrcName that contains only valid characters for a
     609                 :  * TAB field name.  All invalid characters are replaced by '_'.
     610                 :  *
     611                 :  * The returned string should be freed by the caller.
     612                 :  **********************************************************************/
     613              76 : char *TABCleanFieldName(const char *pszSrcName)
     614                 : {
     615                 :     char *pszNewName;
     616              76 :     int numInvalidChars = 0;
     617                 : 
     618              76 :     pszNewName = CPLStrdup(pszSrcName);
     619                 : 
     620              76 :     if (strlen(pszNewName) > 31)
     621                 :     {
     622               0 :         pszNewName[31] = '\0';
     623                 :         CPLError(CE_Warning, TAB_WarningInvalidFieldName,
     624                 :                  "Field name '%s' is longer than the max of 31 characters. "
     625               0 :                  "'%s' will be used instead.", pszSrcName, pszNewName);
     626                 :     }
     627                 : 
     628                 : #if defined(_WIN32) && !defined(unix) && !defined(WIN32CE)
     629                 :     /*-----------------------------------------------------------------
     630                 :      * On Windows, check if we're using a double-byte codepage, and
     631                 :      * if so then just keep the field name as is... 
     632                 :      *----------------------------------------------------------------*/
     633                 :     if (_getmbcp() != 0)
     634                 :         return pszNewName;
     635                 : #endif
     636                 : 
     637                 :     /*-----------------------------------------------------------------
     638                 :      * According to the MapInfo User's Guide (p. 240, v5.5)
     639                 :      * New Table Command:
     640                 :      *  Name:
     641                 :      * Displays the field name in the name box. You can also enter new field
     642                 :      * names here. Defaults are Field1, Field2, etc. A field name can contain
     643                 :      * up to 31 alphanumeric characters. Use letters, numbers, and the 
     644                 :      * underscore. Do not use spaces; instead, use the underscore character
     645                 :      * (_) to separate words in a field name. Use upper and lower case for
     646                 :      * legibility, but MapInfo is not case-sensitive.
     647                 :      *
     648                 :      * It was also verified that extended chars with accents are also 
     649                 :      * accepted.
     650                 :      *----------------------------------------------------------------*/
     651             519 :     for(int i=0; pszSrcName && pszSrcName[i] != '\0'; i++)
     652                 :     {
     653             443 :         if ( pszSrcName[i]=='#' )
     654                 :   {
     655               0 :             if (i == 0)
     656                 :             {
     657               0 :                 pszNewName[i] = '_';
     658               0 :                 numInvalidChars++;
     659                 :             }
     660                 :         }
     661            2375 :         else if ( !( pszSrcName[i] == '_' ||
     662             718 :                      (i!=0 && pszSrcName[i]>='0' && pszSrcName[i]<='9') || 
     663             526 :                      (pszSrcName[i]>='a' && pszSrcName[i]<='z') || 
     664             688 :                      (pszSrcName[i]>='A' && pszSrcName[i]<='Z') ||
     665               0 :                      (GByte)pszSrcName[i]>=192 ) )
     666                 :         {
     667               0 :             pszNewName[i] = '_';
     668               0 :             numInvalidChars++;
     669                 :         }
     670                 :     }
     671                 : 
     672              76 :     if (numInvalidChars > 0)
     673                 :     {
     674                 :         CPLError(CE_Warning, TAB_WarningInvalidFieldName,
     675                 :                  "Field name '%s' contains invalid characters. "
     676               0 :                  "'%s' will be used instead.", pszSrcName, pszNewName);
     677                 :     }
     678                 : 
     679              76 :     return pszNewName;
     680                 : }
     681                 : 
     682                 : 
     683                 : /**********************************************************************
     684                 :  * MapInfo Units string to numeric ID conversion
     685                 :  **********************************************************************/
     686                 : typedef struct 
     687                 : {
     688                 :     int         nUnitId;
     689                 :     const char *pszAbbrev;
     690                 : } MapInfoUnitsInfo;
     691                 : 
     692                 : static MapInfoUnitsInfo gasUnitsList[] = 
     693                 : {
     694                 :     {0, "mi"},
     695                 :     {1, "km"},
     696                 :     {2, "in"},
     697                 :     {3, "ft"},
     698                 :     {4, "yd"},
     699                 :     {5, "mm"},
     700                 :     {6, "cm"},
     701                 :     {7, "m"},
     702                 :     {8, "survey ft"},
     703                 :     {9, "nmi"},
     704                 :     {30, "li"},
     705                 :     {31, "ch"},
     706                 :     {32, "rd"},
     707                 :     {-1, NULL}
     708                 : };
     709                 : 
     710                 : 
     711                 : /**********************************************************************
     712                 :  *                       TABUnitIdToString()
     713                 :  *
     714                 :  * Return the MIF units name for specified units id.
     715                 :  * Return "" if no match found.
     716                 :  *
     717                 :  * The returned string should not be freed by the caller.
     718                 :  **********************************************************************/
     719               0 : const char *TABUnitIdToString(int nId)
     720                 : {
     721                 :     MapInfoUnitsInfo *psList;
     722                 : 
     723               0 :     psList = gasUnitsList;
     724                 : 
     725               0 :     while(psList->nUnitId != -1)
     726                 :     {
     727               0 :         if (psList->nUnitId == nId) 
     728               0 :             return psList->pszAbbrev;
     729               0 :         psList++;
     730                 :     }
     731                 : 
     732               0 :     return "";
     733                 : }
     734                 : 
     735                 : /**********************************************************************
     736                 :  *                       TABUnitIdFromString()
     737                 :  *
     738                 :  * Return the units ID for specified MIF units name
     739                 :  *
     740                 :  * Returns -1 if no match found.
     741                 :  **********************************************************************/
     742               0 : int TABUnitIdFromString(const char *pszName)
     743                 : {
     744                 :     MapInfoUnitsInfo *psList;
     745                 : 
     746               0 :     psList = gasUnitsList;
     747                 : 
     748               0 :     while(psList->nUnitId != -1)
     749                 :     {
     750               0 :         if (EQUAL(psList->pszAbbrev, pszName)) 
     751               0 :             return psList->nUnitId;
     752               0 :         psList++;
     753                 :     }
     754                 : 
     755               0 :     return -1;
     756                 : }
     757                 : 

Generated by: LCOV version 1.7