LCOV - code coverage report
Current view: top level - ogr - ogrmitabspatialref.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 944 1063 88.8 %
Date: 2024-11-21 22:18:42 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: MIT
       2             : // Copyright 1999-2003, Daniel Morissette
       3             : // Copyright (c) 1999-2001, Frank Warmerdam
       4             : // Implementation translation between MIF CoordSys format, and
       5             : // and OGRSpatialRef format.
       6             : 
       7             : /*! @cond Doxygen_Suppress */
       8             : 
       9             : #include "ogrmitabspatialref.h"
      10             : 
      11             : #include "cpl_port.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <cmath>
      15             : #include <cstddef>
      16             : #include <cstdio>
      17             : #include <cstdlib>
      18             : #include <cstring>
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_error.h"
      22             : #include "cpl_string.h"
      23             : #include "ogr_spatialref.h"
      24             : #include "ogr_srs_api.h"
      25             : 
      26             : typedef struct
      27             : {
      28             :     int nDatumEPSGCode;
      29             :     int nMapInfoDatumID;
      30             :     const char *pszOGCDatumName;
      31             :     int nEllipsoid;
      32             :     double dfShiftX;
      33             :     double dfShiftY;
      34             :     double dfShiftZ;
      35             :     double dfDatumParm0; /* RotX */
      36             :     double dfDatumParm1; /* RotY */
      37             :     double dfDatumParm2; /* RotZ */
      38             :     double dfDatumParm3; /* Scale Factor */
      39             :     double dfDatumParm4; /* Prime Meridian */
      40             : } MapInfoDatumInfo;
      41             : 
      42             : typedef struct
      43             : {
      44             :     int nMapInfoId;
      45             :     const char *pszMapinfoName;
      46             :     double dfA;             /* semi major axis in meters */
      47             :     double dfInvFlattening; /* Inverse flattening */
      48             : } MapInfoSpheroidInfo;
      49             : 
      50             : /**********************************************************************
      51             :  * MapInfo Units string to numeric ID conversion
      52             :  **********************************************************************/
      53             : typedef struct
      54             : {
      55             :     int nUnitId;
      56             :     const char *pszAbbrev;
      57             : } MapInfoUnitsInfo;
      58             : 
      59             : static const MapInfoUnitsInfo gasUnitsList[] = {
      60             :     {0, "mi"},        {1, "km"},          {2, "in"},  {3, "ft"},
      61             :     {4, "yd"},        {5, "mm"},          {6, "cm"},  {7, "m"},
      62             :     {8, "survey ft"}, {8, "survey foot"},  // alternate
      63             :     {13, nullptr},    {9, "nmi"},         {30, "li"}, {31, "ch"},
      64             :     {32, "rd"},       {-1, nullptr}};
      65             : 
      66             : /**********************************************************************
      67             :  *                       TABUnitIdToString()
      68             :  *
      69             :  * Return the MIF units name for specified units id.
      70             :  * Return "" if no match found.
      71             :  *
      72             :  * The returned string should not be freed by the caller.
      73             :  **********************************************************************/
      74          81 : static const char *TABUnitIdToString(int nId)
      75             : {
      76          81 :     const MapInfoUnitsInfo *psList = gasUnitsList;
      77             : 
      78         674 :     while (psList->nUnitId != -1)
      79             :     {
      80         674 :         if (psList->nUnitId == nId)
      81          81 :             return psList->pszAbbrev;
      82         593 :         psList++;
      83             :     }
      84             : 
      85           0 :     return "";
      86             : }
      87             : 
      88             : /**********************************************************************
      89             :  *                       TABUnitIdFromString()
      90             :  *
      91             :  * Return the units ID for specified MIF units name
      92             :  *
      93             :  * Returns -1 if no match found.
      94             :  **********************************************************************/
      95         167 : static int TABUnitIdFromString(const char *pszName)
      96             : {
      97         167 :     if (pszName == nullptr)
      98           0 :         return 13;
      99             : 
     100         167 :     const MapInfoUnitsInfo *psList = gasUnitsList;
     101             : 
     102        1322 :     while (psList->nUnitId != -1)
     103             :     {
     104        1322 :         if (psList->pszAbbrev != nullptr && EQUAL(psList->pszAbbrev, pszName))
     105         167 :             return psList->nUnitId;
     106        1155 :         psList++;
     107             :     }
     108             : 
     109           0 :     return -1;
     110             : }
     111             : 
     112             : /* -------------------------------------------------------------------- */
     113             : /*      This table was automatically generated by doing translations    */
     114             : /*      between mif and tab for each datum, and extracting the          */
     115             : /*      parameters from the tab file.  The EPSG codes and OGC names     */
     116             : /*      were added afterwards and may be incomplete or inaccurate.       */
     117             : /* -------------------------------------------------------------------- */
     118             : 
     119             : extern const MapInfoDatumInfo asDatumInfoList[];
     120             : extern const MapInfoSpheroidInfo asSpheroidInfoList[];
     121             : 
     122             : /* EPSG code, MapInfo datum ID (or 9999), OGC Name, datum parameters... */
     123             : const MapInfoDatumInfo asDatumInfoList[] = {
     124             : 
     125             :     {0, 104, "WGS_1984", 28, 0, 0, 0, 0, 0, 0, 0, 0},
     126             :     {6269, 74, "North_American_Datum_1983", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     127             : 
     128             :     {0, 0, "", 29, 0, 0, 0, 0, 0, 0, 0, 0},  // Datum ignore
     129             : 
     130             :     {6201, 1, "Adindan", 6, -162, -12, 206, 0, 0, 0, 0, 0},
     131             :     {6205, 2, "Afgooye", 3, -43, -163, 45, 0, 0, 0, 0, 0},
     132             :     {6204, 3, "Ain_el_Abd_1970", 4, -150, -251, -2, 0, 0, 0, 0, 0},
     133             :     {0, 4, "Anna_1_Astro_1965", 2, -491, -22, 435, 0, 0, 0, 0, 0},
     134             :     {6209, 5, "Arc_1950", 15, -143, -90, -294, 0, 0, 0, 0, 0},
     135             :     {6210, 6, "Arc_1960", 6, -160, -8, -300, 0, 0, 0, 0, 0},
     136             :     {0, 7, "Ascension_Islands", 4, -207, 107, 52, 0, 0, 0, 0, 0},
     137             :     {0, 8, "Astro_Beacon_E", 4, 145, 75, -272, 0, 0, 0, 0, 0},
     138             :     {0, 9, "Astro_B4_Sorol_Atoll", 4, 114, -116, -333, 0, 0, 0, 0, 0},
     139             :     {0, 10, "Astro_Dos_71_4", 4, -320, 550, -494, 0, 0, 0, 0, 0},
     140             :     {0, 11, "Astronomic_Station_1952", 4, 124, -234, -25, 0, 0, 0, 0, 0},
     141             :     {6202, 12, "Australian_Geodetic_Datum_66", 2, -133, -48, 148, 0, 0, 0, 0,
     142             :      0},
     143             :     {6203, 13, "Australian_Geodetic_Datum_84", 2, -134, -48, 149, 0, 0, 0, 0,
     144             :      0},
     145             :     {0, 14, "Bellevue_Ign", 4, -127, -769, 472, 0, 0, 0, 0, 0},
     146             :     {6216, 15, "Bermuda_1957", 7, -73, 213, 296, 0, 0, 0, 0, 0},
     147             :     {6218, 16, "Bogota", 4, 307, 304, -318, 0, 0, 0, 0, 0},
     148             :     {6221, 17, "Campo_Inchauspe", 4, -148, 136, 90, 0, 0, 0, 0, 0},
     149             :     {0, 18, "Canton_Astro_1966", 4, 298, -304, -375, 0, 0, 0, 0, 0},
     150             :     {6222, 19, "Cape", 6, -136, -108, -292, 0, 0, 0, 0, 0},
     151             :     {6717, 20, "Cape_Canaveral", 7, -2, 150, 181, 0, 0, 0, 0, 0},
     152             :     {6223, 21, "Carthage", 6, -263, 6, 431, 0, 0, 0, 0, 0},
     153             :     {6672, 22, "Chatham_1971", 4, 175, -38, 113, 0, 0, 0, 0, 0},
     154             :     {6224, 23, "Chua", 4, -134, 229, -29, 0, 0, 0, 0, 0},
     155             :     {6225, 24, "Corrego_Alegre", 4, -206, 172, -6, 0, 0, 0, 0, 0},
     156             :     {6211, 25, "Batavia", 10, -377, 681, -50, 0, 0, 0, 0, 0},
     157             :     {0, 26, "Dos_1968", 4, 230, -199, -752, 0, 0, 0, 0, 0},
     158             :     {6719, 27, "Easter_Island_1967", 4, 211, 147, 111, 0, 0, 0, 0, 0},
     159             :     {6230, 28, "European_Datum_1950", 4, -87, -98, -121, 0, 0, 0, 0, 0},
     160             :     {6668, 29, "European_Datum_1979", 4, -86, -98, -119, 0, 0, 0, 0, 0},
     161             :     {6233, 30, "Gandajika_1970", 4, -133, -321, 50, 0, 0, 0, 0, 0},
     162             :     {6272, 31, "New_Zealand_GD49", 4, 84, -22, 209, 0, 0, 0, 0, 0},
     163             :     {6272, 31, "New_Zealand_Geodetic_Datum_1949", 4, 84, -22, 209, 0, 0, 0, 0,
     164             :      0},
     165             :     {0, 32, "GRS_67", 21, 0, 0, 0, 0, 0, 0, 0, 0},
     166             :     {0, 33, "GRS_80", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     167             :     {6171, 33, "Reseau_Geodesique_Francais_1993", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     168             :     {6619, 33, "SWEREF99", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     169             :     {6675, 34, "Guam_1963", 7, -100, -248, 259, 0, 0, 0, 0, 0},
     170             :     {0, 35, "Gux_1_Astro", 4, 252, -209, -751, 0, 0, 0, 0, 0},
     171             :     {6254, 36, "Hito_XVIII_1963", 4, 16, 196, 93, 0, 0, 0, 0, 0},
     172             :     {6658, 37, "Hjorsey_1955", 4, -73, 46, -86, 0, 0, 0, 0, 0},
     173             :     {6738, 38, "Hong_Kong_1963", 4, -156, -271, -189, 0, 0, 0, 0, 0},
     174             :     {6236, 39, "Hu_Tzu_Shan", 4, -634, -549, -201, 0, 0, 0, 0, 0},
     175             :     {0, 40, "Indian_Thailand_Vietnam", 11, 214, 836, 303, 0, 0, 0, 0, 0},
     176             :     {0, 41, "Indian_Bangladesh", 11, 289, 734, 257, 0, 0, 0, 0, 0},
     177             :     {6299, 42, "Ireland_1965", 13, 506, -122, 611, 0, 0, 0, 0, 0},
     178             :     {0, 43, "ISTS_073_Astro_1969", 4, 208, -435, -229, 0, 0, 0, 0, 0},
     179             :     {6725, 44, "Johnston_Island_1961", 4, 191, -77, -204, 0, 0, 0, 0, 0},
     180             :     {6244, 45, "Kandawala", 11, -97, 787, 86, 0, 0, 0, 0, 0},
     181             :     {0, 46, "Kerguyelen_Island", 4, 145, -187, 103, 0, 0, 0, 0, 0},
     182             :     {6245, 47, "Kertau", 17, -11, 851, 5, 0, 0, 0, 0, 0},
     183             :     {0, 48, "L_C_5_Astro", 7, 42, 124, 147, 0, 0, 0, 0, 0},
     184             :     {6251, 49, "Liberia_1964", 6, -90, 40, 88, 0, 0, 0, 0, 0},
     185             :     {0, 50, "Luzon_Phillippines", 7, -133, -77, -51, 0, 0, 0, 0, 0},
     186             :     {0, 51, "Luzon_Mindanao_Island", 7, -133, -79, -72, 0, 0, 0, 0, 0},
     187             :     {6256, 52, "Mahe_1971", 6, 41, -220, -134, 0, 0, 0, 0, 0},
     188             :     {0, 53, "Marco_Astro", 4, -289, -124, 60, 0, 0, 0, 0, 0},
     189             :     {6262, 54, "Massawa", 10, 639, 405, 60, 0, 0, 0, 0, 0},
     190             :     {6261, 55, "Merchich", 16, 31, 146, 47, 0, 0, 0, 0, 0},
     191             :     {0, 56, "Midway_Astro_1961", 4, 912, -58, 1227, 0, 0, 0, 0, 0},
     192             :     {6263, 57, "Minna", 6, -92, -93, 122, 0, 0, 0, 0, 0},
     193             :     {0, 58, "Nahrwan_Masirah_Island", 6, -247, -148, 369, 0, 0, 0, 0, 0},
     194             :     {0, 59, "Nahrwan_Un_Arab_Emirates", 6, -249, -156, 381, 0, 0, 0, 0, 0},
     195             :     {0, 60, "Nahrwan_Saudi_Arabia", 6, -231, -196, 482, 0, 0, 0, 0, 0},
     196             :     {6271, 61, "Naparima_1972", 4, -2, 374, 172, 0, 0, 0, 0, 0},
     197             :     {6267, 62, "NAD_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
     198             :     {6267, 62, "North_American_Datum_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
     199             :     {0, 63, "NAD_27_Alaska", 7, -5, 135, 172, 0, 0, 0, 0, 0},
     200             :     {0, 64, "NAD_27_Bahamas", 7, -4, 154, 178, 0, 0, 0, 0, 0},
     201             :     {0, 65, "NAD_27_San_Salvador", 7, 1, 140, 165, 0, 0, 0, 0, 0},
     202             :     {0, 66, "NAD_27_Canada", 7, -10, 158, 187, 0, 0, 0, 0, 0},
     203             :     {0, 67, "NAD_27_Canal_Zone", 7, 0, 125, 201, 0, 0, 0, 0, 0},
     204             :     {0, 68, "NAD_27_Caribbean", 7, -7, 152, 178, 0, 0, 0, 0, 0},
     205             :     {0, 69, "NAD_27_Central_America", 7, 0, 125, 194, 0, 0, 0, 0, 0},
     206             :     {0, 70, "NAD_27_Cuba", 7, -9, 152, 178, 0, 0, 0, 0, 0},
     207             :     {0, 71, "NAD_27_Greenland", 7, 11, 114, 195, 0, 0, 0, 0, 0},
     208             :     {0, 72, "NAD_27_Mexico", 7, -12, 130, 190, 0, 0, 0, 0, 0},
     209             :     {0, 73, "NAD_27_Michigan", 8, -8, 160, 176, 0, 0, 0, 0, 0},
     210             :     {0, 75, "Observatorio_1966", 4, -425, -169, 81, 0, 0, 0, 0, 0},
     211             :     {0, 76, "Old_Egyptian", 22, -130, 110, -13, 0, 0, 0, 0, 0},
     212             :     {6135, 77, "Old_Hawaiian", 7, 61, -285, -181, 0, 0, 0, 0, 0},
     213             :     {0, 78, "Oman", 6, -346, -1, 224, 0, 0, 0, 0, 0},
     214             :     {6277, 79, "OSGB_1936", 9, 375, -111, 431, 0, 0, 0, 0, 0},
     215             :     {0, 80, "Pico_De_Las_Nieves", 4, -307, -92, 127, 0, 0, 0, 0, 0},
     216             :     {6729, 81, "Pitcairn_Astro_1967", 4, 185, 165, 42, 0, 0, 0, 0, 0},
     217             :     {6248, 82, "Provisional_South_American", 4, -288, 175, -376, 0, 0, 0, 0, 0},
     218             :     {6139, 83, "Puerto_Rico", 7, 11, 72, -101, 0, 0, 0, 0, 0},
     219             :     {6614, 84, "Qatar_National", 4, -128, -283, 22, 0, 0, 0, 0, 0},
     220             :     {6287, 85, "Qornoq", 4, 164, 138, -189, 0, 0, 0, 0, 0},
     221             :     {6627, 86, "Reunion", 4, 94, -948, -1262, 0, 0, 0, 0, 0},
     222             :     {6265, 87, "Monte_Mario", 4, -225, -65, 9, 0, 0, 0, 0, 0},
     223             :     {0, 88, "Santo_Dos", 4, 170, 42, 84, 0, 0, 0, 0, 0},
     224             :     {0, 89, "Sao_Braz", 4, -203, 141, 53, 0, 0, 0, 0, 0},
     225             :     {6292, 90, "Sapper_Hill_1943", 4, -355, 16, 74, 0, 0, 0, 0, 0},
     226             :     {6293, 91, "Schwarzeck", 14, 616, 97, -251, 0, 0, 0, 0, 0},
     227             :     {6618, 92, "South_American_Datum_1969", 24, -57, 1, -41, 0, 0, 0, 0, 0},
     228             :     {0, 93, "South_Asia", 19, 7, -10, -26, 0, 0, 0, 0, 0},
     229             :     {0, 94, "Southeast_Base", 4, -499, -249, 314, 0, 0, 0, 0, 0},
     230             :     {0, 95, "Southwest_Base", 4, -104, 167, -38, 0, 0, 0, 0, 0},
     231             :     {6298, 96, "Timbalai_1948", 11, -689, 691, -46, 0, 0, 0, 0, 0},
     232             :     {6301, 97, "Tokyo", 10, -128, 481, 664, 0, 0, 0, 0, 0},
     233             :     {0, 98, "Tristan_Astro_1968", 4, -632, 438, -609, 0, 0, 0, 0, 0},
     234             :     {6731, 99, "Viti_Levu_1916", 6, 51, 391, -36, 0, 0, 0, 0, 0},
     235             :     {0, 100, "Wake_Entiwetok_1960", 23, 101, 52, -39, 0, 0, 0, 0, 0},
     236             :     {0, 101, "WGS_60", 26, 0, 0, 0, 0, 0, 0, 0, 0},
     237             :     {6760, 102, "WGS_66", 27, 0, 0, 0, 0, 0, 0, 0, 0},
     238             :     {6322, 103, "WGS_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0},
     239             :     {6322, 103, "World_Geodetic_System_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0},
     240             :     {6326, 104, "WGS_1984", 28, 0, 0, 0, 0, 0, 0, 0, 0},
     241             :     {6309, 105, "Yacare", 4, -155, 171, 37, 0, 0, 0, 0, 0},
     242             :     {6311, 106, "Zanderij", 4, -265, 120, -358, 0, 0, 0, 0, 0},
     243             :     {0, 107, "NTF", 30, -168, -60, 320, 0, 0, 0, 0, 0},
     244             :     {6231, 108, "European_Datum_1987", 4, -83, -96, -113, 0, 0, 0, 0, 0},
     245             :     {0, 109, "Netherlands_Bessel", 10, 593, 26, 478, 0, 0, 0, 0, 0},
     246             :     {0, 110, "Belgium_Hayford", 4, 81, 120, 129, 0, 0, 0, 0, 0},
     247             :     {0, 111, "NWGL_10", 1, -1, 15, 1, 0, 0, 0, 0, 0},
     248             :     {6124, 112, "Rikets_koordinatsystem_1990", 10, 498, -36, 568, 0, 0, 0, 0,
     249             :      0},
     250             :     {0, 113, "Lisboa_DLX", 4, -303, -62, 105, 0, 0, 0, 0, 0},
     251             :     {0, 114, "Melrica_1973_D73", 4, -223, 110, 37, 0, 0, 0, 0, 0},
     252             :     {6258, 115, "European_Terrestrial_Reference_System_1989", 0, 0, 0, 0, 0, 0,
     253             :      0, 0, 0},
     254             :     {6258, 115, "Euref_89", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     255             :     {6180, 115, "Estonia_1997", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     256             :     {6283, 116, "GDA94", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     257             :     {6283, 116, "Geocentric_Datum_of_Australia_1994", 0, 0, 0, 0, 0, 0, 0, 0,
     258             :      0},
     259             :     {6167, 117, "NZGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     260             :     {6167, 117, "New_Zealand_Geodetic_Datum_2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     261             :     {6169, 118, "America_Samoa", 7, -115, 118, 426, 0, 0, 0, 0, 0},
     262             :     {0, 119, "Antigua_Astro_1965", 6, -270, 13, 62, 0, 0, 0, 0, 0},
     263             :     {6713, 120, "Ayabelle_Lighthouse", 6, -79, -129, 145, 0, 0, 0, 0, 0},
     264             :     {6219, 121, "Bukit_Rimpah", 10, -384, 664, -48, 0, 0, 0, 0, 0},
     265             :     {0, 122, "Estonia_1937", 10, 374, 150, 588, 0, 0, 0, 0, 0},
     266             :     {6155, 123, "Dabola", 6, -83, 37, 124, 0, 0, 0, 0, 0},
     267             :     {6736, 124, "Deception_Island", 6, 260, 12, -147, 0, 0, 0, 0, 0},
     268             :     {0, 125, "Fort_Thomas_1955", 6, -7, 215, 225, 0, 0, 0, 0, 0},
     269             :     {0, 126, "Graciosa_base_1948", 4, -104, 167, -38, 0, 0, 0, 0, 0},
     270             :     {6255, 127, "Herat_North", 4, -333, -222, 114, 0, 0, 0, 0, 0},
     271             :     {0, 128, "Hermanns_Kogel", 10, 682, -203, 480, 0, 0, 0, 0, 0},
     272             :     {6240, 129, "Indian", 50, 283, 682, 231, 0, 0, 0, 0, 0},
     273             :     {6239, 130, "Indian_1954", 11, 217, 823, 299, 0, 0, 0, 0, 0},
     274             :     {6131, 131, "Indian_1960", 11, 198, 881, 317, 0, 0, 0, 0, 0},
     275             :     {6240, 132, "Indian_1975", 11, 210, 814, 289, 0, 0, 0, 0, 0},
     276             :     {6238, 133, "Indonesian_Datum_1974", 4, -24, -15, 5, 0, 0, 0, 0, 0},
     277             :     {0, 134, "ISTS061_Astro_1968", 4, -794, 119, -298, 0, 0, 0, 0, 0},
     278             :     {0, 135, "Kusaie_Astro_1951", 4, 647, 1777, -1124, 0, 0, 0, 0, 0},
     279             :     {6250, 136, "Leigon", 6, -130, 29, 364, 0, 0, 0, 0, 0},
     280             :     {0, 137, "Montserrat_Astro_1958", 6, 174, 359, 365, 0, 0, 0, 0, 0},
     281             :     {6266, 138, "Mporaloko", 6, -74, -130, 42, 0, 0, 0, 0, 0},
     282             :     {0, 139, "North_Sahara_1959", 6, -186, -93, 310, 0, 0, 0, 0, 0},
     283             :     {0, 140, "Observatorio_Met_1939", 4, -425, -169, 81, 0, 0, 0, 0, 0},
     284             :     {6620, 141, "Point_58", 6, -106, -129, 165, 0, 0, 0, 0, 0},
     285             :     {6282, 142, "Pointe_Noire", 6, -148, 51, -291, 0, 0, 0, 0, 0},
     286             :     {6615, 143, "Porto_Santo_1936", 4, -499, -249, 314, 0, 0, 0, 0, 0},
     287             :     {6616, 144, "Selvagem_Grande_1938", 4, -289, -124, 60, 0, 0, 0, 0, 0},
     288             :     {0, 145, "Sierra_Leone_1960", 6, -88, 4, 101, 0, 0, 0, 0, 0},
     289             :     {6156, 146, "S_JTSK_Ferro", 10, 589, 76, 480, 0, 0, 0, 0, 0},
     290             :     {6297, 147, "Tananarive_1925", 4, -189, -242, -91, 0, 0, 0, 0, 0},
     291             :     {6811, 148, "Voirol_1874", 6, -73, -247, 227, 0, 0, 0, 0, 0},
     292             :     {0, 149, "Virol_1960", 6, -123, -206, 219, 0, 0, 0, 0, 0},
     293             :     {6148, 150, "Hartebeesthoek94", 28, 0, 0, 0, 0, 0, 0, 0, 0},
     294             :     {6122, 151, "ATS77", 51, 0, 0, 0, 0, 0, 0, 0, 0},
     295             :     {6612, 152, "JGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
     296             :     {0, 153, "HGRS87", 0, -199.87, 74.79, 246.62, 0, 0, 0, 0, 0},
     297             :     {6214, 154, "Beijing 1954", 3, -31.4, 144.3, 81.2, 0, 0, 0, 0, 0},
     298             :     {6754, 155, "Libya (LGD 2006)", 4, 208.4058, 109.8777, 2.5764, 0, 0, 0, 0,
     299             :      0},
     300             :     {6317, 156, "Dealul Piscului 1970", 3, 28, -121, -77, 0, 0, 0, 0, 0},
     301             :     {0, 157, "WGS_1984", 54, 0, 0, 0, 0, 0, 0, 0, 0},  // Google merc
     302             :     {6150, 158, "CH1903+ datum for Switzerland", 10, 674.374, 15.056, 405.346,
     303             :      0, 0, 0, 0, 0},
     304             :     {0, 159, "Schwarzeck (updated) datum for Namibia", 14, 616.8, 103.3, -256.9,
     305             :      0, 0, 0, 0, 0},
     306             :     {0, 161, "NOAA GCS_Sphere", 55, 0, 0, 0, 0, 0, 0, 0, 0},
     307             :     // Ellipsoid 40 got from https://docs.precisely.com/docs/sftw/mapinfo-pro/v2021/en-us/pdf/mapinfo-pro-v2021-user-guide.pdf
     308             :     // Ellipsoid 40 is "Everest (India 1956)", 6377301.243, 300.80174
     309             :     // but EPSG uses "Everest 1830 (RSO 1969)",6377295.664,300.8017
     310             :     {6751, 164, "Kertau (RSO)", 40, -11, 851, 5, 0, 0, 0, 0, 0},
     311             :     {0, 1000, "DHDN_Potsdam_Rauenberg", 10, 582, 105, 414, -1.04, -0.35, 3.08,
     312             :      8.3, 0},
     313             :     {6284, 1001, "Pulkovo_1942", 3, 24, -123, -94, -0.02, 0.25, 0.13, 1.1, 0},
     314             :     {6807, 1002, "NTF_Paris_Meridian", 30, -168, -60, 320, 0, 0, 0, 0,
     315             :      2.337229166667},
     316             :     {6149, 1003, "Switzerland_CH_1903", 10, 660.077, 13.551, 369.344, 0.804816,
     317             :      0.577692, 0.952236, 5.66, 0},
     318             :     {6237, 1004, "Hungarian_Datum_1972", 21, -56, 75.77, 15.31, -0.37, -0.2,
     319             :      -0.21, -1.01, 0},
     320             :     {0, 1005, "Cape_7_Parameter", 28, -134.73, -110.92, -292.66, 0, 0, 0, 1, 0},
     321             :     {6203, 1006, "AGD84_7_Param_Aust", 2, -117.763, -51.51, 139.061, -0.292,
     322             :      -0.443, -0.277, -0.191, 0},
     323             :     {0, 1007, "AGD66_7_Param_ACT", 2, -129.193, -41.212, 130.73, -0.246, -0.374,
     324             :      -0.329, -2.955, 0},
     325             :     {0, 1008, "AGD66_7_Param_TAS", 2, -120.271, -64.543, 161.632, -0.2175,
     326             :      0.0672, 0.1291, 2.4985, 0},
     327             :     {0, 1009, "AGD66_7_Param_VIC_NSW", 2, -119.353, -48.301, 139.484, -0.415,
     328             :      -0.26, -0.437, -0.613, 0},
     329             :     {6272, 1010, "NZGD_7_Param_49", 4, 59.47, -5.04, 187.44, -0.47, 0.1, -1.024,
     330             :      -4.5993, 0},
     331             :     {0, 1011, "Rikets_Tri_7_Param_1990", 10, 419.3836, 99.3335, 591.3451,
     332             :      -0.850389, -1.817277, 7.862238, -0.99496, 0},
     333             :     {0, 1012, "Russia_PZ90", 52, -1.08, -0.27, -0.9, 0, 0, -0.16, -0.12, 0},
     334             :     {0, 1013, "Russia_SK42", 52, 23.92, -141.27, -80.9, 0, -0.35, -0.82, -0.12,
     335             :      0},
     336             :     {0, 1014, "Russia_SK95", 52, 24.82, -131.21, -82.66, 0, 0, -0.16, -0.12, 0},
     337             :     {6301, 1015, "Tokyo", 10, -146.414, 507.337, 680.507, 0, 0, 0, 0, 0},
     338             :     {6123, 1016, "Kartastokoordinaattijarjestelma_1966", 4, -96.062, -82.428,
     339             :      -121.754, -4.801, -0.345, 1.376, 1.496, 0},
     340             :     {6610, 1017, "Xian 1980", 53, 24, -123, -94, -0.02, -0.25, 0.13, 1.1, 0},
     341             :     {0, 1018, "Lithuanian Pulkovo 1942", 4, -40.59527, -18.54979, -69.33956,
     342             :      -2.508, -1.8319, 2.6114, -4.2991, 0},
     343             :     {6313, 1019, "Belgian 1972 7 Parameter", 4, -99.059, 53.322, -112.486,
     344             :      -0.419, 0.83, -1.885, 0.999999, 0},
     345             :     {6818, 1020, "S-JTSK with Ferro prime meridian", 10, 589, 76, 480, 0, 0, 0,
     346             :      0, -17.666666666667},
     347             :     {1031, 1021, "Serbia datum MGI 1901", 10, 574.027, 170.175, 401.545,
     348             :      4.88786, -0.66524, -13.24673, 6.88933, 0},
     349             :     {0, 1022, "North Sahara 7-parameter", 6, -38.7086, -128.8054, 118.8837,
     350             :      0.83822, 7.38459, -1.57989, 3.9904, 0},
     351             :     {0, 1023, "Hungarian Projection System (EOV) - updated", 21, 52.684,
     352             :      -71.194, -13.975, 0.312, 0.1063, 0.3729, 1.0191, 0},
     353             :     {1052, 1024, "S-JTSK (Krovak) Coordinate system - updated", 10, 570.6934,
     354             :      85.6936, 462.8393, -4.99825, -1.58663, -5.26114, 3.5430155, 0},
     355             :     {0, 1025, "JTSK03 (Slovak Republic)", 10, 485.014055, 169.473618,
     356             :      483.842943, -7.78625453, -4.39770887, -4.10248899, 0, 0},
     357             :     {1168, 1028, "Geocentric Datum of Australia 2020", 0, -0.06155, 0.01087,
     358             :      0.04019, 0.0394924, 0.0327221, 0.0328979, 0.009994, 0},
     359             :     // For some weird reason, MapInfo uses nEllipsoid=8 "Clarke 1866 (modified
     360             :     // for Michigan)" cf
     361             :     // https://docs.precisely.com/docs/sftw/mapinfo-pro/v2021.1/en-us/pdf/mapinfo-pro-v2021.1-release-notes.pdf
     362             :     // page 8 whereas EPSG uses the regular Clarke 1866 ellipsoid.
     363             :     {6683, 1031, "Philippine Reference System 1992", 8, -127.62, -67.24, -47.04,
     364             :      -3.068, 4.903, 1.578, -1.06, 0},
     365             :     {0, 9999, "Bosnia-Herzegovina", 10, 472.8677, 187.8769, 544.7084,
     366             :      -5.76198422, -5.3222842, 12.80666941, 1.54517287, 0},
     367             :     {6181, 9999, "Luxembourg 1930 / Gauss", 4, -192.986, 13.673, -39.309,
     368             :      0.4099, 2.9332, -2.6881, 0.43, 0},
     369             :     {1168, 9999, "Geocentric Datum of Australia 2020", 0, -0.06155, 0.01087,
     370             :      0.04019, 0.0394924, 0.0327221, 0.0328979, 0.009994, 0},
     371             :     {-1, -1, nullptr, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
     372             : 
     373             : /* -------------------------------------------------------------------- */
     374             : /*      This table was hand entered from Appendix I of the mapinfo 6    */
     375             : /*      manuals.                                                        */
     376             : /* -------------------------------------------------------------------- */
     377             : 
     378             : const MapInfoSpheroidInfo asSpheroidInfoList[] = {
     379             :     {9, "Airy 1930", 6377563.396, 299.3249646},
     380             :     {13, "Airy 1930 (modified for Ireland 1965", 6377340.189, 299.3249646},
     381             :     {51, "ATS77 (Average Terrestrial System 1977)", 6378135, 298.257},
     382             :     {2, "Australian", 6378160.0, 298.25},
     383             :     {10, "Bessel 1841", 6377397.155, 299.1528128},
     384             :     {35, "Bessel 1841 (modified for NGO 1948)", 6377492.0176, 299.15281},
     385             :     {14, "Bessel 1841 (modified for Schwarzeck)", 6377483.865, 299.1528128},
     386             :     {36, "Clarke 1858", 6378293.639, 294.26068},
     387             :     {7, "Clarke 1866", 6378206.4, 294.9786982},
     388             :     {8, "Clarke 1866 (modified for Michigan)", 6378450.047484481, 294.9786982},
     389             :     {6, "Clarke 1880", 6378249.145, 293.465},
     390             :     {15, "Clarke 1880 (modified for Arc 1950)", 6378249.145326, 293.4663076},
     391             :     {30, "Clarke 1880 (modified for IGN)", 6378249.2, 293.4660213},
     392             :     {37, "Clarke 1880 (modified for Jamaica)", 6378249.136, 293.46631},
     393             :     {16, "Clarke 1880 (modified for Merchich)", 6378249.2, 293.46598},
     394             :     {38, "Clarke 1880 (modified for Palestine)", 6378300.79, 293.46623},
     395             :     {39, "Everest (Brunei and East Malaysia)", 6377298.556, 300.8017},
     396             :     {11, "Everest (India 1830)", 6377276.345, 300.8017},
     397             :     {40, "Everest (India 1956)", 6377301.243, 300.80174},
     398             :     {50, "Everest (Pakistan)", 6377309.613, 300.8017},
     399             :     {17, "Everest (W. Malaysia and Singapore 1948)", 6377304.063, 300.8017},
     400             :     {48, "Everest (West Malaysia 1969)", 6377304.063, 300.8017},
     401             :     {18, "Fischer 1960", 6378166.0, 298.3},
     402             :     {19, "Fischer 1960 (modified for South Asia)", 6378155.0, 298.3},
     403             :     {20, "Fischer 1968", 6378150.0, 298.3},
     404             :     {21, "GRS 67", 6378160.0, 298.247167427},
     405             :     {0, "GRS 80", 6378137.0, 298.257222101},
     406             :     {56, "GSK2011", 6378136.5, 298.2564151},
     407             :     {5, "Hayford", 6378388.0, 297.0},
     408             :     {22, "Helmert 1906", 6378200.0, 298.3},
     409             :     {23, "Hough", 6378270.0, 297.0},
     410             :     {31, "IAG 75", 6378140.0, 298.257222},
     411             :     {41, "Indonesian", 6378160.0, 298.247},
     412             :     {4, "International 1924", 6378388.0, 297.0},
     413             :     {49, "Irish (WOFO)", 6377542.178, 299.325},
     414             :     {3, "Krassovsky", 6378245.0, 298.3},
     415             :     {32, "MERIT 83", 6378137.0, 298.257},
     416             :     {33, "New International 1967", 6378157.5, 298.25},
     417             :     {42, "NWL 9D", 6378145.0, 298.25},
     418             :     {43, "NWL 10D", 6378135.0, 298.26},
     419             :     {44, "OSU86F", 6378136.2, 298.25722},
     420             :     {45, "OSU91A", 6378136.3, 298.25722},
     421             :     {46, "Plessis 1817", 6376523.0, 308.64},
     422             :     {52, "PZ90", 6378136.0, 298.257839303},
     423             :     {57, "PZ90.11", 6378136.0, 298.25784},
     424             :     {24, "South American", 6378160.0, 298.25},
     425             :     {12, "Sphere", 6370997.0, 0.0},
     426             :     {47, "Struve 1860", 6378297.0, 294.73},
     427             :     {34, "Walbeck", 6376896.0, 302.78},
     428             :     {25, "War Office", 6378300.583, 296.0},
     429             :     {26, "WGS 60", 6378165.0, 298.3},
     430             :     {27, "WGS 66", 6378145.0, 298.25},
     431             :     {1, "WGS 72", 6378135.0, 298.26},
     432             :     {28, "WGS 84", 6378137.0, 298.257223563},
     433             :     {29, "WGS 84 (MAPINFO Datum 0)", 6378137.01, 298.257223563},
     434             :     {54, "WGS 84 (MAPINFO Datum 157)", 6378137.01, 298.257223563},
     435             :     {-1, nullptr, 0.0, 0.0}};
     436             : 
     437             : /* For LCC, standard parallel 1 and 2 can be switched indifferently */
     438             : /* So the MapInfo order and the EPSG order are not generally identical */
     439             : /* which may cause recognition problems when reading in MapInfo */
     440             : /* This table contains the parameters in the order expected by MapInfo */
     441             : typedef struct
     442             : {
     443             :     int nEPSGCode;
     444             :     int bReverseStdP;
     445             :     int nMapInfoDatumID;
     446             :     double dfCenterLong;
     447             :     double dfCenterLat;
     448             :     double dfStdP1;
     449             :     double dfStdP2;
     450             : } MapInfoLCCSRS;
     451             : 
     452             : static const MapInfoLCCSRS asMapInfoLCCSRSList[] = {
     453             :     {2154, 1, 33, 3, 46.5, 44, 49},
     454             :     {2154, 1, 33, 3, 46.5, 44, 49.00000000001},
     455             :     {2154, 1, 33, 3, 46.5, 44, 49.00000000002},
     456             :     {2225, 1, 74, -122, 39.3333333333, 40, 41.6666666667},
     457             :     {2226, 1, 74, -122, 37.6666666667, 38.3333333333, 39.8333333333},
     458             :     {2227, 1, 74, -120.5, 36.5, 37.0666666667, 38.4333333333},
     459             :     {2228, 1, 74, -119, 35.3333333333, 36, 37.25},
     460             :     {2229, 1, 74, -118, 33.5, 34.0333333333, 35.4666666667},
     461             :     {2230, 1, 74, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
     462             :     {2231, 1, 74, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
     463             :     {2232, 1, 74, -105.5, 37.8333333333, 38.45, 39.75},
     464             :     {2233, 1, 74, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
     465             :     {2234, 1, 74, -72.75, 40.8333333333, 41.2, 41.8666666667},
     466             :     {2238, 1, 74, -84.5, 29, 29.5833333333, 30.75},
     467             :     {2246, 0, 74, -84.25, 37.5, 37.9666666667, 38.9666666667},
     468             :     {2247, 1, 74, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
     469             :     {2248, 1, 74, -77, 37.6666666667, 38.3, 39.45},
     470             :     {2249, 1, 74, -71.5, 41, 41.7166666667, 42.6833333333},
     471             :     {2250, 1, 74, -70.5, 41, 41.2833333333, 41.4833333333},
     472             :     {2251, 1, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
     473             :     {2252, 1, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
     474             :     {2253, 1, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
     475             :     {2256, 1, 74, -109.5, 44.25, 45, 49},
     476             :     {2263, 1, 74, -74, 40.1666666667, 40.6666666667, 41.0333333333},
     477             :     {2264, 1, 74, -79, 33.75, 34.3333333333, 36.1666666667},
     478             :     {2265, 1, 74, -100.5, 47, 47.4333333333, 48.7333333333},
     479             :     {2266, 1, 74, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
     480             :     {2267, 1, 74, -98, 35, 35.5666666667, 36.7666666667},
     481             :     {2268, 1, 74, -98, 33.3333333333, 33.9333333333, 35.2333333333},
     482             :     {2269, 1, 74, -120.5, 43.6666666667, 44.3333333333, 46},
     483             :     {2270, 1, 74, -120.5, 41.6666666667, 42.3333333333, 44},
     484             :     {2271, 1, 74, -77.75, 40.1666666667, 40.8833333333, 41.95},
     485             :     {2272, 1, 74, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
     486             :     {2273, 1, 74, -81, 31.8333333333, 32.5, 34.8333333333},
     487             :     {2274, 1, 74, -86, 34.3333333333, 35.25, 36.4166666667},
     488             :     {2275, 1, 74, -101.5, 34, 34.65, 36.1833333333},
     489             :     {2276, 1, 74, -98.5, 31.6666666667, 32.1333333333, 33.9666666667},
     490             :     {2277, 1, 74, -100.3333333333, 29.6666666667, 30.1166666667, 31.8833333333},
     491             :     {2278, 1, 74, -99, 27.8333333333, 28.3833333333, 30.2833333333},
     492             :     {2279, 1, 74, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
     493             :     {2280, 1, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
     494             :     {2281, 1, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
     495             :     {2282, 1, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
     496             :     {2283, 1, 74, -78.5, 37.6666666667, 38.0333333333, 39.2},
     497             :     {2284, 1, 74, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
     498             :     {2285, 1, 74, -120.8333333333, 47, 47.5, 48.7333333333},
     499             :     {2286, 1, 74, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
     500             :     {2287, 1, 74, -90, 45.1666666667, 45.5666666667, 46.7666666667},
     501             :     {2288, 1, 74, -90, 43.8333333333, 44.25, 45.5},
     502             :     {2289, 1, 74, -90, 42, 42.7333333333, 44.0666666667},
     503             :     {26740, 1, 63, -176, 51, 51.8333333333, 53.8333333333},
     504             :     {26741, 1, 62, -122, 39.3333333333, 40, 41.6666666667},
     505             :     {26742, 1, 62, -122, 37.6666666667, 38.3333333333, 39.8333333333},
     506             :     {26743, 1, 62, -120.5, 36.5, 37.0666666667, 38.4333333333},
     507             :     {26744, 1, 62, -119, 35.3333333333, 36, 37.25},
     508             :     {26745, 1, 62, -118, 33.5, 34.0333333333, 35.4666666667},
     509             :     {26746, 1, 62, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
     510             :     {26747, 1, 62, -118.3333333333, 34.1333333333, 33.8666666667,
     511             :      34.4166666667},
     512             :     {26751, 1, 62, -92, 34.3333333333, 34.9333333333, 36.2333333333},
     513             :     {26752, 1, 62, -92, 32.6666666667, 33.3, 34.7666666667},
     514             :     {26753, 0, 62, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
     515             :     {26754, 1, 62, -105.5, 37.8333333333, 38.45, 39.75},
     516             :     {26755, 1, 62, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
     517             :     {26756, 1, 62, -72.75, 40.8333333333, 41.2, 41.8666666667},
     518             :     {26760, 1, 62, -84.5, 29, 29.5833333333, 30.75},
     519             :     {26775, 1, 62, -93.5, 41.5, 42.0666666667, 43.2666666667},
     520             :     {26776, 1, 62, -93.5, 40, 40.6166666667, 41.7833333333},
     521             :     {26777, 1, 62, -98, 38.3333333333, 38.7166666667, 39.7833333333},
     522             :     {26778, 0, 62, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
     523             :     {26779, 0, 62, -84.25, 37.5, 37.9666666667, 38.9666666667},
     524             :     {26780, 0, 62, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
     525             :     {26781, 0, 62, -92.5, 30.6666666667, 31.1666666667, 32.6666666667},
     526             :     {26785, 0, 62, -77, 37.8333333333, 38.3, 39.45},
     527             :     {26786, 0, 62, -71.5, 41, 41.7166666667, 42.6833333333},
     528             :     {26788, 0, 73, -87, 44.7833333333, 45.4833333333, 47.0833333333},
     529             :     {26789, 0, 73, -84.3333333333, 43.3166666667, 44.1833333333, 45.7},
     530             :     {26790, 0, 73, -84.3333333333, 41.5, 42.1, 43.6666666667},
     531             :     {26791, 0, 62, -93.1, 46.5, 47.0333333333, 48.6333333333},
     532             :     {26792, 0, 62, -94.25, 45, 45.6166666667, 47.05},
     533             :     {26793, 0, 62, -94, 43, 43.7833333333, 45.2166666667},
     534             :     {26940, 1, 74, -176, 51, 51.8333333333, 53.8333333333},
     535             :     {26941, 1, 74, -122, 39.3333333333, 40, 41.6666666667},
     536             :     {26942, 1, 74, -122, 37.6666666667, 38.3333333333, 39.8333333333},
     537             :     {26943, 1, 74, -120.5, 36.5, 37.0666666667, 38.4333333333},
     538             :     {26944, 1, 74, -119, 35.3333333333, 36, 37.25},
     539             :     {26945, 1, 74, -118, 33.5, 34.0333333333, 35.4666666667},
     540             :     {26946, 1, 74, -116.25, 32.1666666667, 32.7833333333, 33.8833333333},
     541             :     {26951, 1, 74, -92, 34.3333333333, 34.9333333333, 36.2333333333},
     542             :     {26952, 1, 74, -92, 32.6666666667, 33.3, 34.7666666667},
     543             :     {26953, 1, 74, -105.5, 39.3333333333, 39.7166666667, 40.7833333333},
     544             :     {26954, 1, 74, -105.5, 37.8333333333, 38.45, 39.75},
     545             :     {26955, 1, 74, -105.5, 36.6666666667, 37.2333333333, 38.4333333333},
     546             :     {26956, 1, 74, -72.75, 40.8333333333, 41.2, 41.8666666667},
     547             :     {26960, 1, 74, -84.5, 29, 29.5833333333, 30.75},
     548             :     {26975, 1, 74, -93.5, 41.5, 42.0666666667, 43.2666666667},
     549             :     {26976, 1, 74, -93.5, 40, 40.6166666667, 41.7833333333},
     550             :     {26977, 1, 74, -98, 38.3333333333, 38.7166666667, 39.7833333333},
     551             :     {26978, 0, 74, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
     552             :     {26980, 1, 74, -85.75, 36.3333333333, 36.7333333333, 37.9333333333},
     553             :     {26981, 1, 74, -92.5, 30.5, 31.1666666667, 32.6666666667},
     554             :     {26982, 1, 74, -91.3333333333, 28.5, 29.3, 30.7},
     555             :     {26985, 1, 74, -77, 37.6666666667, 38.3, 39.45},
     556             :     {26986, 1, 74, -71.5, 41, 41.7166666667, 42.6833333333},
     557             :     {26987, 1, 74, -70.5, 41, 41.2833333333, 41.4833333333},
     558             :     {26988, 1, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
     559             :     {26989, 1, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
     560             :     {26990, 1, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
     561             :     {26991, 1, 74, -93.1, 46.5, 47.0333333333, 48.6333333333},
     562             :     {26992, 1, 74, -94.25, 45, 45.6166666667, 47.05},
     563             :     {26993, 1, 74, -94, 43, 43.7833333333, 45.2166666667},
     564             :     {3111, 0, 116, 145, -37, -36, -38},
     565             :     {31370, 1, 1019, 4.3674866667, 90, 49.8333339000, 51.1666672333},
     566             :     {32001, 1, 62, -109.5, 47, 47.85, 48.7166666667},
     567             :     {32002, 1, 62, -109.5, 45.8333333333, 46.45, 47.8833333333},
     568             :     {32003, 1, 62, -109.5, 44, 44.8666666667, 46.4},
     569             :     {32005, 0, 62, -100, 41.3333333333, 41.85, 42.8166666667},
     570             :     {32006, 0, 62, -99.5, 39.6666666667, 40.2833333333, 41.7166666667},
     571             :     {32018, 1, 62, -74, 40.5, 40.6666666667, 41.0333333333},
     572             :     {32019, 0, 62, -79, 33.75, 34.3333333333, 36.1666666667},
     573             :     {32020, 0, 62, -100.5, 47, 47.4333333333, 48.7333333333},
     574             :     {32021, 0, 62, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
     575             :     {32022, 0, 62, -82.5, 39.6666666667, 40.4333333333, 41.7},
     576             :     {32023, 0, 62, -82.5, 38, 38.7333333333, 40.0333333333},
     577             :     {32024, 0, 62, -98, 35, 35.5666666667, 36.7666666667},
     578             :     {32025, 0, 62, -98, 33.3333333333, 33.9333333333, 35.2333333333},
     579             :     {32026, 0, 62, -120.5, 43.6666666667, 44.3333333333, 46},
     580             :     {32027, 0, 62, -120.5, 41.6666666667, 42.3333333333, 44},
     581             :     {32028, 0, 62, -77.75, 40.1666666667, 40.8833333333, 41.95},
     582             :     {32031, 0, 62, -81, 33, 33.7666666667, 34.9666666667},
     583             :     {32033, 0, 62, -81, 31.8333333333, 32.3333333333, 33.6666666667},
     584             :     {32034, 0, 62, -100, 43.8333333333, 44.4166666667, 45.6833333333},
     585             :     {32035, 0, 62, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
     586             :     {32036, 0, 62, -86, 34.6666666667, 35.25, 36.4166666667},
     587             :     {32037, 0, 62, -101.5, 34, 34.65, 36.1833333333},
     588             :     {32038, 0, 62, -97.5, 31.6666666667, 32.1333333333, 33.9666666667},
     589             :     {32039, 0, 62, -100.3333333333, 29.6666666667, 30.1166666667,
     590             :      31.8833333333},
     591             :     {32040, 0, 62, -99, 27.8333333333, 28.3833333333, 30.2833333333},
     592             :     {32041, 0, 62, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
     593             :     {32042, 0, 62, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
     594             :     {32043, 0, 62, -111.5, 38.3333333333, 39.0166666667, 40.65},
     595             :     {32044, 0, 62, -111.5, 36.6666666667, 37.2166666667, 38.35},
     596             :     {32046, 0, 62, -78.5, 37.6666666667, 38.0333333333, 39.2},
     597             :     {32047, 0, 62, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
     598             :     {32048, 0, 62, -120.8333333333, 47, 47.5, 48.7333333333},
     599             :     {32049, 0, 62, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
     600             :     {32050, 0, 62, -79.5, 38.5, 39, 40.25},
     601             :     {32051, 0, 62, -81, 37, 37.4833333333, 38.8833333333},
     602             :     {32052, 0, 62, -90, 45.1666666667, 45.5666666667, 46.7666666667},
     603             :     {32053, 0, 62, -90, 43.8333333333, 44.25, 45.5},
     604             :     {32054, 0, 62, -90, 42, 42.7333333333, 44.0666666667},
     605             :     {32059, 0, 62, -66.4333333333, 18.4333333333, 18.0333333333, 18.4333333333},
     606             :     {32060, 0, 62, -66.4333333333, 18.4333333333, 18.0333333333, 18.4333333333},
     607             :     {32100, 1, 74, -109.5, 44.25, 45, 49},
     608             :     {32104, 1, 74, -100, 39.8333333333, 40, 43},
     609             :     {32118, 1, 74, -74, 40.1666666667, 40.6666666667, 41.0333333333},
     610             :     {32119, 1, 74, -79, 33.75, 34.3333333333, 36.1666666667},
     611             :     {32120, 1, 74, -100.5, 47, 47.4333333333, 48.7333333333},
     612             :     {32121, 1, 74, -100.5, 45.6666666667, 46.1833333333, 47.4833333333},
     613             :     {32122, 1, 74, -82.5, 39.6666666667, 40.4333333333, 41.7},
     614             :     {32123, 1, 74, -82.5, 38, 38.7333333333, 40.0333333333},
     615             :     {32124, 1, 74, -98, 35, 35.5666666667, 36.7666666667},
     616             :     {32125, 1, 74, -98, 33.3333333333, 33.9333333333, 35.2333333333},
     617             :     {32126, 1, 74, -120.5, 43.6666666667, 44.3333333333, 46},
     618             :     {32127, 1, 74, -120.5, 41.6666666667, 42.3333333333, 44},
     619             :     {32128, 1, 74, -77.75, 40.1666666667, 40.8833333333, 41.95},
     620             :     {32129, 1, 74, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
     621             :     {32133, 1, 74, -81, 31.8333333333, 32.5, 34.8333333333},
     622             :     {32134, 1, 74, -100, 43.8333333333, 44.4166666667, 45.6833333333},
     623             :     {32135, 1, 74, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
     624             :     {32136, 1, 74, -86, 34.3333333333, 35.25, 36.4166666667},
     625             :     {32137, 1, 74, -101.5, 34, 34.65, 36.1833333333},
     626             :     {32138, 1, 74, -98.5, 31.6666666667, 32.1333333333, 33.9666666667},
     627             :     {32139, 1, 74, -100.3333333333, 29.6666666667, 30.1166666667,
     628             :      31.8833333333},
     629             :     {32140, 1, 74, -99, 27.8333333333, 28.3833333333, 30.2833333333},
     630             :     {32141, 1, 74, -98.5, 25.6666666667, 26.1666666667, 27.8333333333},
     631             :     {32142, 1, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
     632             :     {32143, 1, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
     633             :     {32144, 1, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
     634             :     {32146, 1, 74, -78.5, 37.6666666667, 38.0333333333, 39.2},
     635             :     {32147, 1, 74, -78.5, 36.3333333333, 36.7666666667, 37.9666666667},
     636             :     {32148, 1, 74, -120.8333333333, 47, 47.5, 48.7333333333},
     637             :     {32149, 1, 74, -120.5, 45.3333333333, 45.8333333333, 47.3333333333},
     638             :     {32150, 1, 74, -79.5, 38.5, 39, 40.25},
     639             :     {32151, 1, 74, -81, 37, 37.4833333333, 38.8833333333},
     640             :     {32152, 1, 74, -90, 45.1666666667, 45.5666666667, 46.7666666667},
     641             :     {32153, 1, 74, -90, 43.8333333333, 44.25, 45.5},
     642             :     {32154, 1, 74, -90, 42, 42.7333333333, 44.0666666667},
     643             :     {32161, 1, 74, -66.4333333333, 17.8333333333, 18.0333333333, 18.4333333333},
     644             :     {3300, 1, 115, 24, 57.51755394, 58, 59.33333333},
     645             :     {3301, 1, 115, 24, 57.51755393056, 58, 59.33333333},
     646             :     {3797, 0, 66, -70, 44, 50, 46},
     647             :     {3798, 0, 74, -70, 44, 50, 46},
     648             :     {3799, 0, 74, -70, 44, 50, 46},
     649             :     {3942, 0, 33, 3, 42, 41.25, 42.75},
     650             :     {3943, 0, 33, 3, 43, 42.25, 43.75},
     651             :     {3944, 0, 33, 3, 44, 43.25, 44.75},
     652             :     {3945, 0, 33, 3, 45, 44.25, 45.75},
     653             :     {3946, 0, 33, 3, 46, 45.25, 46.75},
     654             :     {3947, 0, 33, 3, 47, 46.25, 47.75},
     655             :     {3948, 0, 33, 3, 48, 47.25, 48.75},
     656             :     {3949, 0, 33, 3, 49, 48.25, 49.75},
     657             :     {3950, 0, 33, 3, 50, 49.25, 50.75},
     658             :     {42101, 0, 104, -95, 0, 49, 77},
     659             :     {42103, 0, 104, -100, 0, 33, 45},
     660             :     {42304, 0, 74, -95, 49, 49, 77},
     661             :     {0, 0, 0, 110, 10, 25, 40},
     662             :     {0, 0, 0, 132.5, -10, -21.5, -33.5},
     663             :     {0, 0, 0, 25, 35, 40, 65},
     664             :     {0, 0, 0, 47.5, 25, 15, 35},
     665             :     {0, 0, 0, 95, 40, 20, 60},
     666             :     {0, 0, 1002, 0, 42.165, 41.5603877778, 42.76766333},
     667             :     {0, 0, 1002, 0, 42.165, 41.5603877778, 42.767663333},
     668             :     {0, 0, 1002, 0, 42.165, 41.560387778, 42.76766333},
     669             :     {0, 0, 1002, 0, 42.165, 41.560387778, 42.767663333},
     670             :     {0, 0, 1002, 0, 42.165, 41.56038778, 42.76766333},
     671             :     {0, 0, 1002, 0, 42.165, 41.560387840948, 42.76766346965},
     672             :     {0, 0, 1002, 0, 44.1, 43.199291275544, 44.996093814511},
     673             :     {0, 0, 1002, 0, 44.1, 43.1992913889, 44.99609389},
     674             :     {0, 0, 1002, 0, 44.1, 43.199291389, 44.99609389},
     675             :     {0, 0, 1002, 0, 44.1, 43.19929139, 44.99609389},
     676             :     {0, 0, 1002, 0, 46.8, 45.8989188889, 47.69601444},
     677             :     {0, 0, 1002, 0, 46.8, 45.898918889, 47.69601444},
     678             :     {0, 0, 1002, 0, 46.8, 45.89891889, 47.69601444},
     679             :     {0, 0, 1002, 0, 46.8, 45.898918964419, 47.696014502038},
     680             :     {0, 0, 1002, 0, 49.5, 48.5985227778, 50.39591167},
     681             :     {0, 0, 1002, 0, 49.5, 48.598522778, 50.39591167},
     682             :     {0, 0, 1002, 0, 49.5, 48.59852278, 50.39591167},
     683             :     {0, 0, 1002, 0, 49.5, 48.598522847174, 50.395911631678},
     684             :     {0, 0, 1005, 23, -23, -18, -32},
     685             :     {0, 0, 1022, 2.7, 36, 37.575, 34.425},
     686             :     {0, 0, 104, 13.33333333, 47.5, 46, 49},
     687             :     {0, 0, 104, 13.33333333, 48, 46, 49},
     688             :     {0, 0, 104, -19, 65, 64.25, 65.75},
     689             :     {0, 0, 104, 36.0, 25.0, 37.5, 40.5},
     690             :     {0, 0, 104, 36, 25, 37.5, 40.5},
     691             :     {0, 0, 104, 70, -50, -68.5, -74.5},
     692             :     {0, 0, 110, 4.367975, 90, 49.8333333333, 51.1666666667},
     693             :     {0, 0, 115, 10, 52, 35, 45},
     694             :     {0, 0, 116, 135, -24, -18, -36},
     695             :     {0, 0, 116, 135, -32, -28, -36},
     696             :     {0, 0, 12, 135, -24, -18, -36},
     697             :     {0, 0, 12, 145, -37, -36, -38},
     698             :     {0, 0, 13, 135, -24, -18, -36},
     699             :     {0, 0, 19, 23, -23, -18, -32},
     700             :     {0, 0, 28, 17, 29.77930555, 42, 56},
     701             :     {0, 0, 28, 19, 29.77930555, 42, 56},
     702             :     {0, 0, 28, 36.0, 25.0, 37.5, 40.5},
     703             :     {0, 0, 33, 13.5, 0, 52.6666666667, 55.3333333333},
     704             :     {0, 0, 33, 15, 0, 56.5, 60.5},
     705             :     {0, 0, 33, 15, 0, 58, 66},
     706             :     {0, 0, 33, 15, 0, 63.5, 67.5},
     707             :     {0, 0, 33, 15.5, 0, 56.6666666667, 59.3333333333},
     708             :     {0, 0, 33, 15.5, 0, 60.6666666667, 63.3333333333},
     709             :     {0, 0, 33, 16.5, 0, 60.6666666667, 63.3333333333},
     710             :     {0, 0, 33, 18.5, 0, 64.6666666667, 67.3333333333},
     711             :     {0, 0, 33, 19, 0, 64.6666666667, 67.3333333333},
     712             :     {0, 0, 55, -5.4, 22.5, 20.9075742561, 24.0921050540},
     713             :     {0, 0, 55, -5.4, 26.1, 24.5075340813, 27.6921073632},
     714             :     {0, 0, 55, -5.4, 29.7, 28.1063294800, 31.2932791054},
     715             :     {0, 0, 55, -5.4, 33.3, 31.72786641202, 34.8717272112},
     716             :     {0, 0, 62, -70.5, 41, 41.2833333333, 41.4833333333},
     717             :     {0, 0, 62, -77.75, 39.3333333333, 39.9333333333, 40.9666666667},
     718             :     {0, 0, 62, -91.3333333333, 25.6666666667, 26.1666666667, 27.8333333333},
     719             :     {0, 0, 62, -91.3333333333, 28.6666666667, 29.3, 30.67},
     720             :     {0, 0, 62, -96, 23, 20, 60},
     721             :     {0, 0, 62, -96, 23, 33, 45},
     722             :     {0, 0, 62, -96, 39, 33, 45},
     723             :     {0, 0, 66, -68.5, 44, 46, 60},
     724             :     {0, 0, 74, -100.3333333333, 42.3333333333, 42.8333333333, 44.4},
     725             :     {0, 0, 74, -100, 39.8333333333, 40, 43},
     726             :     {0, 0, 74, -100, 43.8333333333, 44.4166666667, 45.6833333333},
     727             :     {0, 0, 74, -109.5, 44.25, 45, 49},
     728             :     {0, 0, 74, -111.5, 36.6666666667, 37.2166666667, 38.35},
     729             :     {0, 0, 74, -111.5, 38.3333333333, 39.0166666667, 40.65},
     730             :     {0, 0, 74, -111.5, 40.3333333333, 40.7166666667, 41.7833333333},
     731             :     {0, 0, 74, -120.5, 41.6666666667, 42.3333333333, 44},
     732             :     {0, 0, 74, -120.5, 43.6666666667, 44.3333333333, 46},
     733             :     {0, 0, 74, -176, 51, 51.8333333333, 53.8333333333},
     734             :     {0, 0, 74, -66.4333333333, 17.8333333333, 18.0333333333, 18.4333333333},
     735             :     {0, 0, 74, -68.5, 44, 46, 60},
     736             :     {0, 0, 74, -79.5, 38.5, 39, 40.25},
     737             :     {0, 0, 74, -81, 31.8333333333, 32.5, 34.8333333333},
     738             :     {0, 0, 74, -81, 37, 37.4833333333, 38.8833333333},
     739             :     {0, 0, 74, -82.5, 38, 38.7333333333, 40.0333333333},
     740             :     {0, 0, 74, -82.5, 39.6666666667, 40.4333333333, 41.7},
     741             :     {0, 0, 74, -84.25, 37.5, 37.9666666667, 38.9666666667},
     742             :     {0, 0, 74, -84.3666666667, 41.5, 42.1, 43.6666666667},
     743             :     {0, 0, 74, -84.3666666667, 43.3166666667, 44.1833333333, 45.7},
     744             :     {0, 0, 74, -87, 44.7833333333, 45.4833333333, 47.0833333333},
     745             :     {0, 0, 74, -91.3333333333, 25.5, 26.1666666667, 27.8333333333},
     746             :     {0, 0, 74, -91.3333333333, 28.5, 29.3, 30.7},
     747             :     {0, 0, 74, -92, 32.6666666667, 33.3, 34.7666666667},
     748             :     {0, 0, 74, -92, 34.3333333333, 34.9333333333, 36.2333333333},
     749             :     {0, 0, 74, -92.5, 30.5, 31.1666666667, 32.6666666667},
     750             :     {0, 0, 74, -93.1, 46.5, 47.0333333333, 48.6333333333},
     751             :     {0, 0, 74, -93.5, 40, 40.6166666667, 41.7833333333},
     752             :     {0, 0, 74, -93.5, 41.5, 42.0666666667, 43.2666666667},
     753             :     {0, 0, 74, -94.25, 45, 45.6166666667, 47.05},
     754             :     {0, 0, 74, -94, 43, 43.7833333333, 45.2166666667},
     755             :     {0, 0, 74, -98, 38.3333333333, 38.7166666667, 39.7833333333},
     756             :     {0, 0, 74, -98.5, 36.6666666667, 38.5666666667, 37.2666666667},
     757             : };
     758             : 
     759             : /**********************************************************************
     760             :  *                   TABFile::GetSpatialRefFromTABProj()
     761             :  **********************************************************************/
     762             : 
     763       11015 : static bool TAB_EQUAL(double a, double b)
     764             : {
     765       11015 :     return std::fabs(a - b) < 1.0e-10;
     766             : }
     767             : 
     768             : OGRSpatialReference *
     769        1442 : TABFileGetSpatialRefFromTABProj(const TABProjInfo &sTABProj)
     770             : {
     771             :     /*-----------------------------------------------------------------
     772             :      * Get the units name, and translation factor.
     773             :      *----------------------------------------------------------------*/
     774        1442 :     const char *pszUnitsName = nullptr;
     775        1442 :     const char *pszUnitsConv = nullptr;
     776             :     /* double      dfConv = 1.0; */
     777             : 
     778        1442 :     switch (sTABProj.nUnitsId)
     779             :     {
     780          16 :         case 0:
     781          16 :             pszUnitsName = "Mile";
     782          16 :             pszUnitsConv = "1609.344";
     783          16 :             break;
     784             : 
     785           2 :         case 1:
     786           2 :             pszUnitsName = "Kilometer";
     787           2 :             pszUnitsConv = "1000.0";
     788           2 :             break;
     789             : 
     790           2 :         case 2:
     791           2 :             pszUnitsName = "IINCH";
     792           2 :             pszUnitsConv = "0.0254";
     793           2 :             break;
     794             : 
     795           4 :         case 3:
     796           4 :             pszUnitsName = SRS_UL_FOOT;
     797           4 :             pszUnitsConv = SRS_UL_FOOT_CONV;
     798           4 :             break;
     799             : 
     800           2 :         case 4:
     801           2 :             pszUnitsName = "IYARD";
     802           2 :             pszUnitsConv = "0.9144";
     803           2 :             break;
     804             : 
     805           2 :         case 5:
     806           2 :             pszUnitsName = "Millimeter";
     807           2 :             pszUnitsConv = "0.001";
     808           2 :             break;
     809             : 
     810           2 :         case 6:
     811           2 :             pszUnitsName = "Centimeter";
     812           2 :             pszUnitsConv = "0.01";
     813           2 :             break;
     814             : 
     815        1395 :         case 7:
     816        1395 :             pszUnitsName = SRS_UL_METER;
     817        1395 :             pszUnitsConv = "1.0";
     818        1395 :             break;
     819             : 
     820           8 :         case 8:
     821           8 :             pszUnitsName = SRS_UL_US_FOOT;
     822           8 :             pszUnitsConv = SRS_UL_US_FOOT_CONV;
     823           8 :             break;
     824             : 
     825           2 :         case 9:
     826           2 :             pszUnitsName = SRS_UL_NAUTICAL_MILE;
     827           2 :             pszUnitsConv = SRS_UL_NAUTICAL_MILE_CONV;
     828           2 :             break;
     829             : 
     830           2 :         case 30:
     831           2 :             pszUnitsName = SRS_UL_LINK;
     832           2 :             pszUnitsConv = SRS_UL_LINK_CONV;
     833           2 :             break;
     834             : 
     835           2 :         case 31:
     836           2 :             pszUnitsName = SRS_UL_CHAIN;
     837           2 :             pszUnitsConv = SRS_UL_CHAIN_CONV;
     838           2 :             break;
     839             : 
     840           2 :         case 32:
     841           2 :             pszUnitsName = SRS_UL_ROD;
     842           2 :             pszUnitsConv = SRS_UL_ROD_CONV;
     843           2 :             break;
     844             : 
     845           1 :         default:
     846           1 :             pszUnitsName = SRS_UL_METER;
     847           1 :             pszUnitsConv = "1.0";
     848           1 :             break;
     849             :     }
     850             : 
     851             :     /* dfConv = CPLAtof(pszUnitsConv); */
     852             : 
     853             :     /*-----------------------------------------------------------------
     854             :      * Transform them into an OGRSpatialReference.
     855             :      *----------------------------------------------------------------*/
     856        1442 :     OGRSpatialReference *poSpatialRef = new OGRSpatialReference;
     857        1442 :     poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     858             : 
     859             :     /*-----------------------------------------------------------------
     860             :      * Handle the PROJCS style projections, but add the datum later.
     861             :      *----------------------------------------------------------------*/
     862        1442 :     switch (sTABProj.nProjId)
     863             :     {
     864        1259 :         case 0:
     865        1259 :             poSpatialRef->SetLocalCS("Nonearth");
     866        1259 :             poSpatialRef->SetLinearUnits(pszUnitsName, CPLAtof(pszUnitsConv));
     867        1259 :             break;
     868             : 
     869             :             /*--------------------------------------------------------------
     870             :              * lat/long .. just add the GEOGCS later.
     871             :              *-------------------------------------------------------------*/
     872          15 :         case 1:
     873          15 :             break;
     874             : 
     875             :             /*--------------------------------------------------------------
     876             :              * Cylindrical Equal Area
     877             :              *-------------------------------------------------------------*/
     878           2 :         case 2:
     879           2 :             poSpatialRef->SetCEA(
     880           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     881           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
     882           2 :             break;
     883             : 
     884             :             /*--------------------------------------------------------------
     885             :              * Lambert Conic Conformal
     886             :              *-------------------------------------------------------------*/
     887          55 :         case 3:
     888          55 :             poSpatialRef->SetLCC(
     889          55 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     890          55 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     891          55 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
     892          55 :             break;
     893             : 
     894             :             /*--------------------------------------------------------------
     895             :              * Lambert Azimuthal Equal Area
     896             :              *-------------------------------------------------------------*/
     897           2 :         case 4:
     898             :         case 29:
     899           2 :             poSpatialRef->SetLAEA(sTABProj.adProjParams[1],
     900           2 :                                   sTABProj.adProjParams[0], 0.0, 0.0);
     901           2 :             break;
     902             : 
     903             :             /*--------------------------------------------------------------
     904             :              * Azimuthal Equidistant (Polar aspect only)
     905             :              *-------------------------------------------------------------*/
     906           4 :         case 5:
     907             :         case 28:
     908           4 :             poSpatialRef->SetAE(sTABProj.adProjParams[1],
     909           4 :                                 sTABProj.adProjParams[0], 0.0, 0.0);
     910           4 :             break;
     911             : 
     912             :             /*--------------------------------------------------------------
     913             :              * Equidistant Conic
     914             :              *-------------------------------------------------------------*/
     915           2 :         case 6:
     916           2 :             poSpatialRef->SetEC(
     917           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     918           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     919           2 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
     920           2 :             break;
     921             : 
     922             :             /*--------------------------------------------------------------
     923             :              * Hotine Oblique Mercator
     924             :              *-------------------------------------------------------------*/
     925           2 :         case 7:
     926           2 :             poSpatialRef->SetHOM(
     927           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     928           2 :                 sTABProj.adProjParams[2], 90.0, sTABProj.adProjParams[3],
     929           2 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
     930           2 :             break;
     931             : 
     932             :             /*--------------------------------------------------------------
     933             :              * Hotine Oblique Mercator with Angle from Rectified to Skew Grid
     934             :              *-------------------------------------------------------------*/
     935           5 :         case 35:
     936           5 :             poSpatialRef->SetHOM(
     937           5 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     938           5 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     939           5 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5],
     940           5 :                 sTABProj.adProjParams[6]);
     941           5 :             break;
     942             : 
     943             :             /*--------------------------------------------------------------
     944             :              * Transverse Mercator
     945             :              *-------------------------------------------------------------*/
     946          53 :         case 8:
     947             :         case 34:  // Extended Transverse Mercator
     948          53 :             poSpatialRef->SetTM(
     949          53 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     950          53 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     951          53 :                 sTABProj.adProjParams[4]);
     952          53 :             break;
     953             : 
     954             :             /*----------------------------------------------------------------
     955             :              * Transverse Mercator,(modified for Danish System 34 Jylland-Fyn)
     956             :              *---------------------------------------------------------------*/
     957           0 :         case 21:
     958             :             // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_21,
     959           0 :             poSpatialRef->SetTM(
     960           0 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     961           0 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     962           0 :                 sTABProj.adProjParams[4]);
     963           0 :             break;
     964             : 
     965             :             /*--------------------------------------------------------------
     966             :              * Transverse Mercator,(modified for Danish System 34 Sjaelland)
     967             :              *-------------------------------------------------------------*/
     968           0 :         case 22:
     969             :             // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_22,
     970           0 :             poSpatialRef->SetTM(
     971           0 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     972           0 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     973           0 :                 sTABProj.adProjParams[4]);
     974           0 :             break;
     975             : 
     976             :             /*----------------------------------------------------------------
     977             :              * Transverse Mercator,(modified for Danish System 34/45 Bornholm)
     978             :              *---------------------------------------------------------------*/
     979           0 :         case 23:
     980             :             // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_23,
     981           0 :             poSpatialRef->SetTM(
     982           0 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     983           0 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     984           0 :                 sTABProj.adProjParams[4]);
     985           0 :             break;
     986             : 
     987             :             /*--------------------------------------------------------------
     988             :              * Transverse Mercator,(modified for Finnish KKJ)
     989             :              *-------------------------------------------------------------*/
     990           3 :         case 24:
     991             :             // poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_24,
     992           3 :             poSpatialRef->SetTM(
     993           3 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
     994           3 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
     995           3 :                 sTABProj.adProjParams[4]);
     996           3 :             break;
     997             : 
     998             :             /*--------------------------------------------------------------
     999             :              * Albers Conic Equal Area
    1000             :              *-------------------------------------------------------------*/
    1001           2 :         case 9:
    1002           2 :             poSpatialRef->SetACEA(
    1003           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
    1004           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1005           2 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
    1006           2 :             break;
    1007             : 
    1008             :             /*--------------------------------------------------------------
    1009             :              * Mercator
    1010             :              *-------------------------------------------------------------*/
    1011           4 :         case 10:
    1012           4 :             poSpatialRef->SetMercator(0.0, sTABProj.adProjParams[0], 1.0, 0.0,
    1013             :                                       0.0);
    1014           4 :             break;
    1015             : 
    1016             :             /*--------------------------------------------------------------
    1017             :              * Miller Cylindrical
    1018             :              *-------------------------------------------------------------*/
    1019           2 :         case 11:
    1020           2 :             poSpatialRef->SetMC(0.0, sTABProj.adProjParams[0], 0.0, 0.0);
    1021           2 :             break;
    1022             : 
    1023             :             /*--------------------------------------------------------------
    1024             :              * Robinson
    1025             :              *-------------------------------------------------------------*/
    1026           2 :         case 12:
    1027           2 :             poSpatialRef->SetRobinson(sTABProj.adProjParams[0], 0.0, 0.0);
    1028           2 :             break;
    1029             : 
    1030             :             /*--------------------------------------------------------------
    1031             :              * Mollweide
    1032             :              *-------------------------------------------------------------*/
    1033           2 :         case 13:
    1034           2 :             poSpatialRef->SetMollweide(sTABProj.adProjParams[0], 0.0, 0.0);
    1035           2 :             break;
    1036             : 
    1037             :             /*--------------------------------------------------------------
    1038             :              * Eckert IV
    1039             :              *-------------------------------------------------------------*/
    1040           2 :         case 14:
    1041           2 :             poSpatialRef->SetEckertIV(sTABProj.adProjParams[0], 0.0, 0.0);
    1042           2 :             break;
    1043             : 
    1044             :             /*--------------------------------------------------------------
    1045             :              * Eckert VI
    1046             :              *-------------------------------------------------------------*/
    1047           2 :         case 15:
    1048           2 :             poSpatialRef->SetEckertVI(sTABProj.adProjParams[0], 0.0, 0.0);
    1049           2 :             break;
    1050             : 
    1051             :             /*--------------------------------------------------------------
    1052             :              * Sinusoidal
    1053             :              *-------------------------------------------------------------*/
    1054           2 :         case 16:
    1055           2 :             poSpatialRef->SetSinusoidal(sTABProj.adProjParams[0], 0.0, 0.0);
    1056           2 :             break;
    1057             : 
    1058             :             /*--------------------------------------------------------------
    1059             :              * Gall Stereographic
    1060             :              *-------------------------------------------------------------*/
    1061           2 :         case 17:
    1062           2 :             poSpatialRef->SetGS(sTABProj.adProjParams[0], 0.0, 0.0);
    1063           2 :             break;
    1064             : 
    1065             :             /*--------------------------------------------------------------
    1066             :              * New Zealand Map Grid
    1067             :              *-------------------------------------------------------------*/
    1068           2 :         case 18:
    1069           2 :             poSpatialRef->SetNZMG(
    1070           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1071           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
    1072           2 :             break;
    1073             : 
    1074             :             /*--------------------------------------------------------------
    1075             :              * Lambert Conic Conformal (Belgium)
    1076             :              *-------------------------------------------------------------*/
    1077           2 :         case 19:
    1078           2 :             poSpatialRef->SetLCCB(
    1079           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
    1080           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1081           2 :                 sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
    1082           2 :             break;
    1083             : 
    1084             :             /*--------------------------------------------------------------
    1085             :              * Stereographic
    1086             :              *-------------------------------------------------------------*/
    1087           2 :         case 20:
    1088           2 :             poSpatialRef->SetStereographic(
    1089           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1090           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
    1091           2 :                 sTABProj.adProjParams[4]);
    1092           2 :             break;
    1093             : 
    1094             :             /*--------------------------------------------------------------
    1095             :              * Swiss Oblique Mercator / Cylindrical
    1096             :              *-------------------------------------------------------------*/
    1097           2 :         case 25:
    1098           2 :             poSpatialRef->SetSOC(
    1099           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1100           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
    1101           2 :             break;
    1102             : 
    1103             :             /*--------------------------------------------------------------
    1104             :              * Regional Mercator (regular mercator with a latitude).
    1105             :              *-------------------------------------------------------------*/
    1106           2 :         case 26:
    1107           2 :             poSpatialRef->SetMercator2SP(sTABProj.adProjParams[1], 0.0,
    1108           2 :                                          sTABProj.adProjParams[0], 0.0, 0.0);
    1109           2 :             break;
    1110             : 
    1111             :             /*--------------------------------------------------------------
    1112             :              * Polyconic
    1113             :              *-------------------------------------------------------------*/
    1114           2 :         case 27:
    1115           2 :             poSpatialRef->SetPolyconic(
    1116           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1117           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
    1118           2 :             break;
    1119             : 
    1120             :             /*--------------------------------------------------------------
    1121             :              * Cassini/Soldner
    1122             :              *-------------------------------------------------------------*/
    1123           2 :         case 30:
    1124           2 :             poSpatialRef->SetCS(
    1125           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1126           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
    1127           2 :             break;
    1128             : 
    1129             :             /*--------------------------------------------------------------
    1130             :              * Oblique Stereographic
    1131             :              *-------------------------------------------------------------*/
    1132           2 :         case 31:
    1133           2 :             poSpatialRef->SetOS(
    1134           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1135           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3],
    1136           2 :                 sTABProj.adProjParams[4]);
    1137           2 :             break;
    1138             : 
    1139             :             /*--------------------------------------------------------------
    1140             :              * Krovak
    1141             :              *-------------------------------------------------------------*/
    1142           2 :         case 32:
    1143           2 :             poSpatialRef->SetKrovak(
    1144           2 :                 sTABProj.adProjParams[1],   // dfCenterLat
    1145           2 :                 sTABProj.adProjParams[0],   // dfCenterLong
    1146           2 :                 sTABProj.adProjParams[3],   // dfAzimuth
    1147           2 :                 sTABProj.adProjParams[2],   // dfPseudoStdParallelLat
    1148             :                 1.0,                        // dfScale
    1149           2 :                 sTABProj.adProjParams[4],   // dfFalseEasting
    1150           2 :                 sTABProj.adProjParams[5]);  // dfFalseNorthing
    1151           2 :             break;
    1152             : 
    1153             :             /*--------------------------------------------------------------
    1154             :              * Equidistant Cylindrical / Equirectangular
    1155             :              *-------------------------------------------------------------*/
    1156           2 :         case 33:
    1157           2 :             poSpatialRef->SetEquirectangular(
    1158           2 :                 sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1159           2 :                 sTABProj.adProjParams[2], sTABProj.adProjParams[3]);
    1160           2 :             break;
    1161             : 
    1162           0 :         default:
    1163           0 :             poSpatialRef->SetProjection(CPLSPrintf(
    1164           0 :                 "Unhandled MapInfo projection method %d", sTABProj.nProjId));
    1165           0 :             break;
    1166             :     }
    1167             : 
    1168             :     /*-----------------------------------------------------------------
    1169             :      * Local (nonearth) coordinate systems have no Geographic relationship
    1170             :      * so we just return from here.
    1171             :      *----------------------------------------------------------------*/
    1172        1442 :     if (sTABProj.nProjId == 0)
    1173        1259 :         return poSpatialRef;
    1174             : 
    1175             :     /*-----------------------------------------------------------------
    1176             :      * Set the datum.  We are only given the X, Y and Z shift for
    1177             :      * the datum, so for now we just synthesize a name from this.
    1178             :      * It would be better if we could lookup a name based on the shift.
    1179             :      *
    1180             :      * Since we have already encountered files in which adDatumParams[] values
    1181             :      * were in the order of 1e-150 when they should have actually been zeros,
    1182             :      * we will use an epsilon in our scan instead of looking for equality.
    1183             :      *----------------------------------------------------------------*/
    1184         183 :     const MapInfoDatumInfo *psDatumInfo = nullptr;
    1185             : 
    1186        9549 :     for (int iDatumInfo = 0; asDatumInfoList[iDatumInfo].nMapInfoDatumID != -1;
    1187             :          iDatumInfo++)
    1188             :     {
    1189        9544 :         psDatumInfo = asDatumInfoList + iDatumInfo;
    1190             : 
    1191       10220 :         if (TAB_EQUAL(psDatumInfo->nEllipsoid, sTABProj.nEllipsoidId) &&
    1192         676 :             ((sTABProj.nDatumId > 0 &&
    1193         663 :               sTABProj.nDatumId == psDatumInfo->nMapInfoDatumID) ||
    1194         512 :              (sTABProj.nDatumId <= 0 &&
    1195          14 :               TAB_EQUAL(psDatumInfo->dfShiftX, sTABProj.dDatumShiftX) &&
    1196           2 :               TAB_EQUAL(psDatumInfo->dfShiftY, sTABProj.dDatumShiftY) &&
    1197           2 :               TAB_EQUAL(psDatumInfo->dfShiftZ, sTABProj.dDatumShiftZ) &&
    1198           2 :               TAB_EQUAL(psDatumInfo->dfDatumParm0, sTABProj.adDatumParams[0]) &&
    1199           2 :               TAB_EQUAL(psDatumInfo->dfDatumParm1, sTABProj.adDatumParams[1]) &&
    1200           2 :               TAB_EQUAL(psDatumInfo->dfDatumParm2, sTABProj.adDatumParams[2]) &&
    1201           2 :               TAB_EQUAL(psDatumInfo->dfDatumParm3, sTABProj.adDatumParams[3]) &&
    1202           1 :               TAB_EQUAL(psDatumInfo->dfDatumParm4, sTABProj.adDatumParams[4]))))
    1203         178 :             break;
    1204             : 
    1205        9366 :         psDatumInfo = nullptr;
    1206             :     }
    1207             : 
    1208         183 :     char szDatumName[200] = {};
    1209         183 :     if (psDatumInfo == nullptr)
    1210             :     {
    1211           5 :         if (sTABProj.adDatumParams[0] == 0.0 &&
    1212           2 :             sTABProj.adDatumParams[1] == 0.0 &&
    1213           2 :             sTABProj.adDatumParams[2] == 0.0 &&
    1214           2 :             sTABProj.adDatumParams[3] == 0.0 &&
    1215           2 :             sTABProj.adDatumParams[4] == 0.0)
    1216             :         {
    1217           2 :             snprintf(szDatumName, sizeof(szDatumName),
    1218           2 :                      "MIF 999,%u,%.15g,%.15g,%.15g", sTABProj.nEllipsoidId,
    1219           2 :                      sTABProj.dDatumShiftX, sTABProj.dDatumShiftY,
    1220           2 :                      sTABProj.dDatumShiftZ);
    1221             :         }
    1222             :         else
    1223             :         {
    1224           3 :             snprintf(
    1225             :                 szDatumName, sizeof(szDatumName),
    1226             :                 "MIF 9999,%u,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g",
    1227           3 :                 sTABProj.nEllipsoidId, sTABProj.dDatumShiftX,
    1228           3 :                 sTABProj.dDatumShiftY, sTABProj.dDatumShiftZ,
    1229           3 :                 sTABProj.adDatumParams[0], sTABProj.adDatumParams[1],
    1230           3 :                 sTABProj.adDatumParams[2], sTABProj.adDatumParams[3],
    1231           3 :                 sTABProj.adDatumParams[4]);
    1232             :         }
    1233             :     }
    1234         178 :     else if (strlen(psDatumInfo->pszOGCDatumName) > 0)
    1235             :     {
    1236         177 :         CPLStrlcpy(szDatumName, psDatumInfo->pszOGCDatumName,
    1237             :                    sizeof(szDatumName));
    1238             :     }
    1239             :     else
    1240             :     {
    1241           1 :         snprintf(szDatumName, sizeof(szDatumName), "MIF %d",
    1242           1 :                  psDatumInfo->nMapInfoDatumID);
    1243             :     }
    1244             : 
    1245             :     /*-----------------------------------------------------------------
    1246             :      * Set the spheroid.
    1247             :      *----------------------------------------------------------------*/
    1248         183 :     double dfSemiMajor = 0.0;
    1249         183 :     double dfInvFlattening = 0.0;
    1250         183 :     const char *pszSpheroidName = nullptr;
    1251             : 
    1252        6689 :     for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
    1253             :     {
    1254        6689 :         if (asSpheroidInfoList[i].nMapInfoId == sTABProj.nEllipsoidId)
    1255             :         {
    1256         183 :             dfSemiMajor = asSpheroidInfoList[i].dfA;
    1257         183 :             dfInvFlattening = asSpheroidInfoList[i].dfInvFlattening;
    1258         183 :             pszSpheroidName = asSpheroidInfoList[i].pszMapinfoName;
    1259         183 :             break;
    1260             :         }
    1261             :     }
    1262             : 
    1263             :     // use WGS 84 if nothing is known.
    1264         183 :     if (pszSpheroidName == nullptr)
    1265             :     {
    1266           0 :         pszSpheroidName = "unknown";
    1267           0 :         dfSemiMajor = 6378137.0;
    1268           0 :         dfInvFlattening = 298.257223563;
    1269             :     }
    1270             : 
    1271             :     /*-----------------------------------------------------------------
    1272             :      * Set the prime meridian.
    1273             :      *----------------------------------------------------------------*/
    1274         183 :     double dfPMOffset = 0.0;
    1275         183 :     const char *pszPMName = "Greenwich";
    1276             : 
    1277         183 :     if (/*sTABProj.nDatumId == 9999 ||*/ sTABProj.adDatumParams[4] != 0.0)
    1278             :     {
    1279           5 :         dfPMOffset = sTABProj.adDatumParams[4];
    1280             : 
    1281           5 :         if (fabs(dfPMOffset - 2.337229166667) < 1e-10)
    1282           3 :             pszPMName = "Paris";
    1283             :         else
    1284           2 :             pszPMName = "non-Greenwich";
    1285             :     }
    1286             : 
    1287             :     /*-----------------------------------------------------------------
    1288             :      * Create a GEOGCS definition.
    1289             :      *----------------------------------------------------------------*/
    1290             : 
    1291         183 :     poSpatialRef->SetGeogCS("unnamed", szDatumName, pszSpheroidName,
    1292             :                             dfSemiMajor, dfInvFlattening, pszPMName, dfPMOffset,
    1293             :                             SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV));
    1294             : 
    1295         183 :     if (psDatumInfo != nullptr)
    1296             :     {
    1297         178 :         if (CPLTestBool(
    1298             :                 CPLGetConfigOption("MITAB_SET_TOWGS84_ON_KNOWN_DATUM", "NO")))
    1299             :         {
    1300           0 :             poSpatialRef->SetTOWGS84(
    1301           0 :                 psDatumInfo->dfShiftX, psDatumInfo->dfShiftY,
    1302           0 :                 psDatumInfo->dfShiftZ,
    1303           0 :                 psDatumInfo->dfDatumParm0 == 0
    1304             :                     ? 0
    1305           0 :                     : -psDatumInfo->dfDatumParm0, /* avoids 0 to be transformed
    1306             :                                                      into -0 */
    1307           0 :                 psDatumInfo->dfDatumParm1 == 0 ? 0 : -psDatumInfo->dfDatumParm1,
    1308           0 :                 psDatumInfo->dfDatumParm2 == 0 ? 0 : -psDatumInfo->dfDatumParm2,
    1309           0 :                 psDatumInfo->dfDatumParm3);
    1310             :         }
    1311             :     }
    1312             :     else
    1313             :     {
    1314           6 :         poSpatialRef->SetTOWGS84(
    1315           5 :             sTABProj.dDatumShiftX, sTABProj.dDatumShiftY, sTABProj.dDatumShiftZ,
    1316           5 :             sTABProj.adDatumParams[0] == 0 ? 0 : -sTABProj.adDatumParams[0],
    1317           5 :             sTABProj.adDatumParams[1] == 0 ? 0 : -sTABProj.adDatumParams[1],
    1318           3 :             sTABProj.adDatumParams[2] == 0 ? 0 : -sTABProj.adDatumParams[2],
    1319           5 :             sTABProj.adDatumParams[3]);
    1320             :     }
    1321             : 
    1322             :     /*-----------------------------------------------------------------
    1323             :      * Special case for Google Mercator (datum=157, ellipse=54, gdal #4115)
    1324             :      *----------------------------------------------------------------*/
    1325         183 :     if (sTABProj.nProjId == 10 && sTABProj.nDatumId == 157 &&
    1326           2 :         sTABProj.nEllipsoidId == 54)
    1327             :     {
    1328           2 :         poSpatialRef->SetNode("PROJCS", "WGS 84 / Pseudo-Mercator");
    1329           2 :         poSpatialRef->SetExtension(
    1330             :             "PROJCS", "PROJ4",
    1331             :             "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 "
    1332             :             "+y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs");
    1333             :     }
    1334             : 
    1335             :     /*-----------------------------------------------------------------
    1336             :      * Special case for France Lambert-93
    1337             :      *----------------------------------------------------------------*/
    1338          55 :     if (sTABProj.nProjId == 3 && sTABProj.nDatumId == 33 &&
    1339          86 :         sTABProj.nEllipsoidId == 0 &&
    1340          43 :         TAB_EQUAL(poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0),
    1341         238 :                   3.0) &&
    1342          43 :         TAB_EQUAL(poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0),
    1343             :                   46.5))
    1344             :     {
    1345          43 :         poSpatialRef->SetNode("PROJCS", "RGF93 / Lambert-93");
    1346          43 :         poSpatialRef->SetNode("PROJCS|GEOGCS", "RGF93");
    1347          43 :         poSpatialRef->SetNode("PROJCS|GEOGCS|DATUM",
    1348             :                               "Reseau_Geodesique_Francais_1993");
    1349             :     }
    1350             : 
    1351         183 :     if (sTABProj.nProjId == 3)
    1352             :     {
    1353             :         // If the LCC_2SP can be turned into a LCC_1SP that has the same
    1354             :         // latitude of origin, then it is a better candidate
    1355          55 :         OGRSpatialReference *poLCC1SP = poSpatialRef->convertToOtherProjection(
    1356             :             SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP);
    1357          55 :         if (poLCC1SP)
    1358             :         {
    1359          55 :             if (TAB_EQUAL(
    1360             :                     poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,
    1361             :                                                   0.0),
    1362             :                     poLCC1SP->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)))
    1363             :             {
    1364           3 :                 delete poSpatialRef;
    1365           3 :                 poSpatialRef = poLCC1SP;
    1366             :             }
    1367             :             else
    1368             :             {
    1369          52 :                 delete poLCC1SP;
    1370             :             }
    1371             :         }
    1372             :     }
    1373             : 
    1374             :     /* For LCC, standard parallel 1 and 2 can be switched indifferently */
    1375             :     /* So the MapInfo order and the EPSG order are not generally identical */
    1376             :     /* which may cause recognition problems when reading in MapInfo */
    1377         183 :     int nEPSGCandidateCode = 0;
    1378         183 :     if (sTABProj.nProjId == 3)
    1379             :     {
    1380          55 :         double dfCenterLong = sTABProj.adProjParams[0];
    1381          55 :         double dfCenterLat = sTABProj.adProjParams[1];
    1382          55 :         double dfStdP1 = sTABProj.adProjParams[2];
    1383          55 :         double dfStdP2 = sTABProj.adProjParams[3];
    1384             : 
    1385        3116 :         for (size_t i = 0;
    1386        3116 :              i < sizeof(asMapInfoLCCSRSList) / sizeof(asMapInfoLCCSRSList[0]);
    1387             :              i++)
    1388             :         {
    1389         623 :             if (sTABProj.nDatumId == asMapInfoLCCSRSList[i].nMapInfoDatumID &&
    1390        3732 :                 TAB_EQUAL(dfCenterLong, asMapInfoLCCSRSList[i].dfCenterLong) &&
    1391         152 :                 TAB_EQUAL(dfCenterLat, asMapInfoLCCSRSList[i].dfCenterLat))
    1392             :             {
    1393         211 :                 if (TAB_EQUAL(dfStdP1, asMapInfoLCCSRSList[i].dfStdP1) &&
    1394          99 :                     (TAB_EQUAL(dfStdP2, asMapInfoLCCSRSList[i].dfStdP2) ||
    1395             :                      // EPSG:3301 "Estonian Coordinate System of 1997"
    1396             :                      // MapInfo uses a less accurate value of StdP2 than EPSG
    1397           4 :                      (TAB_EQUAL(asMapInfoLCCSRSList[i].dfStdP2, 59.33333333) &&
    1398           2 :                       TAB_EQUAL(dfStdP2, 59.3333333333333))))
    1399             :                 {
    1400          97 :                     if (nEPSGCandidateCode)
    1401             :                     {
    1402          47 :                         poSpatialRef->SetAuthority("PROJCS", "EPSG",
    1403             :                                                    nEPSGCandidateCode);
    1404          47 :                         nEPSGCandidateCode = 0;
    1405          47 :                         break;
    1406             :                     }
    1407          50 :                     if (asMapInfoLCCSRSList[i].bReverseStdP)
    1408             :                     {
    1409          49 :                         CPLDebug("MITAB",
    1410             :                                  "Switching standard parallel 1 and 2");
    1411          49 :                         poSpatialRef->SetLCC(
    1412          49 :                             sTABProj.adProjParams[3], sTABProj.adProjParams[2],
    1413          49 :                             sTABProj.adProjParams[1], sTABProj.adProjParams[0],
    1414          49 :                             sTABProj.adProjParams[4], sTABProj.adProjParams[5]);
    1415             :                     }
    1416          50 :                     if (asMapInfoLCCSRSList[i].nEPSGCode > 0)
    1417          49 :                         nEPSGCandidateCode = asMapInfoLCCSRSList[i].nEPSGCode;
    1418             :                     else
    1419           1 :                         break;
    1420             :                 }
    1421             :             }
    1422             :         }
    1423             :     }
    1424             : 
    1425             :     /*-----------------------------------------------------------------
    1426             :      * Apply linear units. Do that only after all above manipulations of
    1427             :      * projection parameters.
    1428             :      *----------------------------------------------------------------*/
    1429         351 :     if (sTABProj.nProjId != 0 && sTABProj.nProjId != 1 &&
    1430         168 :         CPLAtof(pszUnitsConv) != 1)
    1431             :     {
    1432           8 :         poSpatialRef->SetTargetLinearUnits(nullptr, pszUnitsName,
    1433             :                                            CPLAtof(pszUnitsConv));
    1434             :     }
    1435             : 
    1436         183 :     if (nEPSGCandidateCode)
    1437             :     {
    1438           4 :         OGRSpatialReference oTmp;
    1439           2 :         oTmp.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1440           2 :         if (oTmp.importFromEPSG(nEPSGCandidateCode) == OGRERR_NONE)
    1441             :         {
    1442           2 :             *poSpatialRef = std::move(oTmp);
    1443             :         }
    1444             :     }
    1445             : 
    1446             :     /*-----------------------------------------------------------------
    1447             :      * Special case for Philippine Reference System 1992, to override
    1448             :      * the MapInfo ellipsoid=8 "Clarke 1866 (modified for Michigan)"
    1449             :      * by the regular Clarke 1866 of EPSG
    1450             :      *----------------------------------------------------------------*/
    1451         183 :     if (sTABProj.nDatumId == 1031 && sTABProj.nEllipsoidId == 8)
    1452             :     {
    1453           4 :         OGRSpatialReference oSRS_EPSG_4683;
    1454           2 :         if (oSRS_EPSG_4683.importFromEPSG(4683) == OGRERR_NONE)
    1455           2 :             poSpatialRef->CopyGeogCSFrom(&oSRS_EPSG_4683);
    1456             :     }
    1457             : 
    1458             :     /*-----------------------------------------------------------------
    1459             :      * Special case for Kertau (RSO), to override
    1460             :      * the MapInfo ellipsoid=40 "Everest (India 1956)", 6377301.243, 300.80174
    1461             :      * with EPSG's "Everest 1830 (RSO 1969)",6377295.664,300.8017
    1462             :      *----------------------------------------------------------------*/
    1463         183 :     if (sTABProj.nDatumId == 164 && sTABProj.nEllipsoidId == 40)
    1464             :     {
    1465          10 :         OGRSpatialReference oSRS_EPSG_4751;
    1466           5 :         if (oSRS_EPSG_4751.importFromEPSG(4751) == OGRERR_NONE)
    1467           5 :             poSpatialRef->CopyGeogCSFrom(&oSRS_EPSG_4751);
    1468             :     }
    1469             : 
    1470         183 :     return poSpatialRef;
    1471             : }
    1472             : 
    1473           2 : static int MITABGetCustomDatum(const OGRSpatialReference *poSpatialRef,
    1474             :                                TABProjInfo &sTABProj)
    1475             : {
    1476           2 :     double adfTOWGS[7] = {0};
    1477           2 :     if (OGRERR_NONE != poSpatialRef->GetTOWGS84(
    1478             :                            adfTOWGS, sizeof(adfTOWGS) / sizeof(adfTOWGS[0])))
    1479             :     {
    1480           0 :         return FALSE;
    1481             :     }
    1482           2 :     sTABProj.nDatumId = 9999;
    1483           2 :     sTABProj.dDatumShiftX = adfTOWGS[0];
    1484           2 :     sTABProj.dDatumShiftY = adfTOWGS[1];
    1485           2 :     sTABProj.dDatumShiftZ = adfTOWGS[2];
    1486           2 :     sTABProj.adDatumParams[0] = -adfTOWGS[3];
    1487           2 :     sTABProj.adDatumParams[1] = -adfTOWGS[4];
    1488           2 :     sTABProj.adDatumParams[2] = -adfTOWGS[5];
    1489           2 :     sTABProj.adDatumParams[3] = adfTOWGS[6];
    1490             : 
    1491           2 :     int nSpheroidId = -1;
    1492             : 
    1493           2 :     const char *pszWKTSpheroid = poSpatialRef->GetAttrValue("SPHEROID");
    1494         104 :     for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
    1495             :     {
    1496         103 :         if (EQUAL(pszWKTSpheroid, asSpheroidInfoList[i].pszMapinfoName))
    1497             :         {
    1498           1 :             nSpheroidId = asSpheroidInfoList[i].nMapInfoId;
    1499           1 :             break;
    1500             :         }
    1501             :     }
    1502             : 
    1503           2 :     if (nSpheroidId == -1)
    1504             :     {
    1505           1 :         double adSemiMajor = poSpatialRef->GetSemiMajor();
    1506           1 :         double adInvFlattening = poSpatialRef->GetInvFlattening();
    1507             : 
    1508          39 :         for (int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++)
    1509             :         {
    1510          39 :             if (CPLIsEqual(adSemiMajor, asSpheroidInfoList[i].dfA) &&
    1511           1 :                 CPLIsEqual(adInvFlattening,
    1512             :                            asSpheroidInfoList[i].dfInvFlattening))
    1513             :             {
    1514           1 :                 nSpheroidId = asSpheroidInfoList[i].nMapInfoId;
    1515           1 :                 break;
    1516             :             }
    1517             :         }
    1518             :     }
    1519           2 :     if (nSpheroidId == -1)
    1520             :     {
    1521           0 :         CPLDebug(
    1522             :             "MITAB",
    1523             :             "Cannot find MapInfo spheroid matching %s. Defaulting to WGS 84",
    1524             :             pszWKTSpheroid);
    1525           0 :         nSpheroidId = 28; /* WGS 84 */
    1526             :     }
    1527           2 :     sTABProj.nEllipsoidId = static_cast<GByte>(nSpheroidId);
    1528           2 :     return TRUE;
    1529             : }
    1530             : 
    1531         110 : int TABFileGetTABProjFromSpatialRef(const OGRSpatialReference *poSpatialRef,
    1532             :                                     TABProjInfo &sTABProj, int &nParamCount)
    1533             : {
    1534             :     /*-----------------------------------------------------------------
    1535             :      * Initialize TABProjInfo
    1536             :      *----------------------------------------------------------------*/
    1537         110 :     sTABProj.nProjId = 0;
    1538         110 :     sTABProj.nEllipsoidId = 0; /* how will we set this? */
    1539         110 :     sTABProj.nUnitsId = 7;
    1540         110 :     sTABProj.adProjParams[0] = sTABProj.adProjParams[1] = 0.0;
    1541         110 :     sTABProj.adProjParams[2] = sTABProj.adProjParams[3] = 0.0;
    1542         110 :     sTABProj.adProjParams[4] = sTABProj.adProjParams[5] = 0.0;
    1543             : 
    1544         110 :     sTABProj.nDatumId = 0;
    1545         110 :     sTABProj.dDatumShiftX = 0.0;
    1546         110 :     sTABProj.dDatumShiftY = 0.0;
    1547         110 :     sTABProj.dDatumShiftZ = 0.0;
    1548         110 :     sTABProj.adDatumParams[0] = 0.0;
    1549         110 :     sTABProj.adDatumParams[1] = 0.0;
    1550         110 :     sTABProj.adDatumParams[2] = 0.0;
    1551         110 :     sTABProj.adDatumParams[3] = 0.0;
    1552         110 :     sTABProj.adDatumParams[4] = 0.0;
    1553             : 
    1554         110 :     sTABProj.nAffineFlag = 0;
    1555         110 :     sTABProj.nAffineUnits = 7;
    1556         110 :     sTABProj.dAffineParamA = 0.0;
    1557         110 :     sTABProj.dAffineParamB = 0.0;
    1558         110 :     sTABProj.dAffineParamC = 0.0;
    1559         110 :     sTABProj.dAffineParamD = 0.0;
    1560         110 :     sTABProj.dAffineParamE = 0.0;
    1561         110 :     sTABProj.dAffineParamF = 0.0;
    1562             : 
    1563             :     /*-----------------------------------------------------------------
    1564             :      * Get the linear units and conversion.
    1565             :      *----------------------------------------------------------------*/
    1566         110 :     const char *pszLinearUnits = nullptr;
    1567         110 :     double dfLinearConv = poSpatialRef->GetLinearUnits(&pszLinearUnits);
    1568         110 :     if (dfLinearConv == 0.0)
    1569           0 :         dfLinearConv = 1.0;
    1570             : 
    1571             :     // Get datum information
    1572         110 :     const char *pszWKTDatum = poSpatialRef->GetAttrValue("DATUM");
    1573             : 
    1574         110 :     const auto GetDatumCode = [](const OGRSpatialReference *poSRS)
    1575             :     {
    1576         110 :         const char *pszDatumAuthority = poSRS->GetAuthorityName("DATUM");
    1577         110 :         const char *pszDatumCode = poSRS->GetAuthorityCode("DATUM");
    1578         110 :         if (pszDatumCode && pszDatumAuthority &&
    1579          54 :             EQUAL(pszDatumAuthority, "EPSG"))
    1580             :         {
    1581          54 :             return atoi(pszDatumCode);
    1582             :         }
    1583          56 :         return -1;
    1584             :     };
    1585             : 
    1586         110 :     int nDatumEPSGCode = GetDatumCode(poSpatialRef);
    1587         110 :     if (nDatumEPSGCode < 0)
    1588             :     {
    1589             :         const auto GetDatumCodeFromCRSIndirect =
    1590         104 :             [&GetDatumCode](const OGRSpatialReference *poSRS,
    1591           0 :                             const char *pszNode)
    1592             :         {
    1593         104 :             const char *pszAuthorityName = poSRS->GetAuthorityName(pszNode);
    1594         104 :             const char *pszAuthorityCode = poSRS->GetAuthorityCode(pszNode);
    1595         104 :             if (pszAuthorityName && pszAuthorityCode)
    1596             :             {
    1597           0 :                 OGRSpatialReference oSRSTmp;
    1598           0 :                 if (oSRSTmp.SetFromUserInput(CPLSPrintf(
    1599           0 :                         "%s:%s", pszAuthorityName, pszAuthorityCode)) ==
    1600             :                     OGRERR_NONE)
    1601             :                 {
    1602           0 :                     return GetDatumCode(&oSRSTmp);
    1603             :                 }
    1604             :             }
    1605         104 :             return -1;
    1606          56 :         };
    1607             : 
    1608             :         // When the CRS is built from WKT2 CRS string, the DATUM code will
    1609             :         // typically be absent from the CRS string.
    1610             :         // Try to get the AUTHORITY:CODE from the CRS to instantiate
    1611             :         // a temporary CRS and get its DATUM code.
    1612          56 :         nDatumEPSGCode = GetDatumCodeFromCRSIndirect(poSpatialRef, nullptr);
    1613          56 :         if (nDatumEPSGCode < 0 && !poSpatialRef->IsGeographic())
    1614             :         {
    1615             :             // If there's no AUTHORITY:CODE on the CRS, then retry with its
    1616             :             // geographic CRS
    1617             :             nDatumEPSGCode =
    1618          48 :                 GetDatumCodeFromCRSIndirect(poSpatialRef, "GEOGCS");
    1619             :         }
    1620             :     }
    1621             : 
    1622             :     /*-----------------------------------------------------------------
    1623             :      * Transform the projection and projection parameters.
    1624             :      *----------------------------------------------------------------*/
    1625         110 :     const char *pszProjection = poSpatialRef->GetAttrValue("PROJECTION");
    1626         110 :     double *params = sTABProj.adProjParams;
    1627         110 :     nParamCount = 0;
    1628             : 
    1629         138 :     if (pszProjection == nullptr &&
    1630          28 :         poSpatialRef->GetAttrNode("GEOGCS") == nullptr)
    1631             :     {
    1632             :         /* nonearth */
    1633          17 :         sTABProj.nProjId = 0;
    1634             :     }
    1635             : 
    1636          93 :     else if (pszProjection == nullptr)
    1637             :     {
    1638          11 :         sTABProj.nProjId = 1;
    1639             :     }
    1640             : 
    1641          82 :     else if (EQUAL(pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA))
    1642             :     {
    1643           1 :         sTABProj.nProjId = 9;
    1644           1 :         params[0] =
    1645           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1646           2 :         params[1] =
    1647           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1648           2 :         params[2] =
    1649           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1650           2 :         params[3] =
    1651           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
    1652           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1653           1 :         params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1654           1 :         nParamCount = 6;
    1655             :     }
    1656             : 
    1657          81 :     else if (EQUAL(pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT))
    1658             :     {
    1659           2 :         sTABProj.nProjId = 5;
    1660           2 :         params[0] =
    1661           2 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1662           4 :         params[1] =
    1663           2 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1664           2 :         params[2] = 90.0;
    1665           2 :         nParamCount = 3;
    1666             : 
    1667           2 :         if (std::abs((std::abs(params[1]) - 90)) > 0.001)
    1668           1 :             sTABProj.nProjId = 28;
    1669             :     }
    1670             : 
    1671          79 :     else if (EQUAL(pszProjection, SRS_PT_CYLINDRICAL_EQUAL_AREA))
    1672             :     {
    1673           1 :         sTABProj.nProjId = 2;
    1674           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1675           2 :         params[1] =
    1676           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1677           1 :         nParamCount = 2;
    1678             :     }
    1679             : 
    1680          78 :     else if (EQUAL(pszProjection, SRS_PT_ECKERT_IV))
    1681             :     {
    1682           1 :         sTABProj.nProjId = 14;
    1683           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1684           1 :         nParamCount = 1;
    1685             :     }
    1686             : 
    1687          77 :     else if (EQUAL(pszProjection, SRS_PT_ECKERT_VI))
    1688             :     {
    1689           1 :         sTABProj.nProjId = 15;
    1690           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1691           1 :         nParamCount = 1;
    1692             :     }
    1693             : 
    1694          76 :     else if (EQUAL(pszProjection, SRS_PT_EQUIDISTANT_CONIC))
    1695             :     {
    1696           1 :         sTABProj.nProjId = 6;
    1697           1 :         params[0] =
    1698           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1699           2 :         params[1] =
    1700           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1701           2 :         params[2] =
    1702           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1703           2 :         params[3] =
    1704           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
    1705           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1706           1 :         params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1707           1 :         nParamCount = 6;
    1708             :     }
    1709             : 
    1710          75 :     else if (EQUAL(pszProjection, SRS_PT_GALL_STEREOGRAPHIC))
    1711             :     {
    1712           1 :         sTABProj.nProjId = 17;
    1713           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1714           1 :         nParamCount = 1;
    1715             :     }
    1716             : 
    1717          74 :     else if (EQUAL(pszProjection, SRS_PT_HOTINE_OBLIQUE_MERCATOR))
    1718             :     {
    1719           3 :         if (std::abs(poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,
    1720             :                                                    90.0) -
    1721           3 :                      90.0) < 1e-8)
    1722             :         {
    1723           1 :             sTABProj.nProjId = 7;
    1724           1 :             params[0] =
    1725           1 :                 poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1726           2 :             params[1] =
    1727           1 :                 poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1728           1 :             params[2] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
    1729           1 :             params[3] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1730           1 :             params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1731           1 :             params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1732           1 :             nParamCount = 6;
    1733             :         }
    1734             :         else
    1735             :         {
    1736           2 :             sTABProj.nProjId = 35;
    1737           2 :             params[0] =
    1738           2 :                 poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1739           4 :             params[1] =
    1740           2 :                 poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1741           2 :             params[2] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
    1742           4 :             params[3] =
    1743           2 :                 poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE, 0.0);
    1744           2 :             params[4] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1745           2 :             params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1746           2 :             params[6] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1747           2 :             nParamCount = 7;
    1748             :         }
    1749             :     }
    1750             : 
    1751          71 :     else if (EQUAL(pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA))
    1752             :     {
    1753           1 :         sTABProj.nProjId = 4;
    1754           1 :         params[0] =
    1755           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1756           2 :         params[1] =
    1757           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1758           1 :         params[2] = 90.0;
    1759           1 :         nParamCount = 3;
    1760             : 
    1761           1 :         if (std::abs((std::abs(params[1]) - 90)) > 0.001)
    1762           0 :             sTABProj.nProjId = 29;
    1763             :     }
    1764             : 
    1765          70 :     else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
    1766             :     {
    1767          28 :         sTABProj.nProjId = 3;
    1768          28 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1769          56 :         params[1] =
    1770          28 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1771          56 :         params[2] =
    1772          28 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1773          56 :         params[3] =
    1774          28 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
    1775          28 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1776          28 :         params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1777          28 :         nParamCount = 6;
    1778             :     }
    1779             : 
    1780          42 :     else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP))
    1781             :     {
    1782             :         OGRSpatialReference *poOtherSRS =
    1783           1 :             poSpatialRef->convertToOtherProjection(
    1784             :                 SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP);
    1785           1 :         if (poOtherSRS)
    1786             :         {
    1787           1 :             sTABProj.nProjId = 3;
    1788           1 :             params[0] =
    1789           1 :                 poOtherSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1790           2 :             params[1] =
    1791           1 :                 poOtherSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1792           2 :             params[2] =
    1793           1 :                 poOtherSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1794           2 :             params[3] =
    1795           1 :                 poOtherSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
    1796           1 :             params[4] = poOtherSRS->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1797           1 :             params[5] = poOtherSRS->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1798           1 :             nParamCount = 6;
    1799           1 :             delete poOtherSRS;
    1800             :         }
    1801             :     }
    1802             : 
    1803          41 :     else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM))
    1804             :     {
    1805           1 :         sTABProj.nProjId = 19;
    1806           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1807           2 :         params[1] =
    1808           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1809           2 :         params[2] =
    1810           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1811           2 :         params[3] =
    1812           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0);
    1813           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1814           1 :         params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1815           1 :         nParamCount = 6;
    1816             :     }
    1817             : 
    1818          40 :     else if (EQUAL(pszProjection, SRS_PT_MERCATOR_1SP))
    1819             :     {
    1820           3 :         sTABProj.nProjId = 10;
    1821           3 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1822           6 :         params[1] =
    1823           3 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1824           3 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1825           3 :         nParamCount = 1;  // FIXME for MIF export ?
    1826             : 
    1827           3 :         if (params[1] != 0.0)
    1828             :         {
    1829           0 :             sTABProj.nProjId = 26;
    1830           0 :             nParamCount = 2;  // FIXME for MIF export ?
    1831             :         }
    1832             :     }
    1833             : 
    1834          37 :     else if (EQUAL(pszProjection, SRS_PT_MERCATOR_2SP))
    1835             :     {
    1836           1 :         sTABProj.nProjId = 26;
    1837           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1838           2 :         params[1] =
    1839           1 :             poSpatialRef->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0);
    1840           1 :         nParamCount = 2;  // FIXME for MIF export ?
    1841             :     }
    1842             : 
    1843          36 :     else if (EQUAL(pszProjection, SRS_PT_MILLER_CYLINDRICAL))
    1844             :     {
    1845           1 :         sTABProj.nProjId = 11;
    1846           1 :         params[0] =
    1847           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1848           1 :         nParamCount = 1;
    1849             :     }
    1850             : 
    1851          35 :     else if (EQUAL(pszProjection, SRS_PT_MOLLWEIDE))
    1852             :     {
    1853           1 :         sTABProj.nProjId = 13;
    1854           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1855           1 :         nParamCount = 1;
    1856             :     }
    1857             : 
    1858          34 :     else if (EQUAL(pszProjection, SRS_PT_NEW_ZEALAND_MAP_GRID))
    1859             :     {
    1860           1 :         sTABProj.nProjId = 18;
    1861           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1862           2 :         params[1] =
    1863           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1864           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1865           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1866           1 :         nParamCount = 4;
    1867             :     }
    1868             : 
    1869          33 :     else if (EQUAL(pszProjection, SRS_PT_SWISS_OBLIQUE_CYLINDRICAL))
    1870             :     {
    1871           0 :         sTABProj.nProjId = 25;
    1872           0 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1873           0 :         params[1] =
    1874           0 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1875           0 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1876           0 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1877           0 :         nParamCount = 4;
    1878             :     }
    1879             : 
    1880             :     // Swiss Oblique expressed as Hotine Oblique Mercator Azimuth Center
    1881          66 :     else if (EQUAL(pszProjection,
    1882           1 :                    SRS_PT_HOTINE_OBLIQUE_MERCATOR_AZIMUTH_CENTER) &&
    1883           1 :              std::abs(poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 90.0) -
    1884           1 :                       90.0) < 1e-8 &&
    1885           1 :              std::abs(poSpatialRef->GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,
    1886             :                                                     90.0) -
    1887          34 :                       90.0) < 1e-8 &&
    1888           1 :              std::abs(poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0) -
    1889             :                       1.0) < 1e-8)
    1890             :     {
    1891           1 :         sTABProj.nProjId = 25;
    1892           1 :         params[0] =
    1893           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER, 0.0);
    1894           2 :         params[1] =
    1895           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER, 0.0);
    1896           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1897           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1898           1 :         nParamCount = 4;
    1899             :     }
    1900             : 
    1901          32 :     else if (EQUAL(pszProjection, SRS_PT_ROBINSON))
    1902             :     {
    1903           1 :         sTABProj.nProjId = 12;
    1904           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1905           1 :         nParamCount = 1;
    1906             :     }
    1907             : 
    1908          31 :     else if (EQUAL(pszProjection, SRS_PT_SINUSOIDAL))
    1909             :     {
    1910           1 :         sTABProj.nProjId = 16;
    1911           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1912           1 :         nParamCount = 1;
    1913             :     }
    1914             : 
    1915          30 :     else if (EQUAL(pszProjection, SRS_PT_STEREOGRAPHIC))
    1916             :     {
    1917           1 :         sTABProj.nProjId = 20;
    1918           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1919           2 :         params[1] =
    1920           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1921           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1922           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1923           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1924           1 :         nParamCount = 5;
    1925             :     }
    1926             : 
    1927          29 :     else if (EQUAL(pszProjection, SRS_PT_OBLIQUE_STEREOGRAPHIC))
    1928             :     {
    1929           1 :         sTABProj.nProjId = 31;
    1930           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1931           2 :         params[1] =
    1932           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1933           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1934           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1935           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1936           1 :         nParamCount = 5;
    1937             :     }
    1938             : 
    1939          28 :     else if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR))
    1940             :     {
    1941          24 :         sTABProj.nProjId = 8;
    1942          24 :         if ((pszWKTDatum &&
    1943          24 :              EQUAL(pszWKTDatum, "Kartastokoordinaattijarjestelma_1966")) ||
    1944             :             nDatumEPSGCode == 6123)
    1945             :         {
    1946             :             // Special case for Finnish KKJ
    1947           2 :             sTABProj.nProjId = 24;
    1948             :         }
    1949          24 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1950          48 :         params[1] =
    1951          24 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1952          24 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1953          24 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1954          24 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1955          24 :         nParamCount = 5;
    1956             :     }
    1957             : 
    1958           4 :     else if (EQUAL(pszProjection,
    1959             :                    SRS_PT_TRANSVERSE_MERCATOR_MI_21))  // Encom 2003
    1960             :     {
    1961           0 :         sTABProj.nProjId = 21;
    1962           0 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1963           0 :         params[1] =
    1964           0 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1965           0 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1966           0 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1967           0 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1968           0 :         nParamCount = 5;
    1969             :     }
    1970             : 
    1971           4 :     else if (EQUAL(pszProjection,
    1972             :                    SRS_PT_TRANSVERSE_MERCATOR_MI_22))  // Encom 2003
    1973             :     {
    1974           0 :         sTABProj.nProjId = 22;
    1975           0 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1976           0 :         params[1] =
    1977           0 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1978           0 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1979           0 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1980           0 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1981           0 :         nParamCount = 5;
    1982             :     }
    1983             : 
    1984           4 :     else if (EQUAL(pszProjection,
    1985             :                    SRS_PT_TRANSVERSE_MERCATOR_MI_23))  // Encom 2003
    1986             :     {
    1987           0 :         sTABProj.nProjId = 23;
    1988           0 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    1989           0 :         params[1] =
    1990           0 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    1991           0 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    1992           0 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    1993           0 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    1994           0 :         nParamCount = 5;
    1995             :     }
    1996             : 
    1997           4 :     else if (EQUAL(pszProjection,
    1998             :                    SRS_PT_TRANSVERSE_MERCATOR_MI_24))  // Encom 2003
    1999             :     {
    2000           0 :         sTABProj.nProjId = 24;
    2001           0 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    2002           0 :         params[1] =
    2003           0 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    2004           0 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR, 1.0);
    2005           0 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    2006           0 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    2007           0 :         nParamCount = 5;
    2008             :     }
    2009             : 
    2010           4 :     else if (EQUAL(pszProjection, SRS_PT_CASSINI_SOLDNER))
    2011             :     {
    2012           1 :         sTABProj.nProjId = 30;
    2013           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    2014           2 :         params[1] =
    2015           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    2016           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    2017           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    2018           1 :         nParamCount = 4;
    2019             :     }
    2020             : 
    2021           3 :     else if (EQUAL(pszProjection, SRS_PT_POLYCONIC))
    2022             :     {
    2023           1 :         sTABProj.nProjId = 27;
    2024           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    2025           2 :         params[1] =
    2026           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    2027           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    2028           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    2029           1 :         nParamCount = 4;
    2030             :     }
    2031             : 
    2032           2 :     else if (EQUAL(pszProjection, SRS_PT_KROVAK))
    2033             :     {
    2034           1 :         sTABProj.nProjId = 32;
    2035           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    2036           2 :         params[1] =
    2037           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    2038           2 :         params[2] =
    2039           1 :             poSpatialRef->GetNormProjParm(SRS_PP_PSEUDO_STD_PARALLEL_1, 0.0);
    2040           1 :         params[3] = poSpatialRef->GetNormProjParm(SRS_PP_AZIMUTH, 0.0);
    2041           1 :         params[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    2042           1 :         params[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    2043           1 :         nParamCount = 6;
    2044             :     }
    2045             : 
    2046           1 :     else if (EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR))
    2047             :     {
    2048           1 :         sTABProj.nProjId = 33;
    2049           1 :         params[0] = poSpatialRef->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0);
    2050           2 :         params[1] =
    2051           1 :             poSpatialRef->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
    2052           1 :         params[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING, 0.0);
    2053           1 :         params[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING, 0.0);
    2054           1 :         nParamCount = 4;
    2055             :     }
    2056             : 
    2057             :     else
    2058             :     {
    2059           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    2060             :                  "No translation from %s to MapInfo known", pszProjection);
    2061             :     }
    2062             : 
    2063             :     /* ==============================================================
    2064             :      * Translate Datum and Ellipsoid
    2065             :      * ============================================================== */
    2066         110 :     const MapInfoDatumInfo *psDatumInfo = nullptr;
    2067             : 
    2068             :     /*-----------------------------------------------------------------
    2069             :      * Default to WGS84 if we have no datum at all.
    2070             :      *----------------------------------------------------------------*/
    2071         110 :     if (pszWKTDatum == nullptr)
    2072             :     {
    2073          17 :         CPLDebug("MITAB",
    2074             :                  "Cannot find MapInfo datum matching %d. Defaulting to WGS 84",
    2075             :                  nDatumEPSGCode);
    2076          17 :         psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
    2077             :         // From MIF export code. FIXME?
    2078             :         // if( nProjection == 1 )
    2079             :         //    nProjection = 0;
    2080             :     }
    2081             : 
    2082             :     /*-----------------------------------------------------------------
    2083             :      * We know the MIF datum number, and need to look it up to
    2084             :      * translate into datum parameters.
    2085             :      *----------------------------------------------------------------*/
    2086          93 :     else if (STARTS_WITH_CI(pszWKTDatum, "MIF ") &&
    2087           2 :              atoi(pszWKTDatum + 4) != 999 && atoi(pszWKTDatum + 4) != 9999)
    2088             :     {
    2089           0 :         int nDatum = atoi(pszWKTDatum + 4);
    2090           0 :         for (int i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++)
    2091             :         {
    2092           0 :             if (nDatum == asDatumInfoList[i].nMapInfoDatumID)
    2093             :             {
    2094           0 :                 psDatumInfo = asDatumInfoList + i;
    2095           0 :                 break;
    2096             :             }
    2097             :         }
    2098             : 
    2099           0 :         if (psDatumInfo == nullptr)
    2100             :         {
    2101           0 :             CPLDebug(
    2102             :                 "MITAB",
    2103             :                 "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
    2104             :                 pszWKTDatum);
    2105           0 :             psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
    2106           0 :         }
    2107             :     }
    2108             : 
    2109             :     /*-----------------------------------------------------------------
    2110             :      * We have the MIF datum parameters, and apply those directly.
    2111             :      *----------------------------------------------------------------*/
    2112          93 :     else if (STARTS_WITH_CI(pszWKTDatum, "MIF ") &&
    2113           2 :              (atoi(pszWKTDatum + 4) == 999 || atoi(pszWKTDatum + 4) == 9999))
    2114             :     {
    2115           2 :         sTABProj.nDatumId = static_cast<GInt16>(atoi(pszWKTDatum + 4));
    2116             :         char **papszFields =
    2117           2 :             CSLTokenizeStringComplex(pszWKTDatum + 4, ",", FALSE, TRUE);
    2118             : 
    2119           2 :         if (CSLCount(papszFields) >= 5)
    2120             :         {
    2121           2 :             sTABProj.nEllipsoidId = static_cast<GByte>(atoi(papszFields[1]));
    2122           2 :             sTABProj.dDatumShiftX = CPLAtof(papszFields[2]);
    2123           2 :             sTABProj.dDatumShiftY = CPLAtof(papszFields[3]);
    2124           2 :             sTABProj.dDatumShiftZ = CPLAtof(papszFields[4]);
    2125             :         }
    2126             : 
    2127           2 :         if (CSLCount(papszFields) >= 10)
    2128             :         {
    2129           1 :             sTABProj.adDatumParams[0] = CPLAtof(papszFields[5]);
    2130           1 :             sTABProj.adDatumParams[1] = CPLAtof(papszFields[6]);
    2131           1 :             sTABProj.adDatumParams[2] = CPLAtof(papszFields[7]);
    2132           1 :             sTABProj.adDatumParams[3] = CPLAtof(papszFields[8]);
    2133           1 :             sTABProj.adDatumParams[4] = CPLAtof(papszFields[9]);
    2134             :         }
    2135             : 
    2136           2 :         if (CSLCount(papszFields) < 5)
    2137             :         {
    2138           0 :             CPLDebug(
    2139             :                 "MITAB",
    2140             :                 "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
    2141             :                 pszWKTDatum);
    2142           0 :             psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
    2143             :         }
    2144             : 
    2145           2 :         CSLDestroy(papszFields);
    2146             :     }
    2147             : 
    2148             :     /*-----------------------------------------------------------------
    2149             :      * We have a "real" datum name, and possibly an EPSG code for the
    2150             :      * datum.  Try to look it up (using EPSG code first) and get the
    2151             :      * parameters.  If we don't find it with either just use WGS84.
    2152             :      *----------------------------------------------------------------*/
    2153             :     else
    2154             :     {
    2155        3938 :         for (int i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++)
    2156             :         {
    2157        3936 :             if ((nDatumEPSGCode > 0 &&
    2158        3199 :                  asDatumInfoList[i].nDatumEPSGCode == nDatumEPSGCode) ||
    2159        3888 :                 EQUAL(pszWKTDatum, asDatumInfoList[i].pszOGCDatumName))
    2160             :             {
    2161          89 :                 psDatumInfo = asDatumInfoList + i;
    2162          89 :                 break;
    2163             :             }
    2164             :         }
    2165             : 
    2166          93 :         if (psDatumInfo == nullptr &&
    2167           2 :             !MITABGetCustomDatum(poSpatialRef, sTABProj))
    2168             :         {
    2169           0 :             CPLDebug("MITAB",
    2170             :                      "Cannot find MapInfo datum matching %s,%d. Defaulting to "
    2171             :                      "WGS 84",
    2172             :                      pszWKTDatum, nDatumEPSGCode);
    2173           0 :             psDatumInfo = asDatumInfoList + 0; /* WGS 84 */
    2174             :         }
    2175             :     }
    2176             : 
    2177         110 :     if (psDatumInfo != nullptr)
    2178             :     {
    2179         106 :         sTABProj.nEllipsoidId = static_cast<GByte>(psDatumInfo->nEllipsoid);
    2180         106 :         sTABProj.nDatumId = static_cast<GInt16>(psDatumInfo->nMapInfoDatumID);
    2181         106 :         sTABProj.dDatumShiftX = psDatumInfo->dfShiftX;
    2182         106 :         sTABProj.dDatumShiftY = psDatumInfo->dfShiftY;
    2183         106 :         sTABProj.dDatumShiftZ = psDatumInfo->dfShiftZ;
    2184         106 :         sTABProj.adDatumParams[0] = psDatumInfo->dfDatumParm0;
    2185         106 :         sTABProj.adDatumParams[1] = psDatumInfo->dfDatumParm1;
    2186         106 :         sTABProj.adDatumParams[2] = psDatumInfo->dfDatumParm2;
    2187         106 :         sTABProj.adDatumParams[3] = psDatumInfo->dfDatumParm3;
    2188         106 :         sTABProj.adDatumParams[4] = psDatumInfo->dfDatumParm4;
    2189             : 
    2190             :         /* For LCC, standard parallel 1 and 2 can be switched indifferently */
    2191             :         /* So the MapInfo order and the EPSG order are not generally identical
    2192             :          */
    2193             :         /* which may cause recognition problems when reading in MapInfo */
    2194         106 :         if (sTABProj.nProjId == 3)
    2195             :         {
    2196          29 :             const double dfCenterLong = params[0];
    2197          29 :             const double dfCenterLat = params[1];
    2198          29 :             const double dfStdP1 = params[2];
    2199          29 :             const double dfStdP2 = params[3];
    2200             : 
    2201             :             // EPSG:3301 "Estonian Coordinate System of 1997"
    2202          29 :             if (std::fabs(dfCenterLong - 24) <= 1e-10 &&
    2203           1 :                 std::fabs(dfCenterLat - 57.51755393056) <= 1e-10 &&
    2204             :                 // MapInfo uses a less accurate value of StdP2 than EPSG
    2205           1 :                 std::fabs(dfStdP1 - 59.33333333) <= 1e-8 &&
    2206           1 :                 std::fabs(dfStdP2 - 58) <= 1e-8)
    2207             :             {
    2208           1 :                 CPLDebug("MITAB", "Switching standard parallel 1 and 2");
    2209           1 :                 std::swap(params[2], params[3]);
    2210             :             }
    2211             :             else
    2212             :             {
    2213        1005 :                 for (size_t i = 0; i < sizeof(asMapInfoLCCSRSList) /
    2214             :                                            sizeof(asMapInfoLCCSRSList[0]);
    2215             :                      i++)
    2216             :                 {
    2217        2004 :                     if (sTABProj.nDatumId ==
    2218         192 :                             asMapInfoLCCSRSList[i].nMapInfoDatumID &&
    2219         192 :                         TAB_EQUAL(dfCenterLong,
    2220        1194 :                                   asMapInfoLCCSRSList[i].dfCenterLong) &&
    2221          43 :                         TAB_EQUAL(dfCenterLat,
    2222          43 :                                   asMapInfoLCCSRSList[i].dfCenterLat))
    2223             :                     {
    2224          62 :                         if (TAB_EQUAL(dfStdP1,
    2225          31 :                                       asMapInfoLCCSRSList[i].dfStdP1) &&
    2226           0 :                             TAB_EQUAL(dfStdP2, asMapInfoLCCSRSList[i].dfStdP2))
    2227             :                         {
    2228           0 :                             break;
    2229             :                         }
    2230          62 :                         else if (TAB_EQUAL(dfStdP1,
    2231          56 :                                            asMapInfoLCCSRSList[i].dfStdP2) &&
    2232          25 :                                  TAB_EQUAL(dfStdP2,
    2233          25 :                                            asMapInfoLCCSRSList[i].dfStdP1))
    2234             :                         {
    2235          25 :                             CPLDebug("MITAB",
    2236             :                                      "Switching standard parallel 1 and 2");
    2237          25 :                             std::swap(params[2], params[3]);
    2238          25 :                             break;
    2239             :                         }
    2240             :                     }
    2241             :                 }
    2242             :             }
    2243             :         }
    2244             :     }
    2245             : 
    2246             :     // Google Merc
    2247         110 :     const char *pszAuthorityName = nullptr;
    2248         110 :     const char *pszAuthorityCode = nullptr;
    2249         110 :     const char *pszExtension = nullptr;
    2250         110 :     if (((pszAuthorityName = poSpatialRef->GetAuthorityName(nullptr)) !=
    2251          50 :              nullptr &&
    2252          50 :          EQUAL(pszAuthorityName, "EPSG") &&
    2253          50 :          (pszAuthorityCode = poSpatialRef->GetAuthorityCode(nullptr)) !=
    2254          50 :              nullptr &&
    2255         269 :          atoi(pszAuthorityCode) == 3857) ||
    2256         109 :         ((pszExtension = poSpatialRef->GetExtension(nullptr, "PROJ4")) !=
    2257           1 :              nullptr &&
    2258           1 :          (EQUAL(pszExtension, "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 "
    2259             :                               "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m "
    2260           1 :                               "+nadgrids=@null +wktext  +no_defs") ||
    2261           1 :           EQUAL(pszExtension,
    2262             :                 "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 "
    2263             :                 "+y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs"))))
    2264             :     {
    2265           2 :         sTABProj.nDatumId = 157;
    2266           2 :         sTABProj.nEllipsoidId = 54;
    2267             :     }
    2268             : 
    2269             :     /*-----------------------------------------------------------------
    2270             :      * Translate the units
    2271             :      *----------------------------------------------------------------*/
    2272         110 :     if (sTABProj.nProjId == 1 || pszLinearUnits == nullptr)
    2273          11 :         sTABProj.nUnitsId = 13;
    2274          99 :     else if (dfLinearConv == 1000.0)
    2275           1 :         sTABProj.nUnitsId = 1;
    2276          98 :     else if (dfLinearConv == 0.0254 || EQUAL(pszLinearUnits, "Inch") ||
    2277          97 :              EQUAL(pszLinearUnits, "IINCH"))
    2278           1 :         sTABProj.nUnitsId = 2;
    2279          97 :     else if (fabs(dfLinearConv - CPLAtof(SRS_UL_FOOT_CONV)) <
    2280         192 :                  1e-15 * dfLinearConv ||
    2281          95 :              EQUAL(pszLinearUnits, SRS_UL_FOOT))
    2282           2 :         sTABProj.nUnitsId = 3;
    2283          95 :     else if (EQUAL(pszLinearUnits, "YARD") || EQUAL(pszLinearUnits, "IYARD") ||
    2284             :              dfLinearConv == 0.9144)
    2285           1 :         sTABProj.nUnitsId = 4;
    2286          94 :     else if (dfLinearConv == 0.001)
    2287           1 :         sTABProj.nUnitsId = 5;
    2288          93 :     else if (dfLinearConv == 0.01)
    2289           1 :         sTABProj.nUnitsId = 6;
    2290          92 :     else if (dfLinearConv == 1.0)
    2291          83 :         sTABProj.nUnitsId = 7;
    2292           9 :     else if (fabs(dfLinearConv - CPLAtof(SRS_UL_US_FOOT_CONV)) <
    2293          14 :                  1e-15 * dfLinearConv ||
    2294           5 :              EQUAL(pszLinearUnits, SRS_UL_US_FOOT))
    2295           4 :         sTABProj.nUnitsId = 8;
    2296           5 :     else if (dfLinearConv == 1852.0 ||
    2297           4 :              EQUAL(pszLinearUnits, SRS_UL_NAUTICAL_MILE))
    2298           1 :         sTABProj.nUnitsId = 9;
    2299           4 :     else if (EQUAL(pszLinearUnits, SRS_UL_LINK) ||
    2300           3 :              EQUAL(pszLinearUnits, "GUNTERLINK"))
    2301           1 :         sTABProj.nUnitsId = 30;
    2302           3 :     else if (EQUAL(pszLinearUnits, SRS_UL_CHAIN) ||
    2303           2 :              EQUAL(pszLinearUnits, "GUNTERCHAIN"))
    2304           1 :         sTABProj.nUnitsId = 31;
    2305           2 :     else if (EQUAL(pszLinearUnits, SRS_UL_ROD))
    2306           1 :         sTABProj.nUnitsId = 32;
    2307           1 :     else if (EQUAL(pszLinearUnits, "Mile") || EQUAL(pszLinearUnits, "IMILE"))
    2308           1 :         sTABProj.nUnitsId = 0;
    2309             :     else
    2310           0 :         sTABProj.nUnitsId = 7;
    2311             : 
    2312         110 :     return 0;
    2313             : }
    2314             : 
    2315             : extern const MapInfoDatumInfo asDatumInfoList[];
    2316             : extern const MapInfoSpheroidInfo asSpheroidInfoList[];
    2317             : 
    2318             : /************************************************************************/
    2319             : /*                      MITABCoordSys2SpatialRef()                      */
    2320             : /*                                                                      */
    2321             : /*      Convert a MIF COORDSYS string into a new OGRSpatialReference    */
    2322             : /*      object.                                                         */
    2323             : /************************************************************************/
    2324             : 
    2325        7021 : OGRSpatialReference *MITABCoordSys2SpatialRef(const char *pszCoordSys)
    2326             : 
    2327             : {
    2328             :     TABProjInfo sTABProj;
    2329        7021 :     if (MITABCoordSys2TABProjInfo(pszCoordSys, &sTABProj) < 0)
    2330        6858 :         return nullptr;
    2331         163 :     OGRSpatialReference *poSR = TABFileGetSpatialRefFromTABProj(sTABProj);
    2332             : 
    2333             :     // Report on translation.
    2334         163 :     char *pszWKT = nullptr;
    2335             : 
    2336         163 :     poSR->exportToWkt(&pszWKT);
    2337         163 :     if (pszWKT != nullptr)
    2338             :     {
    2339         163 :         CPLDebug("MITAB", "This CoordSys value:\n%s\nwas translated to:\n%s",
    2340             :                  pszCoordSys, pszWKT);
    2341         163 :         CPLFree(pszWKT);
    2342             :     }
    2343             : 
    2344         163 :     return poSR;
    2345             : }
    2346             : 
    2347             : /************************************************************************/
    2348             : /*                      MITABSpatialRef2CoordSys()                      */
    2349             : /*                                                                      */
    2350             : /*      Converts a OGRSpatialReference object into a MIF COORDSYS       */
    2351             : /*      string.                                                         */
    2352             : /*                                                                      */
    2353             : /*      The function returns a newly allocated string that should be    */
    2354             : /*      CPLFree()'d by the caller.                                      */
    2355             : /************************************************************************/
    2356             : 
    2357          81 : char *MITABSpatialRef2CoordSys(const OGRSpatialReference *poSR)
    2358             : 
    2359             : {
    2360          81 :     if (poSR == nullptr)
    2361           0 :         return nullptr;
    2362             : 
    2363             :     TABProjInfo sTABProj;
    2364          81 :     int nParamCount = 0;
    2365          81 :     TABFileGetTABProjFromSpatialRef(poSR, sTABProj, nParamCount);
    2366             : 
    2367             :     // Do coordsys lookup.
    2368          81 :     double dXMin = 0.0;
    2369          81 :     double dYMin = 0.0;
    2370          81 :     double dXMax = 0.0;
    2371          81 :     double dYMax = 0.0;
    2372          81 :     bool bHasBounds = false;
    2373         136 :     if (sTABProj.nProjId > 1 &&
    2374          55 :         MITABLookupCoordSysBounds(&sTABProj, dXMin, dYMin, dXMax, dYMax, true))
    2375             :     {
    2376           5 :         bHasBounds = true;
    2377             :     }
    2378             : 
    2379             :     // Translate the units.
    2380          81 :     const char *pszMIFUnits = TABUnitIdToString(sTABProj.nUnitsId);
    2381             : 
    2382             :     // Build coordinate system definition.
    2383         162 :     CPLString osCoordSys;
    2384             : 
    2385          81 :     if (sTABProj.nProjId != 0)
    2386             :     {
    2387          66 :         osCoordSys.Printf("Earth Projection %d", sTABProj.nProjId);
    2388             :     }
    2389             :     else
    2390             :     {
    2391          15 :         osCoordSys.Printf("NonEarth Units");
    2392             :     }
    2393             : 
    2394             :     // Append Datum.
    2395          81 :     if (sTABProj.nProjId != 0)
    2396             :     {
    2397          66 :         osCoordSys += CPLSPrintf(", %d", sTABProj.nDatumId);
    2398             : 
    2399          66 :         if (sTABProj.nDatumId == 999 || sTABProj.nDatumId == 9999)
    2400             :         {
    2401             :             osCoordSys +=
    2402           4 :                 CPLSPrintf(", %d, %.15g, %.15g, %.15g", sTABProj.nEllipsoidId,
    2403             :                            sTABProj.dDatumShiftX, sTABProj.dDatumShiftY,
    2404           4 :                            sTABProj.dDatumShiftZ);
    2405             :         }
    2406             : 
    2407          66 :         if (sTABProj.nDatumId == 9999)
    2408             :         {
    2409             :             osCoordSys +=
    2410             :                 CPLSPrintf(", %.15g, %.15g, %.15g, %.15g, %.15g",
    2411             :                            sTABProj.adDatumParams[0], sTABProj.adDatumParams[1],
    2412             :                            sTABProj.adDatumParams[2], sTABProj.adDatumParams[3],
    2413           3 :                            sTABProj.adDatumParams[4]);
    2414             :         }
    2415             :     }
    2416             : 
    2417             :     // Append units.
    2418          81 :     if (sTABProj.nProjId != 1 && pszMIFUnits != nullptr)
    2419             :     {
    2420          70 :         if (sTABProj.nProjId != 0)
    2421          55 :             osCoordSys += ",";
    2422             : 
    2423          70 :         osCoordSys += CPLSPrintf(" \"%s\"", pszMIFUnits);
    2424             :     }
    2425             : 
    2426             :     // Append Projection Params.
    2427         321 :     for (int iParam = 0; iParam < nParamCount; iParam++)
    2428         240 :         osCoordSys += CPLSPrintf(", %.15g", sTABProj.adProjParams[iParam]);
    2429             : 
    2430             :     // Append user bounds.
    2431          81 :     if (bHasBounds)
    2432             :     {
    2433           5 :         if (fabs(dXMin - floor(dXMin + 0.5)) < 1e-8 &&
    2434           5 :             fabs(dYMin - floor(dYMin + 0.5)) < 1e-8 &&
    2435           5 :             fabs(dXMax - floor(dXMax + 0.5)) < 1e-8 &&
    2436           5 :             fabs(dYMax - floor(dYMax + 0.5)) < 1e-8)
    2437             :         {
    2438           5 :             osCoordSys +=
    2439             :                 CPLSPrintf(" Bounds (%d, %d) (%d, %d)", static_cast<int>(dXMin),
    2440             :                            static_cast<int>(dYMin), static_cast<int>(dXMax),
    2441           5 :                            static_cast<int>(dYMax));
    2442             :         }
    2443             :         else
    2444             :         {
    2445             :             osCoordSys += CPLSPrintf(" Bounds (%f, %f) (%f, %f)", dXMin, dYMin,
    2446           0 :                                      dXMax, dYMax);
    2447             :         }
    2448             :     }
    2449             : 
    2450             :     // Report on translation.
    2451          81 :     char *pszWKT = nullptr;
    2452             : 
    2453          81 :     poSR->exportToWkt(&pszWKT);
    2454          81 :     if (pszWKT != nullptr)
    2455             :     {
    2456          81 :         CPLDebug("MITAB", "This WKT Projection:\n%s\n\ntranslates to:\n%s",
    2457             :                  pszWKT, osCoordSys.c_str());
    2458          81 :         CPLFree(pszWKT);
    2459             :     }
    2460             : 
    2461          81 :     return CPLStrdup(osCoordSys.c_str());
    2462             : }
    2463             : 
    2464             : /************************************************************************/
    2465             : /*                      MITABExtractCoordSysBounds                      */
    2466             : /*                                                                      */
    2467             : /* Return true if MIF coordsys string contains a BOUNDS parameter and   */
    2468             : /* Set x/y min/max values.                                              */
    2469             : /************************************************************************/
    2470             : 
    2471          12 : bool MITABExtractCoordSysBounds(const char *pszCoordSys, double &dXMin,
    2472             :                                 double &dYMin, double &dXMax, double &dYMax)
    2473             : 
    2474             : {
    2475          12 :     if (pszCoordSys == nullptr)
    2476           0 :         return false;
    2477             : 
    2478             :     char **papszFields =
    2479          12 :         CSLTokenizeStringComplex(pszCoordSys, " ,()", TRUE, FALSE);
    2480             : 
    2481          12 :     int iBounds = CSLFindString(papszFields, "Bounds");
    2482             : 
    2483          12 :     if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
    2484             :     {
    2485          12 :         dXMin = CPLAtof(papszFields[++iBounds]);
    2486          12 :         dYMin = CPLAtof(papszFields[++iBounds]);
    2487          12 :         dXMax = CPLAtof(papszFields[++iBounds]);
    2488          12 :         dYMax = CPLAtof(papszFields[++iBounds]);
    2489          12 :         CSLDestroy(papszFields);
    2490          12 :         return true;
    2491             :     }
    2492             : 
    2493           0 :     CSLDestroy(papszFields);
    2494           0 :     return false;
    2495             : }
    2496             : 
    2497             : /**********************************************************************
    2498             :  *                     MITABCoordSys2TABProjInfo()
    2499             :  *
    2500             :  * Convert a MIF COORDSYS string into a TABProjInfo structure.
    2501             :  *
    2502             :  * Returns 0 on success, -1 on error.
    2503             :  **********************************************************************/
    2504        7039 : int MITABCoordSys2TABProjInfo(const char *pszCoordSys, TABProjInfo *psProj)
    2505             : 
    2506             : {
    2507             :     // Set all fields to zero, equivalent of NonEarth Units "mi"
    2508        7039 :     memset(psProj, 0, sizeof(TABProjInfo));
    2509             : 
    2510        7039 :     if (pszCoordSys == nullptr)
    2511        6858 :         return -1;
    2512             : 
    2513             :     // Parse the passed string into words.
    2514         215 :     while (*pszCoordSys == ' ')
    2515          34 :         pszCoordSys++;  // Eat leading spaces.
    2516         181 :     if (STARTS_WITH_CI(pszCoordSys, "CoordSys") && pszCoordSys[8] != '\0')
    2517          33 :         pszCoordSys += 9;
    2518             : 
    2519             :     char **papszFields =
    2520         181 :         CSLTokenizeStringComplex(pszCoordSys, " ,", TRUE, FALSE);
    2521             : 
    2522             :     // Clip off Bounds information.
    2523         181 :     int iBounds = CSLFindString(papszFields, "Bounds");
    2524             : 
    2525         322 :     while (iBounds != -1 && papszFields[iBounds] != nullptr)
    2526             :     {
    2527         141 :         CPLFree(papszFields[iBounds]);
    2528         141 :         papszFields[iBounds] = nullptr;
    2529         141 :         iBounds++;
    2530             :     }
    2531             : 
    2532             :     // Fetch the projection.
    2533         181 :     char **papszNextField = nullptr;
    2534             : 
    2535         329 :     if (CSLCount(papszFields) >= 3 && EQUAL(papszFields[0], "Earth") &&
    2536         148 :         EQUAL(papszFields[1], "Projection"))
    2537             :     {
    2538         148 :         int nProjId = atoi(papszFields[2]);
    2539         148 :         if (nProjId >= 3000)
    2540           0 :             nProjId -= 3000;
    2541         148 :         else if (nProjId >= 2000)
    2542           0 :             nProjId -= 2000;
    2543         148 :         else if (nProjId >= 1000)
    2544           0 :             nProjId -= 1000;
    2545             : 
    2546         148 :         psProj->nProjId = static_cast<GByte>(nProjId);
    2547         148 :         papszNextField = papszFields + 3;
    2548             :     }
    2549          33 :     else if (CSLCount(papszFields) >= 2 && EQUAL(papszFields[0], "NonEarth"))
    2550             :     {
    2551             :         // NonEarth Units "..." Bounds (x, y) (x, y)
    2552          33 :         psProj->nProjId = 0;
    2553          33 :         papszNextField = papszFields + 2;
    2554             : 
    2555          33 :         if (papszNextField[0] != nullptr && EQUAL(papszNextField[0], "Units"))
    2556           0 :             papszNextField++;
    2557             :     }
    2558             :     else
    2559             :     {
    2560             :         // Invalid projection string ???
    2561           0 :         if (CSLCount(papszFields) > 0)
    2562           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
    2563             :                      "Failed parsing CoordSys: '%s'", pszCoordSys);
    2564           0 :         CSLDestroy(papszFields);
    2565           0 :         return -1;
    2566             :     }
    2567             : 
    2568             :     // Fetch the datum information.
    2569         181 :     int nDatum = 0;
    2570             : 
    2571         181 :     if (psProj->nProjId != 0 && CSLCount(papszNextField) > 0)
    2572             :     {
    2573         148 :         nDatum = atoi(papszNextField[0]);
    2574         148 :         papszNextField++;
    2575             :     }
    2576             : 
    2577         181 :     if ((nDatum == 999 || nDatum == 9999) && CSLCount(papszNextField) >= 4)
    2578             :     {
    2579           5 :         psProj->nEllipsoidId = static_cast<GByte>(atoi(papszNextField[0]));
    2580           5 :         psProj->dDatumShiftX = CPLAtof(papszNextField[1]);
    2581           5 :         psProj->dDatumShiftY = CPLAtof(papszNextField[2]);
    2582           5 :         psProj->dDatumShiftZ = CPLAtof(papszNextField[3]);
    2583           5 :         papszNextField += 4;
    2584             : 
    2585           5 :         if (nDatum == 9999 && CSLCount(papszNextField) >= 5)
    2586             :         {
    2587           3 :             psProj->adDatumParams[0] = CPLAtof(papszNextField[0]);
    2588           3 :             psProj->adDatumParams[1] = CPLAtof(papszNextField[1]);
    2589           3 :             psProj->adDatumParams[2] = CPLAtof(papszNextField[2]);
    2590           3 :             psProj->adDatumParams[3] = CPLAtof(papszNextField[3]);
    2591           3 :             psProj->adDatumParams[4] = CPLAtof(papszNextField[4]);
    2592           3 :             papszNextField += 5;
    2593             :         }
    2594             :     }
    2595         176 :     else if (nDatum != 999 && nDatum != 9999)
    2596             :     {
    2597             :         // Find the datum, and collect its parameters if possible.
    2598         176 :         const MapInfoDatumInfo *psDatumInfo = nullptr;
    2599             : 
    2600         176 :         int iDatum = 0;  // Used after for.
    2601        5981 :         for (; asDatumInfoList[iDatum].nMapInfoDatumID != -1; iDatum++)
    2602             :         {
    2603        5981 :             if (asDatumInfoList[iDatum].nMapInfoDatumID == nDatum)
    2604             :             {
    2605         176 :                 psDatumInfo = asDatumInfoList + iDatum;
    2606         176 :                 break;
    2607             :             }
    2608             :         }
    2609             : 
    2610         176 :         if (asDatumInfoList[iDatum].nMapInfoDatumID == -1)
    2611             :         {
    2612             :             // Use WGS84.
    2613           0 :             psDatumInfo = asDatumInfoList + 0;
    2614             :         }
    2615             : 
    2616         176 :         if (psDatumInfo != nullptr)
    2617             :         {
    2618         176 :             psProj->nEllipsoidId = static_cast<GByte>(psDatumInfo->nEllipsoid);
    2619         176 :             psProj->nDatumId =
    2620         176 :                 static_cast<GInt16>(psDatumInfo->nMapInfoDatumID);
    2621         176 :             psProj->dDatumShiftX = psDatumInfo->dfShiftX;
    2622         176 :             psProj->dDatumShiftY = psDatumInfo->dfShiftY;
    2623         176 :             psProj->dDatumShiftZ = psDatumInfo->dfShiftZ;
    2624         176 :             psProj->adDatumParams[0] = psDatumInfo->dfDatumParm0;
    2625         176 :             psProj->adDatumParams[1] = psDatumInfo->dfDatumParm1;
    2626         176 :             psProj->adDatumParams[2] = psDatumInfo->dfDatumParm2;
    2627         176 :             psProj->adDatumParams[3] = psDatumInfo->dfDatumParm3;
    2628         176 :             psProj->adDatumParams[4] = psDatumInfo->dfDatumParm4;
    2629             :         }
    2630             :     }
    2631             : 
    2632             :     // Fetch the units string.
    2633         181 :     if (CSLCount(papszNextField) > 0)
    2634             :     {
    2635         167 :         if (isdigit(static_cast<unsigned char>(papszNextField[0][0])))
    2636             :         {
    2637           0 :             psProj->nUnitsId = static_cast<GByte>(atoi(papszNextField[0]));
    2638             :         }
    2639             :         else
    2640             :         {
    2641         167 :             psProj->nUnitsId =
    2642         167 :                 static_cast<GByte>(TABUnitIdFromString(papszNextField[0]));
    2643             :         }
    2644         167 :         papszNextField++;
    2645             :     }
    2646             : 
    2647             :     // Finally the projection parameters.
    2648         808 :     for (int iParam = 0; iParam < 7 && CSLCount(papszNextField) > 0; iParam++)
    2649             :     {
    2650         627 :         psProj->adProjParams[iParam] = CPLAtof(papszNextField[0]);
    2651         627 :         papszNextField++;
    2652             :     }
    2653             : 
    2654         181 :     CSLDestroy(papszFields);
    2655             : 
    2656         181 :     return 0;
    2657             : }
    2658             : 
    2659             : /*! @endcond */

Generated by: LCOV version 1.14