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

Generated by: LCOV version 1.14