LCOV - code coverage report
Current view: top level - frmts/dted - dteddataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 361 430 84.0 %
Date: 2024-05-03 15:49:35 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DTED Translator
       4             :  * Purpose:  GDALDataset driver for DTED translator.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "dted_api.h"
      31             : #include "gdal_frmts.h"
      32             : #include "gdal_pam.h"
      33             : #include "ogr_spatialref.h"
      34             : 
      35             : #include <cstdlib>
      36             : #include <algorithm>
      37             : 
      38             : /************************************************************************/
      39             : /* ==================================================================== */
      40             : /*                              DTEDDataset                             */
      41             : /* ==================================================================== */
      42             : /************************************************************************/
      43             : 
      44             : class DTEDRasterBand;
      45             : 
      46             : class DTEDDataset final : public GDALPamDataset
      47             : {
      48             :     friend class DTEDRasterBand;
      49             : 
      50             :     char *pszFilename;
      51             :     DTEDInfo *psDTED;
      52             :     int bVerifyChecksum;
      53             :     mutable OGRSpatialReference m_oSRS{};
      54             : 
      55             :   public:
      56             :     DTEDDataset();
      57             :     ~DTEDDataset() override;
      58             : 
      59             :     const OGRSpatialReference *GetSpatialRef() const override;
      60             :     CPLErr GetGeoTransform(double *) override;
      61             : 
      62           1 :     const char *GetFileName() const
      63             :     {
      64           1 :         return pszFilename;
      65             :     }
      66             : 
      67             :     void SetFileName(const char *pszFilename);
      68             : 
      69             :     static GDALDataset *Open(GDALOpenInfo *);
      70             :     static int Identify(GDALOpenInfo *);
      71             : };
      72             : 
      73             : /************************************************************************/
      74             : /* ==================================================================== */
      75             : /*                            DTEDRasterBand                             */
      76             : /* ==================================================================== */
      77             : /************************************************************************/
      78             : 
      79             : class DTEDRasterBand final : public GDALPamRasterBand
      80             : {
      81             :     friend class DTEDDataset;
      82             : 
      83             :     int bNoDataSet;
      84             :     double dfNoDataValue;
      85             : 
      86             :   public:
      87             :     DTEDRasterBand(DTEDDataset *, int);
      88             : 
      89             :     CPLErr IReadBlock(int, int, void *) override;
      90             :     CPLErr IWriteBlock(int, int, void *) override;
      91             : 
      92             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
      93             : 
      94          26 :     const char *GetUnitType() override
      95             :     {
      96          26 :         return "m";
      97             :     }
      98             : };
      99             : 
     100             : /************************************************************************/
     101             : /*                           DTEDRasterBand()                            */
     102             : /************************************************************************/
     103             : 
     104          51 : DTEDRasterBand::DTEDRasterBand(DTEDDataset *poDSIn, int nBandIn)
     105          51 :     : bNoDataSet(TRUE), dfNoDataValue(static_cast<double>(DTED_NODATA_VALUE))
     106             : {
     107          51 :     poDS = poDSIn;
     108          51 :     nBand = nBandIn;
     109             : 
     110          51 :     eDataType = GDT_Int16;
     111             : 
     112             :     /* For some applications, it may be valuable to consider the whole DTED */
     113             :     /* file as single block, as the column orientation doesn't fit very well */
     114             :     /* with some scanline oriented algorithms */
     115             :     /* Of course you need to have a big enough case size, particularly for DTED
     116             :      * 2 */
     117             :     /* datasets */
     118          51 :     nBlockXSize =
     119          51 :         CPLTestBool(CPLGetConfigOption("GDAL_DTED_SINGLE_BLOCK", "NO"))
     120          51 :             ? poDS->GetRasterXSize()
     121             :             : 1;
     122          51 :     nBlockYSize = poDS->GetRasterYSize();
     123          51 : }
     124             : 
     125             : /************************************************************************/
     126             : /*                             IReadBlock()                             */
     127             : /************************************************************************/
     128             : 
     129        3911 : CPLErr DTEDRasterBand::IReadBlock(int nBlockXOff, CPL_UNUSED int nBlockYOff,
     130             :                                   void *pImage)
     131             : {
     132        3911 :     DTEDDataset *poDTED_DS = (DTEDDataset *)poDS;
     133        3911 :     int nYSize = poDTED_DS->psDTED->nYSize;
     134             :     GInt16 *panData;
     135             : 
     136             :     (void)nBlockXOff;
     137        3911 :     CPLAssert(nBlockYOff == 0);
     138             : 
     139        3911 :     if (nBlockXSize != 1)
     140             :     {
     141           1 :         const int cbs = 32;  // optimize for 64 byte cache line size
     142           1 :         const int bsy = (nBlockYSize + cbs - 1) / cbs * cbs;
     143           1 :         panData = (GInt16 *)pImage;
     144           1 :         GInt16 *panBuffer = (GInt16 *)CPLMalloc(sizeof(GInt16) * cbs * bsy);
     145           5 :         for (int i = 0; i < nBlockXSize; i += cbs)
     146             :         {
     147           4 :             int n = std::min(cbs, nBlockXSize - i);
     148         125 :             for (int j = 0; j < n; ++j)
     149             :             {
     150         121 :                 if (!DTEDReadProfileEx(poDTED_DS->psDTED, i + j,
     151         121 :                                        panBuffer + j * bsy,
     152             :                                        poDTED_DS->bVerifyChecksum))
     153             :                 {
     154           0 :                     CPLFree(panBuffer);
     155           0 :                     return CE_Failure;
     156             :                 }
     157             :             }
     158         488 :             for (int y = 0; y < nBlockYSize; ++y)
     159             :             {
     160         484 :                 GInt16 *dst = panData + i + (nYSize - y - 1) * nBlockXSize;
     161         484 :                 GInt16 *src = panBuffer + y;
     162       15125 :                 for (int j = 0; j < n; ++j)
     163             :                 {
     164       14641 :                     dst[j] = src[j * bsy];
     165             :                 }
     166             :             }
     167             :         }
     168             : 
     169           1 :         CPLFree(panBuffer);
     170           1 :         return CE_None;
     171             :     }
     172             : 
     173             :     /* -------------------------------------------------------------------- */
     174             :     /*      Read the data.                                                  */
     175             :     /* -------------------------------------------------------------------- */
     176        3910 :     panData = (GInt16 *)pImage;
     177        3910 :     if (!DTEDReadProfileEx(poDTED_DS->psDTED, nBlockXOff, panData,
     178             :                            poDTED_DS->bVerifyChecksum))
     179           1 :         return CE_Failure;
     180             : 
     181             :     /* -------------------------------------------------------------------- */
     182             :     /*      Flip line to orient it top to bottom instead of bottom to       */
     183             :     /*      top.                                                            */
     184             :     /* -------------------------------------------------------------------- */
     185      566898 :     for (int i = nYSize / 2; i >= 0; i--)
     186             :     {
     187      562989 :         std::swap(panData[i], panData[nYSize - i - 1]);
     188             :     }
     189             : 
     190        3909 :     return CE_None;
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                             IReadBlock()                             */
     195             : /************************************************************************/
     196             : 
     197           0 : CPLErr DTEDRasterBand::IWriteBlock(int nBlockXOff, CPL_UNUSED int nBlockYOff,
     198             :                                    void *pImage)
     199             : {
     200           0 :     DTEDDataset *poDTED_DS = (DTEDDataset *)poDS;
     201             :     GInt16 *panData;
     202             : 
     203             :     (void)nBlockXOff;
     204           0 :     CPLAssert(nBlockYOff == 0);
     205             : 
     206           0 :     if (poDTED_DS->eAccess != GA_Update)
     207           0 :         return CE_Failure;
     208             : 
     209           0 :     if (nBlockXSize != 1)
     210             :     {
     211           0 :         panData = (GInt16 *)pImage;
     212           0 :         GInt16 *panBuffer = (GInt16 *)CPLMalloc(sizeof(GInt16) * nBlockYSize);
     213           0 :         for (int i = 0; i < nBlockXSize; i++)
     214             :         {
     215           0 :             for (int j = 0; j < nBlockYSize; j++)
     216             :             {
     217           0 :                 panBuffer[j] = panData[j * nBlockXSize + i];
     218             :             }
     219           0 :             if (!DTEDWriteProfile(poDTED_DS->psDTED, i, panBuffer))
     220             :             {
     221           0 :                 CPLFree(panBuffer);
     222           0 :                 return CE_Failure;
     223             :             }
     224             :         }
     225             : 
     226           0 :         CPLFree(panBuffer);
     227           0 :         return CE_None;
     228             :     }
     229             : 
     230           0 :     panData = (GInt16 *)pImage;
     231           0 :     if (!DTEDWriteProfile(poDTED_DS->psDTED, nBlockXOff, panData))
     232           0 :         return CE_Failure;
     233             : 
     234           0 :     return CE_None;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /*                           GetNoDataValue()                           */
     239             : /************************************************************************/
     240             : 
     241          64 : double DTEDRasterBand::GetNoDataValue(int *pbSuccess)
     242             : 
     243             : {
     244          64 :     if (pbSuccess)
     245          53 :         *pbSuccess = bNoDataSet;
     246             : 
     247          64 :     return dfNoDataValue;
     248             : }
     249             : 
     250             : /************************************************************************/
     251             : /*                            ~DTEDDataset()                            */
     252             : /************************************************************************/
     253             : 
     254          51 : DTEDDataset::DTEDDataset()
     255         102 :     : pszFilename(CPLStrdup("unknown")), psDTED(nullptr),
     256             :       bVerifyChecksum(
     257          51 :           CPLTestBool(CPLGetConfigOption("DTED_VERIFY_CHECKSUM", "NO")))
     258             : {
     259          51 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     260          51 : }
     261             : 
     262             : /************************************************************************/
     263             : /*                            ~DTEDDataset()                            */
     264             : /************************************************************************/
     265             : 
     266         102 : DTEDDataset::~DTEDDataset()
     267             : 
     268             : {
     269          51 :     FlushCache(true);
     270          51 :     CPLFree(pszFilename);
     271          51 :     if (psDTED != nullptr)
     272          51 :         DTEDClose(psDTED);
     273         102 : }
     274             : 
     275             : /************************************************************************/
     276             : /*                            SetFileName()                             */
     277             : /************************************************************************/
     278             : 
     279          51 : void DTEDDataset::SetFileName(const char *pszFilenameIn)
     280             : 
     281             : {
     282          51 :     CPLFree(this->pszFilename);
     283          51 :     this->pszFilename = CPLStrdup(pszFilenameIn);
     284          51 : }
     285             : 
     286             : /************************************************************************/
     287             : /*                              Identify()                              */
     288             : /************************************************************************/
     289             : 
     290       53813 : int DTEDDataset::Identify(GDALOpenInfo *poOpenInfo)
     291             : 
     292             : {
     293             :     /* -------------------------------------------------------------------- */
     294             :     /*      Does the file start with one of the possible DTED header        */
     295             :     /*      record types, and do we have a UHL marker?                      */
     296             :     /* -------------------------------------------------------------------- */
     297       53813 :     if (poOpenInfo->nHeaderBytes < 240)
     298       47683 :         return FALSE;
     299             : 
     300        6130 :     if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "VOL") &&
     301        6130 :         !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "HDR") &&
     302        6128 :         !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "UHL"))
     303             :     {
     304        6028 :         return FALSE;
     305             :     }
     306             : 
     307         102 :     bool bFoundUHL = false;
     308         206 :     for (int i = 0; i < poOpenInfo->nHeaderBytes - 3 && !bFoundUHL;
     309         104 :          i += DTED_UHL_SIZE)
     310             :     {
     311         104 :         if (STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader + i, "UHL"))
     312             :         {
     313         102 :             bFoundUHL = true;
     314             :         }
     315             :     }
     316         102 :     if (!bFoundUHL)
     317           0 :         return FALSE;
     318             : 
     319         102 :     return TRUE;
     320             : }
     321             : 
     322             : /************************************************************************/
     323             : /*                                Open()                                */
     324             : /************************************************************************/
     325             : 
     326          51 : GDALDataset *DTEDDataset::Open(GDALOpenInfo *poOpenInfo)
     327             : 
     328             : {
     329          51 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     330           0 :         return nullptr;
     331             : 
     332             :     /* -------------------------------------------------------------------- */
     333             :     /*      Try opening the dataset.                                        */
     334             :     /* -------------------------------------------------------------------- */
     335          51 :     VSILFILE *fp = poOpenInfo->fpL;
     336          51 :     poOpenInfo->fpL = nullptr;
     337             :     DTEDInfo *psDTED =
     338          51 :         DTEDOpenEx(fp, poOpenInfo->pszFilename,
     339          51 :                    (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb", TRUE);
     340             : 
     341          51 :     if (psDTED == nullptr)
     342           0 :         return nullptr;
     343             : 
     344             :     /* -------------------------------------------------------------------- */
     345             :     /*      Create a corresponding GDALDataset.                             */
     346             :     /* -------------------------------------------------------------------- */
     347          51 :     DTEDDataset *poDS = new DTEDDataset();
     348          51 :     poDS->SetFileName(poOpenInfo->pszFilename);
     349             : 
     350          51 :     poDS->eAccess = poOpenInfo->eAccess;
     351          51 :     poDS->psDTED = psDTED;
     352             : 
     353             :     /* -------------------------------------------------------------------- */
     354             :     /*      Capture some information from the file that is of interest.     */
     355             :     /* -------------------------------------------------------------------- */
     356          51 :     poDS->nRasterXSize = psDTED->nXSize;
     357          51 :     poDS->nRasterYSize = psDTED->nYSize;
     358             : 
     359          51 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     360             :     {
     361           0 :         delete poDS;
     362           0 :         return nullptr;
     363             :     }
     364             : 
     365             :     /* -------------------------------------------------------------------- */
     366             :     /*      Create band information objects.                                */
     367             :     /* -------------------------------------------------------------------- */
     368          51 :     poDS->nBands = 1;
     369         102 :     for (int i = 0; i < poDS->nBands; i++)
     370          51 :         poDS->SetBand(i + 1, new DTEDRasterBand(poDS, i + 1));
     371             : 
     372             :     /* -------------------------------------------------------------------- */
     373             :     /*      Collect any metadata available.                                 */
     374             :     /* -------------------------------------------------------------------- */
     375          51 :     char *pszValue = DTEDGetMetadata(psDTED, DTEDMD_VERTACCURACY_UHL);
     376          51 :     poDS->SetMetadataItem("DTED_VerticalAccuracy_UHL", pszValue);
     377          51 :     CPLFree(pszValue);
     378             : 
     379          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_VERTACCURACY_ACC);
     380          51 :     poDS->SetMetadataItem("DTED_VerticalAccuracy_ACC", pszValue);
     381          51 :     CPLFree(pszValue);
     382             : 
     383          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_SECURITYCODE_UHL);
     384          51 :     poDS->SetMetadataItem("DTED_SecurityCode_UHL", pszValue);
     385          51 :     CPLFree(pszValue);
     386             : 
     387          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_SECURITYCODE_DSI);
     388          51 :     poDS->SetMetadataItem("DTED_SecurityCode_DSI", pszValue);
     389          51 :     CPLFree(pszValue);
     390             : 
     391          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_UNIQUEREF_UHL);
     392          51 :     poDS->SetMetadataItem("DTED_UniqueRef_UHL", pszValue);
     393          51 :     CPLFree(pszValue);
     394             : 
     395          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_UNIQUEREF_DSI);
     396          51 :     poDS->SetMetadataItem("DTED_UniqueRef_DSI", pszValue);
     397          51 :     CPLFree(pszValue);
     398             : 
     399          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_DATA_EDITION);
     400          51 :     poDS->SetMetadataItem("DTED_DataEdition", pszValue);
     401          51 :     CPLFree(pszValue);
     402             : 
     403          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_MATCHMERGE_VERSION);
     404          51 :     poDS->SetMetadataItem("DTED_MatchMergeVersion", pszValue);
     405          51 :     CPLFree(pszValue);
     406             : 
     407          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_MAINT_DATE);
     408          51 :     poDS->SetMetadataItem("DTED_MaintenanceDate", pszValue);
     409          51 :     CPLFree(pszValue);
     410             : 
     411          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_MATCHMERGE_DATE);
     412          51 :     poDS->SetMetadataItem("DTED_MatchMergeDate", pszValue);
     413          51 :     CPLFree(pszValue);
     414             : 
     415          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_MAINT_DESCRIPTION);
     416          51 :     poDS->SetMetadataItem("DTED_MaintenanceDescription", pszValue);
     417          51 :     CPLFree(pszValue);
     418             : 
     419          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_PRODUCER);
     420          51 :     poDS->SetMetadataItem("DTED_Producer", pszValue);
     421          51 :     CPLFree(pszValue);
     422             : 
     423          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_VERTDATUM);
     424          51 :     poDS->SetMetadataItem("DTED_VerticalDatum", pszValue);
     425          51 :     CPLFree(pszValue);
     426             : 
     427          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_HORIZDATUM);
     428          51 :     poDS->SetMetadataItem("DTED_HorizontalDatum", pszValue);
     429          51 :     CPLFree(pszValue);
     430             : 
     431          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_DIGITIZING_SYS);
     432          51 :     poDS->SetMetadataItem("DTED_DigitizingSystem", pszValue);
     433          51 :     CPLFree(pszValue);
     434             : 
     435          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_COMPILATION_DATE);
     436          51 :     poDS->SetMetadataItem("DTED_CompilationDate", pszValue);
     437          51 :     CPLFree(pszValue);
     438             : 
     439          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_HORIZACCURACY);
     440          51 :     poDS->SetMetadataItem("DTED_HorizontalAccuracy", pszValue);
     441          51 :     CPLFree(pszValue);
     442             : 
     443          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_REL_HORIZACCURACY);
     444          51 :     poDS->SetMetadataItem("DTED_RelHorizontalAccuracy", pszValue);
     445          51 :     CPLFree(pszValue);
     446             : 
     447          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_REL_VERTACCURACY);
     448          51 :     poDS->SetMetadataItem("DTED_RelVerticalAccuracy", pszValue);
     449          51 :     CPLFree(pszValue);
     450             : 
     451          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_ORIGINLAT);
     452          51 :     poDS->SetMetadataItem("DTED_OriginLatitude", pszValue);
     453          51 :     CPLFree(pszValue);
     454             : 
     455          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_ORIGINLONG);
     456          51 :     poDS->SetMetadataItem("DTED_OriginLongitude", pszValue);
     457          51 :     CPLFree(pszValue);
     458             : 
     459          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_NIMA_DESIGNATOR);
     460          51 :     poDS->SetMetadataItem("DTED_NimaDesignator", pszValue);
     461          51 :     CPLFree(pszValue);
     462             : 
     463          51 :     pszValue = DTEDGetMetadata(psDTED, DTEDMD_PARTIALCELL_DSI);
     464          51 :     poDS->SetMetadataItem("DTED_PartialCellIndicator", pszValue);
     465          51 :     CPLFree(pszValue);
     466             : 
     467          51 :     poDS->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
     468             : 
     469             :     /* -------------------------------------------------------------------- */
     470             :     /*      Initialize any PAM information.                                 */
     471             :     /* -------------------------------------------------------------------- */
     472          51 :     poDS->SetDescription(poOpenInfo->pszFilename);
     473          51 :     poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
     474             : 
     475             :     // if no SR in xml, try aux
     476          51 :     if (poDS->GDALPamDataset::GetSpatialRef() == nullptr)
     477             :     {
     478          51 :         int bTryAux = TRUE;
     479          51 :         if (poOpenInfo->GetSiblingFiles() != nullptr &&
     480          51 :             CSLFindString(poOpenInfo->GetSiblingFiles(),
     481             :                           CPLResetExtension(
     482          51 :                               CPLGetFilename(poOpenInfo->pszFilename), "aux")) <
     483         102 :                 0 &&
     484         102 :             CSLFindString(
     485          51 :                 poOpenInfo->GetSiblingFiles(),
     486          51 :                 CPLSPrintf("%s.aux", CPLGetFilename(poOpenInfo->pszFilename))) <
     487             :                 0)
     488          51 :             bTryAux = FALSE;
     489          51 :         if (bTryAux)
     490             :         {
     491           0 :             GDALDataset *poAuxDS = GDALFindAssociatedAuxFile(
     492           0 :                 poOpenInfo->pszFilename, GA_ReadOnly, poDS);
     493           0 :             if (poAuxDS)
     494             :             {
     495           0 :                 const auto poSRS = poAuxDS->GetSpatialRef();
     496           0 :                 if (poSRS)
     497             :                 {
     498           0 :                     poDS->m_oSRS = *poSRS;
     499             :                 }
     500             : 
     501           0 :                 GDALClose(poAuxDS);
     502             :             }
     503             :         }
     504             :     }
     505             : 
     506             :     /* -------------------------------------------------------------------- */
     507             :     /*      Support overviews.                                              */
     508             :     /* -------------------------------------------------------------------- */
     509          51 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
     510             :                                 poOpenInfo->GetSiblingFiles());
     511          51 :     return poDS;
     512             : }
     513             : 
     514             : /************************************************************************/
     515             : /*                          GetGeoTransform()                           */
     516             : /************************************************************************/
     517             : 
     518          43 : CPLErr DTEDDataset::GetGeoTransform(double *padfTransform)
     519             : 
     520             : {
     521             : 
     522             :     bool bApplyPixelIsPoint =
     523          43 :         CPLTestBool(CPLGetConfigOption("DTED_APPLY_PIXEL_IS_POINT", "FALSE"));
     524          43 :     if (!bApplyPixelIsPoint)
     525             :     {
     526          42 :         padfTransform[0] = psDTED->dfULCornerX;
     527          42 :         padfTransform[1] = psDTED->dfPixelSizeX;
     528          42 :         padfTransform[2] = 0.0;
     529          42 :         padfTransform[3] = psDTED->dfULCornerY;
     530          42 :         padfTransform[4] = 0.0;
     531          42 :         padfTransform[5] = psDTED->dfPixelSizeY * -1;
     532             : 
     533          42 :         return CE_None;
     534             :     }
     535             :     else
     536             :     {
     537           1 :         padfTransform[0] = psDTED->dfULCornerX + (0.5 * psDTED->dfPixelSizeX);
     538           1 :         padfTransform[1] = psDTED->dfPixelSizeX;
     539           1 :         padfTransform[2] = 0.0;
     540           1 :         padfTransform[3] = psDTED->dfULCornerY - (0.5 * psDTED->dfPixelSizeY);
     541           1 :         padfTransform[4] = 0.0;
     542           1 :         padfTransform[5] = psDTED->dfPixelSizeY * -1;
     543             : 
     544           1 :         return CE_None;
     545             :     }
     546             : }
     547             : 
     548             : /************************************************************************/
     549             : /*                          GetSpatialRef()                             */
     550             : /************************************************************************/
     551             : 
     552          39 : const OGRSpatialReference *DTEDDataset::GetSpatialRef() const
     553             : 
     554             : {
     555          39 :     if (!m_oSRS.IsEmpty())
     556          20 :         return &m_oSRS;
     557             : 
     558             :     // get xml and aux SR first
     559          19 :     const auto poSRS = GDALPamDataset::GetSpatialRef();
     560          19 :     if (poSRS)
     561             :     {
     562           0 :         m_oSRS = *poSRS;
     563           0 :         return &m_oSRS;
     564             :     }
     565             : 
     566             :     const char *pszVertDatum;
     567          38 :     const char *pszPrj = const_cast<DTEDDataset *>(this)->GetMetadataItem(
     568          19 :         "DTED_HorizontalDatum");
     569          19 :     if (EQUAL(pszPrj, "WGS84"))
     570             :     {
     571             : 
     572          36 :         pszVertDatum = const_cast<DTEDDataset *>(this)->GetMetadataItem(
     573          18 :             "DTED_VerticalDatum");
     574          36 :         if ((EQUAL(pszVertDatum, "MSL") || EQUAL(pszVertDatum, "E96")) &&
     575          18 :             CPLTestBool(CPLGetConfigOption("REPORT_COMPD_CS", "NO")))
     576             :         {
     577           0 :             m_oSRS.importFromWkt(
     578             :                 "COMPD_CS[\"WGS 84 + EGM96 geoid height\", GEOGCS[\"WGS 84\", "
     579             :                 "DATUM[\"WGS_1984\", SPHEROID[\"WGS "
     580             :                 "84\",6378137,298.257223563, AUTHORITY[\"EPSG\",\"7030\"]], "
     581             :                 "AUTHORITY[\"EPSG\",\"6326\"]], PRIMEM[\"Greenwich\",0, "
     582             :                 "AUTHORITY[\"EPSG\",\"8901\"]], "
     583             :                 "UNIT[\"degree\",0.0174532925199433, "
     584             :                 "AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Latitude\",NORTH],AXIS["
     585             :                 "\"Longitude\",EAST], AUTHORITY[\"EPSG\",\"4326\"]], "
     586             :                 "VERT_CS[\"EGM96 geoid height\", VERT_DATUM[\"EGM96 "
     587             :                 "geoid\",2005, AUTHORITY[\"EPSG\",\"5171\"]], "
     588             :                 "UNIT[\"metre\",1, AUTHORITY[\"EPSG\",\"9001\"]], "
     589             :                 "AXIS[\"Up\",UP], AUTHORITY[\"EPSG\",\"5773\"]]]");
     590             :         }
     591             :         // Support DTED with EGM08 vertical datum reference
     592          18 :         else if ((EQUAL(pszVertDatum, "E08")) &&
     593           0 :                  CPLTestBool(CPLGetConfigOption("REPORT_COMPD_CS", "NO")))
     594             :         {
     595           0 :             m_oSRS.importFromWkt(
     596             :                 "COMPD_CS[\"WGS 84 + EGM2008 height\",GEOGCS[\"WGS "
     597             :                 "84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS "
     598             :                 "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],"
     599             :                 "AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,"
     600             :                 "AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0."
     601             :                 "0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY["
     602             :                 "\"EPSG\",\"4326\"]],VERT_CS[\"EGM2008 "
     603             :                 "height\",VERT_DATUM[\"EGM2008 "
     604             :                 "geoid\",2005,AUTHORITY[\"EPSG\",\"1027\"]],UNIT[\"metre\",1,"
     605             :                 "AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Gravity-related "
     606             :                 "height\",UP],AUTHORITY[\"EPSG\",\"3855\"]]]");
     607             :         }
     608             :         else
     609             :         {
     610          18 :             m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
     611             :         }
     612             :     }
     613           1 :     else if (EQUAL(pszPrj, "WGS72"))
     614             :     {
     615             :         static bool bWarned = false;
     616           1 :         if (!bWarned)
     617             :         {
     618           1 :             bWarned = true;
     619           1 :             CPLError(CE_Warning, CPLE_AppDefined,
     620             :                      "The DTED file %s indicates WGS72 as horizontal datum. \n"
     621             :                      "As this is outdated nowadays, you should contact your "
     622             :                      "data producer to get data georeferenced in WGS84.\n"
     623             :                      "In some cases, WGS72 is a wrong indication and the "
     624             :                      "georeferencing is really WGS84. In that case\n"
     625             :                      "you might consider doing 'gdal_translate -of DTED -mo "
     626             :                      "\"DTED_HorizontalDatum=WGS84\" src.dtX dst.dtX' to\n"
     627             :                      "fix the DTED file.\n"
     628             :                      "No more warnings will be issued in this session about "
     629             :                      "this operation.",
     630             :                      GetFileName());
     631             :         }
     632           1 :         m_oSRS.importFromWkt(
     633             :             "GEOGCS[\"WGS 72\",DATUM[\"WGS_1972\",SPHEROID[\"WGS "
     634             :             "72\",6378135,298.26]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0."
     635             :             "0174532925199433],AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\","
     636             :             "EAST],AUTHORITY[\"EPSG\",\"4322\"]]");
     637             :     }
     638             :     else
     639             :     {
     640             :         static bool bWarned = false;
     641           0 :         if (!bWarned)
     642             :         {
     643           0 :             bWarned = true;
     644           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     645             :                      "The DTED file %s indicates %s as horizontal datum, which "
     646             :                      "is not recognized by the DTED driver. \n"
     647             :                      "The DTED driver is going to consider it as WGS84.\n"
     648             :                      "No more warnings will be issued in this session about "
     649             :                      "this operation.",
     650             :                      GetFileName(), pszPrj);
     651             :         }
     652           0 :         m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG);
     653             :     }
     654          19 :     return &m_oSRS;
     655             : }
     656             : 
     657             : /************************************************************************/
     658             : /*                           DTEDCreateCopy()                           */
     659             : /*                                                                      */
     660             : /*      For now we will assume the input is exactly one proper          */
     661             : /*      cell.                                                           */
     662             : /************************************************************************/
     663             : 
     664          22 : static GDALDataset *DTEDCreateCopy(const char *pszFilename,
     665             :                                    GDALDataset *poSrcDS, int bStrict,
     666             :                                    char ** /* papszOptions */,
     667             :                                    GDALProgressFunc pfnProgress,
     668             :                                    void *pProgressData)
     669             : 
     670             : {
     671             :     /* -------------------------------------------------------------------- */
     672             :     /*      Some some rudimentary checks                                    */
     673             :     /* -------------------------------------------------------------------- */
     674          22 :     const int nBands = poSrcDS->GetRasterCount();
     675          22 :     if (nBands == 0)
     676             :     {
     677           1 :         CPLError(
     678             :             CE_Failure, CPLE_NotSupported,
     679             :             "DTED driver does not support source dataset with zero band.\n");
     680           1 :         return nullptr;
     681             :     }
     682             : 
     683          21 :     if (nBands != 1)
     684             :     {
     685           4 :         CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
     686             :                  "DTED driver only uses the first band of the dataset.\n");
     687           4 :         if (bStrict)
     688           4 :             return nullptr;
     689             :     }
     690             : 
     691          17 :     if (pfnProgress && !pfnProgress(0.0, nullptr, pProgressData))
     692           0 :         return nullptr;
     693             : 
     694             :     /* -------------------------------------------------------------------- */
     695             :     /*      Work out the level.                                             */
     696             :     /* -------------------------------------------------------------------- */
     697             :     int nLevel;
     698             : 
     699          17 :     if (poSrcDS->GetRasterYSize() == 121)
     700           3 :         nLevel = 0;
     701          14 :     else if (poSrcDS->GetRasterYSize() == 1201)
     702           3 :         nLevel = 1;
     703          11 :     else if (poSrcDS->GetRasterYSize() == 3601)
     704           0 :         nLevel = 2;
     705             :     else
     706             :     {
     707          11 :         CPLError(CE_Warning, CPLE_AppDefined,
     708             :                  "The source does not appear to be a properly formatted cell.");
     709          11 :         nLevel = 1;
     710             :     }
     711             : 
     712             :     /* -------------------------------------------------------------------- */
     713             :     /*      Checks the input SRS                                            */
     714             :     /* -------------------------------------------------------------------- */
     715          34 :     OGRSpatialReference ogrsr_input;
     716          17 :     ogrsr_input.importFromWkt(poSrcDS->GetProjectionRef());
     717          34 :     OGRSpatialReference ogrsr_wgs84;
     718          17 :     ogrsr_wgs84.SetWellKnownGeogCS("WGS84");
     719          17 :     if (ogrsr_input.IsSameGeogCS(&ogrsr_wgs84) == FALSE)
     720             :     {
     721           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     722             :                  "The source projection coordinate system is %s. Only WGS 84 "
     723             :                  "is supported.\n"
     724             :                  "The DTED driver will generate a file as if the source was "
     725             :                  "WGS 84 projection coordinate system.",
     726             :                  poSrcDS->GetProjectionRef());
     727             :     }
     728             : 
     729             :     /* -------------------------------------------------------------------- */
     730             :     /*      Work out the LL origin.                                         */
     731             :     /* -------------------------------------------------------------------- */
     732             :     double adfGeoTransform[6];
     733             : 
     734          17 :     poSrcDS->GetGeoTransform(adfGeoTransform);
     735             : 
     736             :     int nLLOriginLat =
     737          34 :         (int)floor(adfGeoTransform[3] +
     738          17 :                    poSrcDS->GetRasterYSize() * adfGeoTransform[5] + 0.5);
     739             : 
     740          17 :     int nLLOriginLong = (int)floor(adfGeoTransform[0] + 0.5);
     741             : 
     742          51 :     if (fabs(nLLOriginLat -
     743          17 :              (adfGeoTransform[3] + (poSrcDS->GetRasterYSize() - 0.5) *
     744          21 :                                        adfGeoTransform[5])) > 1e-10 ||
     745           4 :         fabs(nLLOriginLong - (adfGeoTransform[0] + 0.5 * adfGeoTransform[1])) >
     746             :             1e-10)
     747             :     {
     748          13 :         CPLError(CE_Warning, CPLE_AppDefined,
     749             :                  "The corner coordinates of the source are not properly "
     750             :                  "aligned on plain latitude/longitude boundaries.");
     751             :     }
     752             : 
     753             :     /* -------------------------------------------------------------------- */
     754             :     /*     Check horizontal source size.                                    */
     755             :     /* -------------------------------------------------------------------- */
     756             :     int expectedXSize;
     757          17 :     int nReferenceLat = nLLOriginLat < 0 ? -(nLLOriginLat + 1) : nLLOriginLat;
     758          17 :     if (nReferenceLat >= 80)
     759           0 :         expectedXSize = (poSrcDS->GetRasterYSize() - 1) / 6 + 1;
     760          17 :     else if (nReferenceLat >= 75)
     761           0 :         expectedXSize = (poSrcDS->GetRasterYSize() - 1) / 4 + 1;
     762          17 :     else if (nReferenceLat >= 70)
     763           0 :         expectedXSize = (poSrcDS->GetRasterYSize() - 1) / 3 + 1;
     764          17 :     else if (nReferenceLat >= 50)
     765           1 :         expectedXSize = (poSrcDS->GetRasterYSize() - 1) / 2 + 1;
     766             :     else
     767          16 :         expectedXSize = poSrcDS->GetRasterYSize();
     768             : 
     769          17 :     if (poSrcDS->GetRasterXSize() != expectedXSize)
     770             :     {
     771           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     772             :                  "The horizontal source size is not conformant with the one "
     773             :                  "expected by DTED Level %d at this latitude (%d pixels found "
     774             :                  "instead of %d).",
     775             :                  nLevel, poSrcDS->GetRasterXSize(), expectedXSize);
     776             :     }
     777             : 
     778             :     /* -------------------------------------------------------------------- */
     779             :     /*      Create the output dted file.                                    */
     780             :     /* -------------------------------------------------------------------- */
     781             :     const char *pszError =
     782          17 :         DTEDCreate(pszFilename, nLevel, nLLOriginLat, nLLOriginLong);
     783             : 
     784          17 :     if (pszError != nullptr)
     785             :     {
     786           2 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", pszError);
     787           2 :         return nullptr;
     788             :     }
     789             : 
     790             :     /* -------------------------------------------------------------------- */
     791             :     /*      Open the DTED file so we can output the data to it.             */
     792             :     /* -------------------------------------------------------------------- */
     793          15 :     DTEDInfo *psDTED = DTEDOpen(pszFilename, "rb+", FALSE);
     794          15 :     if (psDTED == nullptr)
     795           0 :         return nullptr;
     796             : 
     797             :     /* -------------------------------------------------------------------- */
     798             :     /*      Read all the data in a single buffer.                           */
     799             :     /* -------------------------------------------------------------------- */
     800          15 :     GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
     801          15 :     GInt16 *panData = (GInt16 *)VSI_MALLOC_VERBOSE(
     802             :         sizeof(GInt16) * psDTED->nXSize * psDTED->nYSize);
     803          15 :     if (panData == nullptr)
     804             :     {
     805           0 :         DTEDClose(psDTED);
     806           0 :         return nullptr;
     807             :     }
     808             : 
     809        1579 :     for (int iY = 0; iY < psDTED->nYSize; iY++)
     810             :     {
     811        3150 :         if (poSrcBand->RasterIO(GF_Read, 0, iY, psDTED->nXSize, 1,
     812        1575 :                                 (void *)(panData + iY * psDTED->nXSize),
     813             :                                 psDTED->nXSize, 1, GDT_Int16, 0, 0,
     814        1575 :                                 nullptr) != CE_None)
     815             :         {
     816          11 :             DTEDClose(psDTED);
     817          11 :             CPLFree(panData);
     818          11 :             return nullptr;
     819             :         }
     820             : 
     821        1564 :         if (pfnProgress && !pfnProgress(0.5 * (iY + 1) / (double)psDTED->nYSize,
     822             :                                         nullptr, pProgressData))
     823             :         {
     824           0 :             CPLError(CE_Failure, CPLE_UserInterrupt,
     825             :                      "User terminated CreateCopy()");
     826           0 :             DTEDClose(psDTED);
     827           0 :             CPLFree(panData);
     828           0 :             return nullptr;
     829             :         }
     830             :     }
     831             : 
     832             :     int bSrcBandHasNoData;
     833           4 :     double srcBandNoData = poSrcBand->GetNoDataValue(&bSrcBandHasNoData);
     834             : 
     835             :     /* -------------------------------------------------------------------- */
     836             :     /*      Write all the profiles.                                         */
     837             :     /* -------------------------------------------------------------------- */
     838             :     GInt16 anProfData[3601];
     839           4 :     int dfNodataCount = 0;
     840             :     GByte iPartialCell;
     841             : 
     842         968 :     for (int iProfile = 0; iProfile < psDTED->nXSize; iProfile++)
     843             :     {
     844      766688 :         for (int iY = 0; iY < psDTED->nYSize; iY++)
     845             :         {
     846      765724 :             anProfData[iY] = panData[iProfile + iY * psDTED->nXSize];
     847      765724 :             if (bSrcBandHasNoData && anProfData[iY] == srcBandNoData)
     848             :             {
     849           0 :                 anProfData[iY] = DTED_NODATA_VALUE;
     850           0 :                 dfNodataCount++;
     851             :             }
     852      765724 :             else if (anProfData[iY] == DTED_NODATA_VALUE)
     853           0 :                 dfNodataCount++;
     854             :         }
     855         964 :         DTEDWriteProfile(psDTED, iProfile, anProfData);
     856             : 
     857        1928 :         if (pfnProgress &&
     858         964 :             !pfnProgress(0.5 + 0.5 * (iProfile + 1) / (double)psDTED->nXSize,
     859             :                          nullptr, pProgressData))
     860             :         {
     861           0 :             CPLError(CE_Failure, CPLE_UserInterrupt,
     862             :                      "User terminated CreateCopy()");
     863           0 :             DTEDClose(psDTED);
     864           0 :             CPLFree(panData);
     865           0 :             return nullptr;
     866             :         }
     867             :     }
     868           4 :     CPLFree(panData);
     869             : 
     870             :     /* -------------------------------------------------------------------- */
     871             :     /* Partial cell indicator: 0 for complete coverage; 1-99 for incomplete */
     872             :     /* -------------------------------------------------------------------- */
     873             :     char szPartialCell[3];
     874             : 
     875           4 :     if (dfNodataCount == 0)
     876           4 :         iPartialCell = 0;
     877             :     else
     878             :     {
     879           0 :         iPartialCell =
     880           0 :             (GByte) int(floor(100.0 - (dfNodataCount * 100.0 /
     881           0 :                                        (psDTED->nXSize * psDTED->nYSize))));
     882           0 :         if (iPartialCell < 1)
     883           0 :             iPartialCell = 1;
     884             :     }
     885             : 
     886           4 :     CPLsnprintf(szPartialCell, sizeof(szPartialCell), "%02d", iPartialCell);
     887           4 :     DTEDSetMetadata(psDTED, DTEDMD_PARTIALCELL_DSI, szPartialCell);
     888             : 
     889             :     /* -------------------------------------------------------------------- */
     890             :     /*      Try to copy any matching available metadata.                    */
     891             :     /* -------------------------------------------------------------------- */
     892           4 :     if (poSrcDS->GetMetadataItem("DTED_VerticalAccuracy_UHL") != nullptr)
     893           3 :         DTEDSetMetadata(psDTED, DTEDMD_VERTACCURACY_UHL,
     894           3 :                         poSrcDS->GetMetadataItem("DTED_VerticalAccuracy_UHL"));
     895             : 
     896           4 :     if (poSrcDS->GetMetadataItem("DTED_VerticalAccuracy_ACC") != nullptr)
     897           3 :         DTEDSetMetadata(psDTED, DTEDMD_VERTACCURACY_ACC,
     898           3 :                         poSrcDS->GetMetadataItem("DTED_VerticalAccuracy_ACC"));
     899             : 
     900           4 :     if (poSrcDS->GetMetadataItem("DTED_SecurityCode_UHL") != nullptr)
     901           3 :         DTEDSetMetadata(psDTED, DTEDMD_SECURITYCODE_UHL,
     902           3 :                         poSrcDS->GetMetadataItem("DTED_SecurityCode_UHL"));
     903             : 
     904           4 :     if (poSrcDS->GetMetadataItem("DTED_SecurityCode_DSI") != nullptr)
     905           3 :         DTEDSetMetadata(psDTED, DTEDMD_SECURITYCODE_DSI,
     906           3 :                         poSrcDS->GetMetadataItem("DTED_SecurityCode_DSI"));
     907             : 
     908           4 :     if (poSrcDS->GetMetadataItem("DTED_UniqueRef_UHL") != nullptr)
     909           3 :         DTEDSetMetadata(psDTED, DTEDMD_UNIQUEREF_UHL,
     910           3 :                         poSrcDS->GetMetadataItem("DTED_UniqueRef_UHL"));
     911             : 
     912           4 :     if (poSrcDS->GetMetadataItem("DTED_UniqueRef_DSI") != nullptr)
     913           3 :         DTEDSetMetadata(psDTED, DTEDMD_UNIQUEREF_DSI,
     914           3 :                         poSrcDS->GetMetadataItem("DTED_UniqueRef_DSI"));
     915             : 
     916           4 :     if (poSrcDS->GetMetadataItem("DTED_DataEdition") != nullptr)
     917           3 :         DTEDSetMetadata(psDTED, DTEDMD_DATA_EDITION,
     918           3 :                         poSrcDS->GetMetadataItem("DTED_DataEdition"));
     919             : 
     920           4 :     if (poSrcDS->GetMetadataItem("DTED_MatchMergeVersion") != nullptr)
     921           3 :         DTEDSetMetadata(psDTED, DTEDMD_MATCHMERGE_VERSION,
     922           3 :                         poSrcDS->GetMetadataItem("DTED_MatchMergeVersion"));
     923             : 
     924           4 :     if (poSrcDS->GetMetadataItem("DTED_MaintenanceDate") != nullptr)
     925           3 :         DTEDSetMetadata(psDTED, DTEDMD_MAINT_DATE,
     926           3 :                         poSrcDS->GetMetadataItem("DTED_MaintenanceDate"));
     927             : 
     928           4 :     if (poSrcDS->GetMetadataItem("DTED_MatchMergeDate") != nullptr)
     929           3 :         DTEDSetMetadata(psDTED, DTEDMD_MATCHMERGE_DATE,
     930           3 :                         poSrcDS->GetMetadataItem("DTED_MatchMergeDate"));
     931             : 
     932           4 :     if (poSrcDS->GetMetadataItem("DTED_MaintenanceDescription") != nullptr)
     933           3 :         DTEDSetMetadata(
     934             :             psDTED, DTEDMD_MAINT_DESCRIPTION,
     935           3 :             poSrcDS->GetMetadataItem("DTED_MaintenanceDescription"));
     936             : 
     937           4 :     if (poSrcDS->GetMetadataItem("DTED_Producer") != nullptr)
     938           3 :         DTEDSetMetadata(psDTED, DTEDMD_PRODUCER,
     939           3 :                         poSrcDS->GetMetadataItem("DTED_Producer"));
     940             : 
     941           4 :     if (poSrcDS->GetMetadataItem("DTED_VerticalDatum") != nullptr)
     942           3 :         DTEDSetMetadata(psDTED, DTEDMD_VERTDATUM,
     943           3 :                         poSrcDS->GetMetadataItem("DTED_VerticalDatum"));
     944             : 
     945           4 :     if (poSrcDS->GetMetadataItem("DTED_HorizontalDatum") != nullptr)
     946           3 :         DTEDSetMetadata(psDTED, DTEDMD_HORIZDATUM,
     947           3 :                         poSrcDS->GetMetadataItem("DTED_HorizontalDatum"));
     948             : 
     949           4 :     if (poSrcDS->GetMetadataItem("DTED_DigitizingSystem") != nullptr)
     950           3 :         DTEDSetMetadata(psDTED, DTEDMD_DIGITIZING_SYS,
     951           3 :                         poSrcDS->GetMetadataItem("DTED_DigitizingSystem"));
     952             : 
     953           4 :     if (poSrcDS->GetMetadataItem("DTED_CompilationDate") != nullptr)
     954           3 :         DTEDSetMetadata(psDTED, DTEDMD_COMPILATION_DATE,
     955           3 :                         poSrcDS->GetMetadataItem("DTED_CompilationDate"));
     956             : 
     957           4 :     if (poSrcDS->GetMetadataItem("DTED_HorizontalAccuracy") != nullptr)
     958           3 :         DTEDSetMetadata(psDTED, DTEDMD_HORIZACCURACY,
     959           3 :                         poSrcDS->GetMetadataItem("DTED_HorizontalAccuracy"));
     960             : 
     961           4 :     if (poSrcDS->GetMetadataItem("DTED_RelHorizontalAccuracy") != nullptr)
     962           3 :         DTEDSetMetadata(psDTED, DTEDMD_REL_HORIZACCURACY,
     963           3 :                         poSrcDS->GetMetadataItem("DTED_RelHorizontalAccuracy"));
     964             : 
     965           4 :     if (poSrcDS->GetMetadataItem("DTED_RelVerticalAccuracy") != nullptr)
     966           3 :         DTEDSetMetadata(psDTED, DTEDMD_REL_VERTACCURACY,
     967           3 :                         poSrcDS->GetMetadataItem("DTED_RelVerticalAccuracy"));
     968             : 
     969             :     /* -------------------------------------------------------------------- */
     970             :     /*      Try to open the resulting DTED file.                            */
     971             :     /* -------------------------------------------------------------------- */
     972           4 :     DTEDClose(psDTED);
     973             : 
     974             :     /* -------------------------------------------------------------------- */
     975             :     /*      Reopen and copy missing information into a PAM file.            */
     976             :     /* -------------------------------------------------------------------- */
     977           4 :     GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_ReadOnly);
     978             : 
     979           4 :     if (poDS)
     980           4 :         poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
     981             : 
     982           4 :     return poDS;
     983             : }
     984             : 
     985             : /************************************************************************/
     986             : /*                         GDALRegister_DTED()                          */
     987             : /************************************************************************/
     988             : 
     989        1511 : void GDALRegister_DTED()
     990             : 
     991             : {
     992        1511 :     if (GDALGetDriverByName("DTED") != nullptr)
     993         295 :         return;
     994             : 
     995        1216 :     GDALDriver *poDriver = new GDALDriver();
     996             : 
     997        1216 :     poDriver->SetDescription("DTED");
     998        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     999        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "DTED Elevation Raster");
    1000        1216 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "dt0 dt1 dt2");
    1001        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/dted.html");
    1002        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int16 UInt16");
    1003             : 
    1004        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1005             : 
    1006        1216 :     poDriver->pfnOpen = DTEDDataset::Open;
    1007        1216 :     poDriver->pfnIdentify = DTEDDataset::Identify;
    1008        1216 :     poDriver->pfnCreateCopy = DTEDCreateCopy;
    1009             : 
    1010        1216 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1011             : }

Generated by: LCOV version 1.14