LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_imapinfofile.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 250 279 89.6 %
Date: 2024-05-05 22:37:24 Functions: 16 19 84.2 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     mitab_imapinfo
       4             :  * Project:  MapInfo mid/mif Tab Read/Write library
       5             :  * Language: C++
       6             :  * Purpose:  Implementation of the IMapInfoFile class, super class of
       7             :  *           of MIFFile and TABFile
       8             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9             :  *
      10             :  **********************************************************************
      11             :  * Copyright (c) 1999-2008, Daniel Morissette
      12             :  * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
      13             :  *
      14             :  * Permission is hereby granted, free of charge, to any person obtaining a
      15             :  * copy of this software and associated documentation files (the "Software"),
      16             :  * to deal in the Software without restriction, including without limitation
      17             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18             :  * and/or sell copies of the Software, and to permit persons to whom the
      19             :  * Software is furnished to do so, subject to the following conditions:
      20             :  *
      21             :  * The above copyright notice and this permission notice shall be included
      22             :  * in all copies or substantial portions of the Software.
      23             :  *
      24             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      25             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      27             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30             :  * DEALINGS IN THE SOFTWARE.
      31             :  **********************************************************************/
      32             : 
      33             : #include "cpl_port.h"
      34             : #include "mitab.h"
      35             : 
      36             : #include <cassert>
      37             : #include <cctype>
      38             : #include <cstring>
      39             : #include <algorithm>
      40             : 
      41             : #include "cpl_conv.h"
      42             : #include "cpl_error.h"
      43             : #include "cpl_vsi.h"
      44             : #include "mitab_priv.h"
      45             : #include "mitab_utils.h"
      46             : #include "ogr_core.h"
      47             : #include "ogr_feature.h"
      48             : #include "ogr_geometry.h"
      49             : 
      50             : #ifdef __HP_aCC
      51             : #include <wchar.h> /* iswspace() */
      52             : #else
      53             : #include <wctype.h> /* iswspace() */
      54             : #endif
      55             : 
      56             : /**********************************************************************
      57             :  *                   IMapInfoFile::IMapInfoFile()
      58             :  *
      59             :  * Constructor.
      60             :  **********************************************************************/
      61        2375 : IMapInfoFile::IMapInfoFile(GDALDataset *poDS)
      62             :     : m_poDS(poDS), m_nCurFeatureId(0), m_poCurFeature(nullptr),
      63        2375 :       m_bBoundsSet(FALSE), m_pszCharset(nullptr)
      64             : {
      65        2375 : }
      66             : 
      67             : /**********************************************************************
      68             :  *                   IMapInfoFile::~IMapInfoFile()
      69             :  *
      70             :  * Destructor.
      71             :  **********************************************************************/
      72        2375 : IMapInfoFile::~IMapInfoFile()
      73             : {
      74        2375 :     if (m_poCurFeature)
      75             :     {
      76           0 :         delete m_poCurFeature;
      77           0 :         m_poCurFeature = nullptr;
      78             :     }
      79             : 
      80        2375 :     CPLFree(m_pszCharset);
      81        2375 :     m_pszCharset = nullptr;
      82        2375 : }
      83             : 
      84             : /**********************************************************************
      85             :  *                   IMapInfoFile::Open()
      86             :  *
      87             :  * Compatibility layer with new interface.
      88             :  * Return 0 on success, -1 in case of failure.
      89             :  **********************************************************************/
      90             : 
      91           0 : int IMapInfoFile::Open(const char *pszFname, const char *pszAccess,
      92             :                        GBool bTestOpenNoError, const char *pszCharset)
      93             : {
      94             :     // cppcheck-suppress nullPointer
      95           0 :     if (STARTS_WITH_CI(pszAccess, "r"))
      96           0 :         return Open(pszFname, TABRead, bTestOpenNoError, pszCharset);
      97           0 :     else if (STARTS_WITH_CI(pszAccess, "w"))
      98           0 :         return Open(pszFname, TABWrite, bTestOpenNoError, pszCharset);
      99             :     else
     100             :     {
     101           0 :         CPLError(CE_Failure, CPLE_FileIO,
     102             :                  "Open() failed: access mode \"%s\" not supported", pszAccess);
     103           0 :         return -1;
     104             :     }
     105             : }
     106             : 
     107             : /**********************************************************************
     108             :  *                   IMapInfoFile::SmartOpen()
     109             :  *
     110             :  * Use this static method to automatically open any flavor of MapInfo
     111             :  * dataset.  This method will detect the file type, create an object
     112             :  * of the right type, and open the file.
     113             :  *
     114             :  * Call GetFileClass() on the returned object if you need to find out
     115             :  * its exact type.  (To access format-specific methods for instance)
     116             :  *
     117             :  * Returns the new object ptr. , or NULL if the open failed.
     118             :  **********************************************************************/
     119        2164 : IMapInfoFile *IMapInfoFile::SmartOpen(GDALDataset *poDS, const char *pszFname,
     120             :                                       GBool bUpdate,
     121             :                                       GBool bTestOpenNoError /*=FALSE*/)
     122             : {
     123        2164 :     IMapInfoFile *poFile = nullptr;
     124        2164 :     int nLen = 0;
     125             : 
     126        2164 :     if (pszFname)
     127        2164 :         nLen = static_cast<int>(strlen(pszFname));
     128             : 
     129        2164 :     if (nLen > 4 && (EQUAL(pszFname + nLen - 4, ".MIF") ||
     130        1294 :                      EQUAL(pszFname + nLen - 4, ".MID")))
     131             :     {
     132             :         /*-------------------------------------------------------------
     133             :          * MIF/MID file
     134             :          *------------------------------------------------------------*/
     135         870 :         poFile = new MIFFile(poDS);
     136             :     }
     137        1294 :     else if (nLen > 4 && EQUAL(pszFname + nLen - 4, ".TAB"))
     138             :     {
     139             :         /*-------------------------------------------------------------
     140             :          * .TAB file ... is it a TABFileView or a TABFile?
     141             :          * We have to read the .tab header to find out.
     142             :          *------------------------------------------------------------*/
     143        1294 :         char *pszAdjFname = CPLStrdup(pszFname);
     144        1294 :         GBool bFoundFields = FALSE;
     145        1294 :         GBool bFoundView = FALSE;
     146        1294 :         GBool bFoundSeamless = FALSE;
     147             : 
     148        1294 :         TABAdjustFilenameExtension(pszAdjFname);
     149        1294 :         VSILFILE *fp = VSIFOpenL(pszAdjFname, "r");
     150        1294 :         const char *pszLine = nullptr;
     151       11947 :         while (fp && (pszLine = CPLReadLineL(fp)) != nullptr)
     152             :         {
     153       21843 :             while (isspace(static_cast<unsigned char>(*pszLine)))
     154       11190 :                 pszLine++;
     155       10653 :             if (STARTS_WITH_CI(pszLine, "Fields"))
     156        1291 :                 bFoundFields = TRUE;
     157        9362 :             else if (STARTS_WITH_CI(pszLine, "create view"))
     158           2 :                 bFoundView = TRUE;
     159        9360 :             else if (STARTS_WITH_CI(pszLine, "\"\\IsSeamless\" = \"TRUE\""))
     160           1 :                 bFoundSeamless = TRUE;
     161             :         }
     162             : 
     163        1294 :         if (bFoundView)
     164           2 :             poFile = new TABView(poDS);
     165        1292 :         else if (bFoundFields && bFoundSeamless)
     166           1 :             poFile = new TABSeamless(poDS);
     167        1291 :         else if (bFoundFields)
     168        1290 :             poFile = new TABFile(poDS);
     169             : 
     170        1294 :         if (fp)
     171        1294 :             VSIFCloseL(fp);
     172             : 
     173        1294 :         CPLFree(pszAdjFname);
     174             :     }
     175             : 
     176             :     /*-----------------------------------------------------------------
     177             :      * Perform the open() call
     178             :      *----------------------------------------------------------------*/
     179        4327 :     if (poFile && poFile->Open(pszFname, bUpdate ? TABReadWrite : TABRead,
     180        2163 :                                bTestOpenNoError) != 0)
     181             :     {
     182          75 :         delete poFile;
     183          75 :         poFile = nullptr;
     184             :     }
     185             : 
     186        2164 :     if (!bTestOpenNoError && poFile == nullptr)
     187             :     {
     188           0 :         CPLError(CE_Failure, CPLE_FileIO,
     189             :                  "%s could not be opened as a MapInfo dataset.", pszFname);
     190             :     }
     191             : 
     192        2164 :     return poFile;
     193             : }
     194             : 
     195             : /**********************************************************************
     196             :  *                   IMapInfoFile::GetNextFeature()
     197             :  *
     198             :  * Standard OGR GetNextFeature implementation.  This method is used
     199             :  * to retrieve the next OGRFeature.
     200             :  **********************************************************************/
     201      223048 : OGRFeature *IMapInfoFile::GetNextFeature()
     202             : {
     203      223048 :     GIntBig nFeatureId = 0;
     204             : 
     205      534753 :     while ((nFeatureId = GetNextFeatureId(m_nCurFeatureId)) != -1)
     206             :     {
     207      523944 :         OGRGeometry *poGeom = nullptr;
     208      523944 :         OGRFeature *poFeatureRef = GetFeatureRef(nFeatureId);
     209      523944 :         if (poFeatureRef == nullptr)
     210         328 :             return nullptr;
     211     1413300 :         else if ((m_poFilterGeom == nullptr ||
     212      366072 :                   ((poGeom = poFeatureRef->GetGeometryRef()) != nullptr &&
     213     1103800 :                    FilterGeometry(poGeom))) &&
     214      214115 :                  (m_poAttrQuery == nullptr ||
     215        4894 :                   m_poAttrQuery->Evaluate(poFeatureRef)))
     216             :         {
     217             :             // Avoid cloning feature... return the copy owned by the class
     218      211911 :             CPLAssert(poFeatureRef == m_poCurFeature);
     219      211911 :             m_poCurFeature = nullptr;
     220      211911 :             if (poFeatureRef->GetGeometryRef() != nullptr)
     221      211754 :                 poFeatureRef->GetGeometryRef()->assignSpatialReference(
     222      211754 :                     GetSpatialRef());
     223      211911 :             return poFeatureRef;
     224             :         }
     225             :     }
     226       10809 :     return nullptr;
     227             : }
     228             : 
     229             : /**********************************************************************
     230             :  *                   IMapInfoFile::CreateTABFeature()
     231             :  *
     232             :  * Instantiate a TABFeature* from a OGRFeature* (or NULL on error)
     233             :  **********************************************************************/
     234             : 
     235       15211 : TABFeature *IMapInfoFile::CreateTABFeature(OGRFeature *poFeature)
     236             : {
     237       15211 :     TABFeature *poTABFeature = nullptr;
     238             :     OGRwkbGeometryType eGType;
     239       15211 :     TABPoint *poTABPointFeature = nullptr;
     240       15211 :     TABRegion *poTABRegionFeature = nullptr;
     241       15211 :     TABPolyline *poTABPolylineFeature = nullptr;
     242             : 
     243             :     /*-----------------------------------------------------------------
     244             :      * MITAB won't accept new features unless they are in a type derived
     245             :      * from TABFeature... so we have to do our best to map to the right
     246             :      * feature type based on the geometry type.
     247             :      *----------------------------------------------------------------*/
     248       15211 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     249       15211 :     if (poGeom != nullptr)
     250       15137 :         eGType = poGeom->getGeometryType();
     251             :     else
     252          74 :         eGType = wkbNone;
     253             : 
     254       15211 :     switch (wkbFlatten(eGType))
     255             :     {
     256             :         /*-------------------------------------------------------------
     257             :          * POINT
     258             :          *------------------------------------------------------------*/
     259       14772 :         case wkbPoint:
     260             :         {
     261       14772 :             const char *pszStyleString = poFeature->GetStyleString();
     262       14772 :             if (pszStyleString)
     263             :             {
     264         113 :                 if (strstr(pszStyleString, "LABEL("))
     265             :                 {
     266           4 :                     auto poText = new TABText(poFeature->GetDefnRef());
     267           4 :                     poText->SetLabelFromStyleString(pszStyleString);
     268           4 :                     poTABFeature = poText;
     269             : 
     270           4 :                     if (strstr(pszStyleString, "SYMBOL("))
     271             :                     {
     272           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     273             :                                  "OGR style string contains both "
     274             :                                  "Label and Symbol parts. "
     275             :                                  "Only Label taken into account due to "
     276             :                                  "MapInfo TAB/MIF format limitations.");
     277             :                     }
     278             :                 }
     279             :                 else
     280             :                 {
     281             :                     TABFeatureClass featureClass =
     282         109 :                         ITABFeatureSymbol::GetSymbolFeatureClass(
     283             :                             pszStyleString);
     284         109 :                     if (featureClass == TABFCFontPoint)
     285             :                     {
     286           2 :                         poTABFeature =
     287           2 :                             new TABFontPoint(poFeature->GetDefnRef());
     288             :                     }
     289         107 :                     else if (featureClass == TABFCCustomPoint)
     290             :                     {
     291           2 :                         poTABFeature =
     292           2 :                             new TABCustomPoint(poFeature->GetDefnRef());
     293             :                     }
     294             :                     else
     295             :                     {
     296         105 :                         poTABFeature = new TABPoint(poFeature->GetDefnRef());
     297             :                     }
     298             :                     poTABPointFeature =
     299         109 :                         cpl::down_cast<TABPoint *>(poTABFeature);
     300         109 :                     poTABPointFeature->SetSymbolFromStyleString(
     301         109 :                         poFeature->GetStyleString());
     302             :                 }
     303             :             }
     304             :             else
     305             :             {
     306       14659 :                 poTABFeature = new TABPoint(poFeature->GetDefnRef());
     307             :             }
     308       14772 :             break;
     309             :         }
     310             : 
     311             :         /*-------------------------------------------------------------
     312             :          * REGION
     313             :          *------------------------------------------------------------*/
     314         109 :         case wkbPolygon:
     315             :         case wkbMultiPolygon:
     316         109 :             poTABFeature = new TABRegion(poFeature->GetDefnRef());
     317         109 :             if (poFeature->GetStyleString())
     318             :             {
     319          17 :                 poTABRegionFeature = cpl::down_cast<TABRegion *>(poTABFeature);
     320          17 :                 poTABRegionFeature->SetPenFromStyleString(
     321          17 :                     poFeature->GetStyleString());
     322             : 
     323          17 :                 poTABRegionFeature->SetBrushFromStyleString(
     324          17 :                     poFeature->GetStyleString());
     325             :             }
     326         109 :             break;
     327             :         /*-------------------------------------------------------------
     328             :          * LINE/PLINE/MULTIPLINE
     329             :          *------------------------------------------------------------*/
     330         238 :         case wkbLineString:
     331             :         case wkbMultiLineString:
     332         238 :             poTABFeature = new TABPolyline(poFeature->GetDefnRef());
     333         238 :             if (poFeature->GetStyleString())
     334             :             {
     335             :                 poTABPolylineFeature =
     336          13 :                     cpl::down_cast<TABPolyline *>(poTABFeature);
     337          13 :                 poTABPolylineFeature->SetPenFromStyleString(
     338          13 :                     poFeature->GetStyleString());
     339             :             }
     340         238 :             break;
     341             :         /*-------------------------------------------------------------
     342             :          * Collection types that are not directly supported... convert
     343             :          * to multiple features in output file through recursive calls.
     344             :          *------------------------------------------------------------*/
     345          18 :         case wkbGeometryCollection:
     346             :         case wkbMultiPoint:
     347             :         {
     348          18 :             OGRErr eStatus = OGRERR_NONE;
     349          18 :             assert(poGeom);  // for clang static analyzer
     350          18 :             OGRGeometryCollection *poColl = poGeom->toGeometryCollection();
     351          18 :             OGRFeature *poTmpFeature = poFeature->Clone();
     352             : 
     353         112 :             for (int i = 0; eStatus == OGRERR_NONE && poColl != nullptr &&
     354          56 :                             i < poColl->getNumGeometries();
     355             :                  i++)
     356             :             {
     357          38 :                 poTmpFeature->SetFID(OGRNullFID);
     358          38 :                 poTmpFeature->SetGeometry(poColl->getGeometryRef(i));
     359          38 :                 eStatus = ICreateFeature(poTmpFeature);
     360             :             }
     361          18 :             delete poTmpFeature;
     362          18 :             return nullptr;
     363             :         }
     364             :         break;
     365             :         /*-------------------------------------------------------------
     366             :          * Unsupported type.... convert to MapInfo geometry NONE
     367             :          *------------------------------------------------------------*/
     368          74 :         case wkbUnknown:
     369             :         default:
     370          74 :             poTABFeature = new TABFeature(poFeature->GetDefnRef());
     371          74 :             break;
     372             :     }
     373             : 
     374       15193 :     if (poGeom != nullptr)
     375       15119 :         poTABFeature->SetGeometryDirectly(poGeom->clone());
     376             : 
     377       31121 :     for (int i = 0; i < poFeature->GetDefnRef()->GetFieldCount(); i++)
     378             :     {
     379       15928 :         poTABFeature->SetField(i, poFeature->GetRawFieldRef(i));
     380             :     }
     381             : 
     382       15193 :     poTABFeature->SetFID(poFeature->GetFID());
     383             : 
     384       15193 :     return poTABFeature;
     385             : }
     386             : 
     387             : /**********************************************************************
     388             :  *                   IMapInfoFile::ICreateFeature()
     389             :  *
     390             :  * Standard OGR CreateFeature implementation.  This method is used
     391             :  * to create a new feature in current dataset
     392             :  **********************************************************************/
     393       14997 : OGRErr IMapInfoFile::ICreateFeature(OGRFeature *poFeature)
     394             : {
     395       14997 :     TABFeature *poTABFeature = CreateTABFeature(poFeature);
     396       14997 :     if (poTABFeature == nullptr) /* MultiGeometry */
     397          18 :         return OGRERR_NONE;
     398             : 
     399       14979 :     OGRErr eErr = CreateFeature(poTABFeature);
     400       14979 :     if (eErr == OGRERR_NONE)
     401       14978 :         poFeature->SetFID(poTABFeature->GetFID());
     402             : 
     403       14979 :     delete poTABFeature;
     404             : 
     405       14979 :     return eErr;
     406             : }
     407             : 
     408             : /**********************************************************************
     409             :  *                   IMapInfoFile::GetFeature()
     410             :  *
     411             :  * Standard OGR GetFeature implementation.  This method is used
     412             :  * to get the wanted (nFeatureId) feature, a NULL value will be
     413             :  * returned on error.
     414             :  **********************************************************************/
     415         281 : OGRFeature *IMapInfoFile::GetFeature(GIntBig nFeatureId)
     416             : {
     417             :     /*fprintf(stderr, "GetFeature(%ld)\n", nFeatureId);*/
     418             : 
     419         281 :     OGRFeature *poFeatureRef = GetFeatureRef(nFeatureId);
     420         281 :     if (poFeatureRef)
     421             :     {
     422             :         // Avoid cloning feature... return the copy owned by the class
     423         263 :         CPLAssert(poFeatureRef == m_poCurFeature);
     424         263 :         m_poCurFeature = nullptr;
     425             : 
     426         263 :         return poFeatureRef;
     427             :     }
     428             :     else
     429          18 :         return nullptr;
     430             : }
     431             : 
     432             : /************************************************************************/
     433             : /*                            GetTABType()                              */
     434             : /*                                                                      */
     435             : /*      Create a native field based on a generic OGR definition.        */
     436             : /************************************************************************/
     437             : 
     438         323 : int IMapInfoFile::GetTABType(const OGRFieldDefn *poField,
     439             :                              TABFieldType *peTABType, int *pnWidth,
     440             :                              int *pnPrecision)
     441             : {
     442             :     TABFieldType eTABType;
     443         323 :     int nWidth = poField->GetWidth();
     444         323 :     int nPrecision = poField->GetPrecision();
     445             : 
     446         323 :     if (poField->GetType() == OFTInteger)
     447             :     {
     448          87 :         eTABType = TABFInteger;
     449          87 :         if (nWidth == 0)
     450          80 :             nWidth = 12;
     451             :     }
     452         236 :     else if (poField->GetType() == OFTInteger64)
     453             :     {
     454           2 :         eTABType = TABFLargeInt;
     455           2 :         if (nWidth == 0)
     456           2 :             nWidth = 20;
     457             :     }
     458         234 :     else if (poField->GetType() == OFTReal)
     459             :     {
     460          35 :         if (nWidth == 0 && poField->GetPrecision() == 0)
     461             :         {
     462          29 :             eTABType = TABFFloat;
     463          29 :             nWidth = 32;
     464             :         }
     465             :         else
     466             :         {
     467           6 :             eTABType = TABFDecimal;
     468             :             // Enforce Mapinfo limits, otherwise MapInfo will crash (#6392)
     469           6 :             if (nWidth > 20 || nWidth - nPrecision < 2 || nPrecision > 16)
     470             :             {
     471           1 :                 if (nWidth > 20)
     472           1 :                     nWidth = 20;
     473           1 :                 if (nWidth - nPrecision < 2)
     474           1 :                     nPrecision = nWidth - 2;
     475           1 :                 if (nPrecision > 16)
     476           1 :                     nPrecision = 16;
     477           1 :                 CPLDebug("MITAB",
     478             :                          "Adjusting initial width,precision of %s from %d,%d "
     479             :                          "to %d,%d",
     480             :                          poField->GetNameRef(), poField->GetWidth(),
     481             :                          poField->GetPrecision(), nWidth, nPrecision);
     482             :             }
     483             :         }
     484             :     }
     485         199 :     else if (poField->GetType() == OFTDate)
     486             :     {
     487          19 :         eTABType = TABFDate;
     488          19 :         if (nWidth == 0)
     489          17 :             nWidth = 10;
     490             :     }
     491         180 :     else if (poField->GetType() == OFTTime)
     492             :     {
     493           3 :         eTABType = TABFTime;
     494           3 :         if (nWidth == 0)
     495           1 :             nWidth = 9;
     496             :     }
     497         177 :     else if (poField->GetType() == OFTDateTime)
     498             :     {
     499          19 :         eTABType = TABFDateTime;
     500          19 :         if (nWidth == 0)
     501          17 :             nWidth = 19;
     502             :     }
     503         158 :     else if (poField->GetType() == OFTString)
     504             :     {
     505         158 :         eTABType = TABFChar;
     506         158 :         if (nWidth == 0)
     507         116 :             nWidth = 254;
     508             :         else
     509          42 :             nWidth = std::min(254, nWidth);
     510             :     }
     511             :     else
     512             :     {
     513           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     514             :                  "IMapInfoFile::CreateField() called with unsupported field"
     515             :                  " type %d.\n"
     516             :                  "Note that Mapinfo files don't support list field types.\n",
     517           0 :                  poField->GetType());
     518             : 
     519           0 :         return -1;
     520             :     }
     521             : 
     522         323 :     *peTABType = eTABType;
     523         323 :     *pnWidth = nWidth;
     524         323 :     *pnPrecision = nPrecision;
     525             : 
     526         323 :     return 0;
     527             : }
     528             : 
     529             : /************************************************************************/
     530             : /*                            CreateField()                             */
     531             : /*                                                                      */
     532             : /*      Create a native field based on a generic OGR definition.        */
     533             : /************************************************************************/
     534             : 
     535         313 : OGRErr IMapInfoFile::CreateField(const OGRFieldDefn *poField, int bApproxOK)
     536             : 
     537             : {
     538             :     TABFieldType eTABType;
     539         313 :     int nWidth = 0;
     540         313 :     int nPrecision = 0;
     541             : 
     542         313 :     if (GetTABType(poField, &eTABType, &nWidth, &nPrecision) < 0)
     543           0 :         return OGRERR_FAILURE;
     544             : 
     545         313 :     if (AddFieldNative(poField->GetNameRef(), eTABType, nWidth, nPrecision,
     546         626 :                        FALSE, FALSE, bApproxOK) > -1)
     547         313 :         return OGRERR_NONE;
     548             : 
     549           0 :     return OGRERR_FAILURE;
     550             : }
     551             : 
     552             : /**********************************************************************
     553             :  *                   IMapInfoFile::SetCharset()
     554             :  *
     555             :  * Set the charset for the tab header.
     556             :  *
     557             :  *
     558             :  * Returns 0 on success, -1 on error.
     559             :  **********************************************************************/
     560        2352 : int IMapInfoFile::SetCharset(const char *pszCharset)
     561             : {
     562        2352 :     if (pszCharset && strlen(pszCharset) > 0)
     563             :     {
     564        2352 :         if (pszCharset == m_pszCharset)
     565             :         {
     566           0 :             return 0;
     567             :         }
     568        2352 :         CPLFree(m_pszCharset);
     569        2352 :         m_pszCharset = CPLStrdup(pszCharset);
     570        2352 :         return 0;
     571             :     }
     572           0 :     return -1;
     573             : }
     574             : 
     575        4784 : const char *IMapInfoFile::GetCharset() const
     576             : {
     577        4784 :     return m_pszCharset;
     578             : }
     579             : 
     580             : // Table is adopted from
     581             : // http://www.i-signum.com/Formation/download/MB_ReferenceGuide.pdf pp. 127-128
     582             : static const char *const apszCharsets[][2] = {
     583             :     {"Neutral", ""},                 // No character conversions performed.
     584             :     {"ISO8859_1", "ISO-8859-1"},     // ISO 8859-1 (UNIX)
     585             :     {"ISO8859_2", "ISO-8859-2"},     // ISO 8859-2 (UNIX)
     586             :     {"ISO8859_3", "ISO-8859-3"},     // ISO 8859-3 (UNIX)
     587             :     {"ISO8859_4", "ISO-8859-4"},     // ISO 8859-4 (UNIX)
     588             :     {"ISO8859_5", "ISO-8859-5"},     // ISO 8859-5 (UNIX)
     589             :     {"ISO8859_6", "ISO-8859-6"},     // ISO 8859-6 (UNIX)
     590             :     {"ISO8859_7", "ISO-8859-7"},     // ISO 8859-7 (UNIX)
     591             :     {"ISO8859_8", "ISO-8859-8"},     // ISO 8859-8 (UNIX)
     592             :     {"ISO8859_9", "ISO-8859-9"},     // ISO 8859-9 (UNIX)
     593             :     {"PackedEUCJapaese", "EUC-JP"},  // UNIX, standard Japanese implementation.
     594             :     {"WindowsLatin1", "CP1252"},
     595             :     {"WindowsLatin2", "CP1250"},
     596             :     {"WindowsArabic", "CP1256"},
     597             :     {"WindowsCyrillic", "CP1251"},
     598             :     {"WindowsBalticRim", "CP1257"},
     599             :     {"WindowsGreek", "CP1253"},
     600             :     {"WindowsHebrew", "CP1255"},
     601             :     {"WindowsTurkish", "CP1254"},     // Windows Eastern Europe
     602             :     {"WindowsTradChinese", "CP950"},  // Windows Traditional Chinese
     603             :     {"WindowsSimpChinese", "CP936"},  // Windows Simplified Chinese
     604             :     {"WindowsJapanese", "CP932"},
     605             :     {"WindowsKorean", "CP949"},
     606             :     {"CodePage437", "CP437"},  // DOS Code Page 437 = IBM Extended ASCII
     607             :     {"CodePage850", "CP850"},  // DOS Code Page 850 = Multilingual
     608             :     {"CodePage852", "CP852"},  // DOS Code Page 852 = Eastern Europe
     609             :     {"CodePage855", "CP855"},  // DOS Code Page 855 = Cyrillic
     610             :     {"CodePage857", "CP857"},
     611             :     {"CodePage860", "CP860"},  // DOS Code Page 860 = Portuguese
     612             :     {"CodePage861", "CP861"},  // DOS Code Page 861 = Icelandic
     613             :     {"CodePage863", "CP863"},  // DOS Code Page 863 = French Canadian
     614             :     {"CodePage864", "CP864"},  // DOS Code Page 864 = Arabic
     615             :     {"CodePage865", "CP865"},  // DOS Code Page 865 = Nordic
     616             :     {"CodePage869", "CP869"},  // DOS Code Page 869 = Modern Greek
     617             :     {"LICS", ""},              // Lotus worksheet release 1,2 character set
     618             :     {"LMBCS", ""},             // Lotus worksheet release 3,4 character set
     619             :     {nullptr, nullptr}};
     620             : 
     621        6959 : const char *IMapInfoFile::CharsetToEncoding(const char *pszCharset)
     622             : {
     623        6959 :     if (pszCharset == nullptr)
     624             :     {
     625         869 :         return apszCharsets[0][1];
     626             :     }
     627             : 
     628       14921 :     for (size_t i = 0; apszCharsets[i][0] != nullptr; ++i)
     629             :     {
     630       14915 :         if (EQUAL(pszCharset, apszCharsets[i][0]))
     631             :         {
     632        6084 :             return apszCharsets[i][1];
     633             :         }
     634             :     }
     635             : 
     636           6 :     CPLError(CE_Warning, CPLE_NotSupported,
     637             :              "Cannot find iconv encoding corresponding to MapInfo %s charset",
     638             :              pszCharset);
     639           6 :     return apszCharsets[0][1];
     640             : }
     641             : 
     642         343 : const char *IMapInfoFile::EncodingToCharset(const char *pszEncoding)
     643             : {
     644         343 :     if (pszEncoding == nullptr)
     645             :     {
     646         336 :         return apszCharsets[0][0];
     647             :     }
     648             : 
     649         105 :     for (size_t i = 0; apszCharsets[i][1] != nullptr; ++i)
     650             :     {
     651         105 :         if (EQUAL(pszEncoding, apszCharsets[i][1]))
     652             :         {
     653           7 :             return apszCharsets[i][0];
     654             :         }
     655             :     }
     656             : 
     657           0 :     CPLError(CE_Warning, CPLE_NotSupported,
     658             :              "Cannot find MapInfo charset corresponding to iconv %s encoding",
     659             :              pszEncoding);
     660           0 :     return apszCharsets[0][0];
     661             : }
     662             : 
     663        3390 : const char *IMapInfoFile::GetEncoding() const
     664             : {
     665        3390 :     return CharsetToEncoding(GetCharset());
     666             : }
     667             : 
     668           0 : void IMapInfoFile::SetEncoding(const char *pszEncoding)
     669             : {
     670           0 :     SetCharset(EncodingToCharset(pszEncoding));
     671           0 : }
     672             : 
     673          68 : int IMapInfoFile::TestUtf8Capability() const
     674             : {
     675          68 :     const char *pszEncoding(GetEncoding());
     676          68 :     if (strlen(pszEncoding) == 0)
     677             :     {
     678          55 :         return FALSE;
     679             :     }
     680             : 
     681          13 :     return CPLCanRecode("test", GetEncoding(), CPL_ENC_UTF8);
     682             : }
     683             : 
     684         466 : CPLString IMapInfoFile::NormalizeFieldName(const char *pszName) const
     685             : {
     686         932 :     CPLString osName(pszName);
     687         466 :     if (strlen(GetEncoding()) > 0)
     688          76 :         osName.Recode(CPL_ENC_UTF8, GetEncoding());
     689             : 
     690             :     char szNewFieldName[31 + 1]; /* 31 is the max characters for a field name*/
     691         466 :     unsigned int nRenameNum = 1;
     692             : 
     693         466 :     strncpy(szNewFieldName, osName.c_str(), sizeof(szNewFieldName) - 1);
     694         466 :     szNewFieldName[sizeof(szNewFieldName) - 1] = '\0';
     695             : 
     696         932 :     while (m_oSetFields.find(CPLString(szNewFieldName).toupper()) !=
     697        1398 :                m_oSetFields.end() &&
     698             :            nRenameNum < 10)
     699             :     {
     700           0 :         CPLsnprintf(szNewFieldName, sizeof(szNewFieldName), "%.29s_%.1u",
     701             :                     osName.c_str(), nRenameNum);
     702           0 :         nRenameNum++;
     703             :     }
     704             : 
     705         932 :     while (m_oSetFields.find(CPLString(szNewFieldName).toupper()) !=
     706        1398 :                m_oSetFields.end() &&
     707             :            nRenameNum < 100)
     708             :     {
     709           0 :         CPLsnprintf(szNewFieldName, sizeof(szNewFieldName), "%.29s%.2u",
     710             :                     osName.c_str(), nRenameNum);
     711           0 :         nRenameNum++;
     712             :     }
     713             : 
     714         466 :     if (m_oSetFields.find(CPLString(szNewFieldName).toupper()) !=
     715         932 :         m_oSetFields.end())
     716             :     {
     717           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     718             :                  "Too many field names like '%s' when truncated to 31 letters "
     719             :                  "for MapInfo format.",
     720             :                  pszName);
     721             :     }
     722             : 
     723         466 :     CPLString osNewFieldName(szNewFieldName);
     724         466 :     if (strlen(GetEncoding()) > 0)
     725          76 :         osNewFieldName.Recode(GetEncoding(), CPL_ENC_UTF8);
     726             : 
     727         466 :     if (!EQUAL(pszName, osNewFieldName.c_str()))
     728             :     {
     729           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     730             :                  "Normalized/laundered field name: '%s' to '%s'", pszName,
     731             :                  osNewFieldName.c_str());
     732             :     }
     733             : 
     734         932 :     return osNewFieldName;
     735             : }

Generated by: LCOV version 1.14