LCOV - code coverage report
Current view: top level - frmts/dted - dteddataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 371 440 84.3 %
Date: 2026-06-19 21:24:00 Functions: 16 17 94.1 %

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

Generated by: LCOV version 1.14