LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_spatialref.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 796 910 87.5 %
Date: 2024-05-05 22:37:24 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14