LCOV - code coverage report
Current view: top level - frmts/dted - dted_api.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 362 480 75.4 %
Date: 2026-05-29 23:25:07 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DTED Translator
       4             :  * Purpose:  Implementation of DTED/CDED access functions.
       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             : 
      16             : #ifndef AVOID_CPL
      17             : #endif
      18             : 
      19             : static int bWarnedTwoComplement = FALSE;
      20             : 
      21             : static void DTEDDetectVariantWithMissingColumns(DTEDInfo *psDInfo);
      22             : 
      23          75 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      24             : {
      25          75 : }
      26             : 
      27         199 : CPL_INLINE static void CPL_IGNORE_RET_VAL_SIZET(CPL_UNUSED size_t unused)
      28             : {
      29         199 : }
      30             : 
      31             : #define DIGIT_ZERO '0'
      32             : 
      33             : /************************************************************************/
      34             : /*                            DTEDGetField()                            */
      35             : /*                                                                      */
      36             : /*      Extract a field as a zero terminated string.  Address is        */
      37             : /*      deliberately 1 based so the getfield arguments will be the      */
      38             : /*      same as the numbers in the file format specification.           */
      39             : /************************************************************************/
      40             : 
      41         630 : static char *DTEDGetField(char szResult[81], const char *pachRecord, int nStart,
      42             :                           int nSize)
      43             : 
      44             : {
      45         630 :     CPLAssert(nSize < 81);
      46         630 :     memcpy(szResult, pachRecord + nStart - 1, nSize);
      47         630 :     szResult[nSize] = '\0';
      48             : 
      49         630 :     return szResult;
      50             : }
      51             : 
      52             : /************************************************************************/
      53             : /*                         StripLeadingZeros()                          */
      54             : /*                                                                      */
      55             : /*      Return a pointer to the first non-zero character in BUF.        */
      56             : /*      BUF must be null terminated.                                    */
      57             : /*      If buff is all zeros, then it will point to the last non-zero   */
      58             : /************************************************************************/
      59             : 
      60         378 : static const char *stripLeadingZeros(const char *buf)
      61             : {
      62         378 :     const char *ptr = buf;
      63             : 
      64             :     /* Go until we run out of characters  or hit something non-zero */
      65             : 
      66         766 :     while (*ptr == DIGIT_ZERO && *(ptr + 1) != '\0')
      67             :     {
      68         388 :         ptr++;
      69             :     }
      70             : 
      71         378 :     return ptr;
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /*                              DTEDOpen()                              */
      76             : /************************************************************************/
      77             : 
      78          15 : DTEDInfo *DTEDOpen(const char *pszFilename, const char *pszAccess,
      79             :                    int bTestOpen)
      80             : 
      81             : {
      82             :     VSILFILE *fp;
      83             : 
      84             :     /* -------------------------------------------------------------------- */
      85             :     /*      Open the physical file.                                         */
      86             :     /* -------------------------------------------------------------------- */
      87          15 :     if (EQUAL(pszAccess, "r") || EQUAL(pszAccess, "rb"))
      88           0 :         pszAccess = "rb";
      89             :     else
      90          15 :         pszAccess = "r+b";
      91             : 
      92          15 :     fp = VSIFOpenL(pszFilename, pszAccess);
      93             : 
      94          15 :     if (fp == NULL)
      95             :     {
      96           0 :         if (!bTestOpen)
      97             :         {
      98             : #ifndef AVOID_CPL
      99           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     100             : #else
     101             :             fprintf(stderr,
     102             : #endif
     103             :                      "Failed to open file %s.", pszFilename);
     104             :         }
     105             : 
     106           0 :         return NULL;
     107             :     }
     108             : 
     109          15 :     return DTEDOpenEx(fp, pszFilename, pszAccess, bTestOpen);
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                             DTEDOpenEx()                             */
     114             : /************************************************************************/
     115             : 
     116          63 : DTEDInfo *DTEDOpenEx(VSILFILE *fp, const char *pszFilename,
     117             :                      const char *pszAccess, int bTestOpen)
     118             : 
     119             : {
     120             :     char achRecord[DTED_UHL_SIZE];
     121          63 :     DTEDInfo *psDInfo = NULL;
     122             :     double dfLLOriginX, dfLLOriginY;
     123          63 :     int deg = 0;
     124          63 :     int min = 0;
     125          63 :     int sec = 0;
     126          63 :     int bSwapLatLong = FALSE;
     127             :     char szResult[81];
     128             :     int bIsWeirdDTED;
     129             :     char chHemisphere;
     130             : 
     131             :     /* -------------------------------------------------------------------- */
     132             :     /*      Read, trying to find the UHL record.  Skip VOL or HDR           */
     133             :     /*      records if they are encountered.                                */
     134             :     /* -------------------------------------------------------------------- */
     135             :     do
     136             :     {
     137          64 :         if (VSIFReadL(achRecord, 1, DTED_UHL_SIZE, fp) != DTED_UHL_SIZE)
     138             :         {
     139           0 :             if (!bTestOpen)
     140             :             {
     141             : #ifndef AVOID_CPL
     142           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     143             : #else
     144             :                 fprintf(stderr,
     145             : #endif
     146             :                          "Unable to read header, %s is not DTED.", pszFilename);
     147             :             }
     148           0 :             CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     149           0 :             return NULL;
     150             :         }
     151             : 
     152         128 :     } while (STARTS_WITH_CI(achRecord, "VOL") ||
     153          64 :              STARTS_WITH_CI(achRecord, "HDR"));
     154             : 
     155          63 :     if (!STARTS_WITH_CI(achRecord, "UHL"))
     156             :     {
     157           0 :         if (!bTestOpen)
     158             :         {
     159             : #ifndef AVOID_CPL
     160           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     161             : #else
     162             :             fprintf(stderr,
     163             : #endif
     164             :                      "No UHL record.  %s is not a DTED file.", pszFilename);
     165             :         }
     166           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     167           0 :         return NULL;
     168             :     }
     169             : 
     170             :     /* -------------------------------------------------------------------- */
     171             :     /*      Create and initialize the DTEDInfo structure.                   */
     172             :     /* -------------------------------------------------------------------- */
     173          63 :     psDInfo = (DTEDInfo *)CPLCalloc(1, sizeof(DTEDInfo));
     174             : 
     175          63 :     psDInfo->fp = fp;
     176             : 
     177          63 :     psDInfo->bUpdate = EQUAL(pszAccess, "r+b");
     178          63 :     psDInfo->bRewriteHeaders = FALSE;
     179             : 
     180          63 :     psDInfo->nUHLOffset = (int)VSIFTellL(fp) - DTED_UHL_SIZE;
     181          63 :     psDInfo->pachUHLRecord = (char *)CPLMalloc(DTED_UHL_SIZE);
     182          63 :     memcpy(psDInfo->pachUHLRecord, achRecord, DTED_UHL_SIZE);
     183             : 
     184          63 :     psDInfo->nDSIOffset = (int)VSIFTellL(fp);
     185          63 :     psDInfo->pachDSIRecord = (char *)CPLMalloc(DTED_DSI_SIZE);
     186          63 :     CPL_IGNORE_RET_VAL_SIZET(
     187          63 :         VSIFReadL(psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, fp));
     188             : 
     189          63 :     psDInfo->nACCOffset = (int)VSIFTellL(fp);
     190          63 :     psDInfo->pachACCRecord = (char *)CPLMalloc(DTED_ACC_SIZE);
     191          63 :     CPL_IGNORE_RET_VAL_SIZET(
     192          63 :         VSIFReadL(psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, fp));
     193             : 
     194          63 :     if (!STARTS_WITH_CI(psDInfo->pachDSIRecord, "DSI") ||
     195          63 :         !STARTS_WITH_CI(psDInfo->pachACCRecord, "ACC"))
     196             :     {
     197             : #ifndef AVOID_CPL
     198           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     199             : #else
     200             :         fprintf(stderr,
     201             : #endif
     202             :                  "DSI or ACC record missing.  DTED access to\n%s failed.",
     203             :                  pszFilename);
     204             : 
     205           0 :         DTEDClose(psDInfo);
     206           0 :         return NULL;
     207             :     }
     208             : 
     209          63 :     psDInfo->nDataOffset = (int)VSIFTellL(fp);
     210             : 
     211             :     /* DTED3 file from http://www.falconview.org/trac/FalconView/downloads/20 */
     212             :     /* (co_elevation.zip) has really weird offsets that don't comply with the
     213             :      * 89020B specification */
     214          63 :     bIsWeirdDTED = achRecord[4] == ' ';
     215             : 
     216             :     /* -------------------------------------------------------------------- */
     217             :     /*      Parse out position information.  Note that we are extracting    */
     218             :     /*      the top left corner of the top left pixel area, not the         */
     219             :     /*      center of the area.                                             */
     220             :     /* -------------------------------------------------------------------- */
     221          63 :     if (!bIsWeirdDTED)
     222             :     {
     223          63 :         psDInfo->dfPixelSizeX =
     224          63 :             atoi(DTEDGetField(szResult, achRecord, 21, 4)) / 36000.0;
     225             : 
     226          63 :         psDInfo->dfPixelSizeY =
     227          63 :             atoi(DTEDGetField(szResult, achRecord, 25, 4)) / 36000.0;
     228             : 
     229          63 :         psDInfo->nXSize = atoi(DTEDGetField(szResult, achRecord, 48, 4));
     230          63 :         psDInfo->nYSize = atoi(DTEDGetField(szResult, achRecord, 52, 4));
     231             :     }
     232             :     else
     233             :     {
     234           0 :         psDInfo->dfPixelSizeX =
     235           0 :             atoi(DTEDGetField(szResult, achRecord, 41, 4)) / 36000.0;
     236             : 
     237           0 :         psDInfo->dfPixelSizeY =
     238           0 :             atoi(DTEDGetField(szResult, achRecord, 45, 4)) / 36000.0;
     239             : 
     240           0 :         psDInfo->nXSize =
     241           0 :             atoi(DTEDGetField(szResult, psDInfo->pachDSIRecord, 563, 4));
     242           0 :         psDInfo->nYSize =
     243           0 :             atoi(DTEDGetField(szResult, psDInfo->pachDSIRecord, 567, 4));
     244             :     }
     245             : 
     246          63 :     if (psDInfo->nXSize <= 0 || psDInfo->nYSize <= 0)
     247             :     {
     248             : #ifndef AVOID_CPL
     249           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     250             : #else
     251             :         fprintf(stderr,
     252             : #endif
     253             :                  "Invalid dimensions : %d x %d.  DTED access to\n%s failed.",
     254             :                  psDInfo->nXSize, psDInfo->nYSize, pszFilename);
     255             : 
     256           0 :         DTEDClose(psDInfo);
     257           0 :         return NULL;
     258             :     }
     259             : 
     260             :     /* create a scope so I don't need to declare these up top */
     261          63 :     if (!bIsWeirdDTED)
     262             :     {
     263          63 :         deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 5, 3)));
     264          63 :         min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 8, 2)));
     265          63 :         sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 10, 2)));
     266          63 :         chHemisphere = achRecord[11];
     267             :     }
     268             :     else
     269             :     {
     270           0 :         deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 9, 3)));
     271           0 :         min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 12, 2)));
     272           0 :         sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 14, 2)));
     273           0 :         chHemisphere = achRecord[15];
     274             :     }
     275             : 
     276             :     /* NOTE : The first version of MIL-D-89020 was buggy.
     277             :        The latitude and longitude of the LL corner of the UHF record was
     278             :        inverted. This was fixed in MIL-D-89020 Amendment 1, but some products
     279             :        may be affected. We detect this situation by looking at N/S in the
     280             :        longitude field and E/W in the latitude one.
     281             :     */
     282             : 
     283          63 :     dfLLOriginX = deg + min / 60.0 + sec / 3600.0;
     284          63 :     if (chHemisphere == 'W')
     285          51 :         dfLLOriginX *= -1;
     286          12 :     else if (chHemisphere == 'N')
     287           1 :         bSwapLatLong = TRUE;
     288          11 :     else if (chHemisphere == 'S')
     289             :     {
     290           0 :         dfLLOriginX *= -1;
     291           0 :         bSwapLatLong = TRUE;
     292             :     }
     293             : 
     294          63 :     if (!bIsWeirdDTED)
     295             :     {
     296          63 :         deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 13, 3)));
     297          63 :         min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 16, 2)));
     298          63 :         sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 18, 2)));
     299          63 :         chHemisphere = achRecord[19];
     300             :     }
     301             :     else
     302             :     {
     303           0 :         deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 25, 3)));
     304           0 :         min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 28, 2)));
     305           0 :         sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 30, 2)));
     306           0 :         chHemisphere = achRecord[31];
     307             :     }
     308             : 
     309          63 :     dfLLOriginY = deg + min / 60.0 + sec / 3600.0;
     310          63 :     if (chHemisphere == 'S' || (bSwapLatLong && chHemisphere == 'W'))
     311           1 :         dfLLOriginY *= -1;
     312             : 
     313          63 :     if (bSwapLatLong)
     314             :     {
     315           1 :         double dfTmp = dfLLOriginX;
     316           1 :         dfLLOriginX = dfLLOriginY;
     317           1 :         dfLLOriginY = dfTmp;
     318             :     }
     319             : 
     320          63 :     psDInfo->dfULCornerX = dfLLOriginX - 0.5 * psDInfo->dfPixelSizeX;
     321          63 :     psDInfo->dfULCornerY = dfLLOriginY - 0.5 * psDInfo->dfPixelSizeY +
     322          63 :                            psDInfo->nYSize * psDInfo->dfPixelSizeY;
     323             : 
     324          63 :     DTEDDetectVariantWithMissingColumns(psDInfo);
     325             : 
     326          63 :     psDInfo->bAssumeConformant =
     327          63 :         CPLTestBool(CPLGetConfigOption("DTED_ASSUME_CONFORMANT", "NO"));
     328             : 
     329          63 :     return psDInfo;
     330             : }
     331             : 
     332             : /************************************************************************/
     333             : /*                DTEDDetectVariantWithMissingColumns()                 */
     334             : /************************************************************************/
     335             : 
     336          63 : static void DTEDDetectVariantWithMissingColumns(DTEDInfo *psDInfo)
     337             : {
     338             :     /* -------------------------------------------------------------------- */
     339             :     /*      Some DTED files have only a subset of all possible columns.     */
     340             :     /*      They can declare for example 3601 columns, but in the file,     */
     341             :     /*      there are just columns 100->500. Detect that situation.         */
     342             :     /* -------------------------------------------------------------------- */
     343             : 
     344             :     GByte pabyRecordHeader[8];
     345             :     int nFirstDataBlockCount, nFirstLongitudeCount;
     346             :     int nLastDataBlockCount, nLastLongitudeCount;
     347             :     int nSize;
     348          63 :     int nColByteSize = 12 + psDInfo->nYSize * 2;
     349             : 
     350         126 :     if (VSIFSeekL(psDInfo->fp, psDInfo->nDataOffset, SEEK_SET) < 0 ||
     351          63 :         VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 ||
     352          61 :         pabyRecordHeader[0] != 0252)
     353             :     {
     354           2 :         CPLDebug("DTED", "Cannot find signature of first column");
     355          59 :         return;
     356             :     }
     357             : 
     358          61 :     nFirstDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3];
     359          61 :     nFirstLongitudeCount = (pabyRecordHeader[4] << 8) | pabyRecordHeader[5];
     360             : 
     361          61 :     CPL_IGNORE_RET_VAL_SIZET(VSIFSeekL(psDInfo->fp, 0, SEEK_END));
     362          61 :     nSize = (int)VSIFTellL(psDInfo->fp);
     363          61 :     if (nSize < 12 + psDInfo->nYSize * 2)
     364             :     {
     365           0 :         CPLDebug("DTED", "File too short");
     366           0 :         return;
     367             :     }
     368             : 
     369         122 :     if (VSIFSeekL(psDInfo->fp, nSize - nColByteSize, SEEK_SET) < 0 ||
     370          61 :         VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 ||
     371          61 :         pabyRecordHeader[0] != 0252)
     372             :     {
     373           0 :         CPLDebug("DTED", "Cannot find signature of last column");
     374           0 :         return;
     375             :     }
     376             : 
     377          61 :     nLastDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3];
     378          61 :     nLastLongitudeCount = (pabyRecordHeader[4] << 8) | pabyRecordHeader[5];
     379             : 
     380          61 :     if (nFirstDataBlockCount == 0 && nFirstLongitudeCount == 0 &&
     381          57 :         nLastDataBlockCount == psDInfo->nXSize - 1 &&
     382          57 :         nLastLongitudeCount == psDInfo->nXSize - 1 &&
     383          57 :         nSize - psDInfo->nDataOffset == psDInfo->nXSize * nColByteSize)
     384             :     {
     385             :         /* This is the most standard form of DTED. Return happily now. */
     386          57 :         return;
     387             :     }
     388             : 
     389             :     /* Well, we have an odd DTED file at that point */
     390             : 
     391           4 :     psDInfo->panMapLogicalColsToOffsets =
     392           4 :         (int *)CPLMalloc(psDInfo->nXSize * sizeof(int));
     393             : 
     394           4 :     if (nFirstDataBlockCount == 0 &&
     395           4 :         nLastLongitudeCount - nFirstLongitudeCount ==
     396           4 :             nLastDataBlockCount - nFirstDataBlockCount &&
     397           2 :         nSize - psDInfo->nDataOffset ==
     398           2 :             (nLastLongitudeCount - nFirstLongitudeCount + 1) * nColByteSize)
     399           2 :     {
     400             :         int i;
     401             : 
     402             :         /* Case seen in a real-world file */
     403             : 
     404           2 :         CPLDebug("DTED",
     405             :                  "The file only contains data from column %d to column %d.",
     406             :                  nFirstLongitudeCount, nLastLongitudeCount);
     407             : 
     408         244 :         for (i = 0; i < psDInfo->nXSize; i++)
     409             :         {
     410         242 :             if (i < nFirstLongitudeCount)
     411           4 :                 psDInfo->panMapLogicalColsToOffsets[i] = -1;
     412         238 :             else if (i <= nLastLongitudeCount)
     413           4 :                 psDInfo->panMapLogicalColsToOffsets[i] =
     414           4 :                     psDInfo->nDataOffset +
     415           4 :                     (i - nFirstLongitudeCount) * nColByteSize;
     416             :             else
     417         234 :                 psDInfo->panMapLogicalColsToOffsets[i] = -1;
     418             :         }
     419             :     }
     420             :     else
     421             :     {
     422           2 :         int nPhysicalCols = (nSize - psDInfo->nDataOffset) / nColByteSize;
     423             :         int i;
     424             : 
     425             :         /* Theoretical case for now... */
     426             : 
     427           2 :         CPLDebug("DTED", "There columns appear to be in non sequential order. "
     428             :                          "Scanning the whole file.");
     429             : 
     430         244 :         for (i = 0; i < psDInfo->nXSize; i++)
     431             :         {
     432         242 :             psDInfo->panMapLogicalColsToOffsets[i] = -1;
     433             :         }
     434             : 
     435           6 :         for (i = 0; i < nPhysicalCols; i++)
     436             :         {
     437             :             int nDataBlockCount;
     438             : 
     439           4 :             if (VSIFSeekL(psDInfo->fp, psDInfo->nDataOffset + i * nColByteSize,
     440           4 :                           SEEK_SET) < 0 ||
     441           4 :                 VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 ||
     442           4 :                 pabyRecordHeader[0] != 0252)
     443             :             {
     444           0 :                 CPLDebug("DTED", "Cannot find signature of physical column %d",
     445             :                          i);
     446           0 :                 return;
     447             :             }
     448             : 
     449           4 :             nDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3];
     450           4 :             if (nDataBlockCount != i)
     451             :             {
     452           0 :                 CPLDebug("DTED",
     453             :                          "Unexpected block count(%d) at physical column %d. "
     454             :                          "Ignoring that and going on...",
     455             :                          nDataBlockCount, i);
     456             :             }
     457             : 
     458           4 :             const int nLongitudeCount =
     459           4 :                 (pabyRecordHeader[4] << 8) | pabyRecordHeader[5];
     460           4 :             if (nLongitudeCount >= psDInfo->nXSize)
     461             :             {
     462           0 :                 CPLDebug("DTED",
     463             :                          "Invalid longitude count (%d) at physical column %d",
     464             :                          nLongitudeCount, i);
     465           0 :                 return;
     466             :             }
     467             : 
     468           4 :             psDInfo->panMapLogicalColsToOffsets[nLongitudeCount] =
     469           4 :                 psDInfo->nDataOffset + i * nColByteSize;
     470             :         }
     471             :     }
     472             : }
     473             : 
     474             : /************************************************************************/
     475             : /*                            DTEDReadPoint()                           */
     476             : /*                                                                      */
     477             : /*      Read one single sample. The coordinates are given from the      */
     478             : /*      top-left corner of the file (contrary to the internal           */
     479             : /*      organization or a DTED file)                                    */
     480             : /************************************************************************/
     481             : 
     482           0 : int DTEDReadPoint(DTEDInfo *psDInfo, int nXOff, int nYOff, GInt16 *panVal)
     483             : {
     484             :     int nOffset;
     485             :     GByte pabyData[2];
     486             : 
     487           0 :     if (nYOff < 0 || nXOff < 0 || nYOff >= psDInfo->nYSize ||
     488           0 :         nXOff >= psDInfo->nXSize)
     489             :     {
     490             : #ifndef AVOID_CPL
     491           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     492             : #else
     493             :         fprintf(stderr,
     494             : #endif
     495             :                  "Invalid raster coordinates (%d,%d) in DTED file.\n", nXOff,
     496             :                  nYOff);
     497           0 :         return FALSE;
     498             :     }
     499             : 
     500           0 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     501             :     {
     502           0 :         nOffset = psDInfo->panMapLogicalColsToOffsets[nXOff];
     503           0 :         if (nOffset < 0)
     504             :         {
     505           0 :             *panVal = DTED_NODATA_VALUE;
     506           0 :             return TRUE;
     507             :         }
     508             :     }
     509             :     else
     510           0 :         nOffset = psDInfo->nDataOffset + nXOff * (12 + psDInfo->nYSize * 2);
     511           0 :     nOffset += 8 + 2 * (psDInfo->nYSize - 1 - nYOff);
     512             : 
     513           0 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     514           0 :         VSIFReadL(pabyData, 2, 1, psDInfo->fp) != 1)
     515             :     {
     516             : #ifndef AVOID_CPL
     517           0 :         CPLError(CE_Failure, CPLE_FileIO,
     518             : #else
     519             :         fprintf(stderr,
     520             : #endif
     521             :                  "Failed to seek to, or read (%d,%d) at offset %d\n"
     522             :                  "in DTED file.\n",
     523             :                  nXOff, nYOff, nOffset);
     524           0 :         return FALSE;
     525             :     }
     526             : 
     527           0 :     *panVal = ((pabyData[0] & 0x7f) << 8) | pabyData[1];
     528             : 
     529           0 :     if (pabyData[0] & 0x80)
     530             :     {
     531           0 :         *panVal *= -1;
     532             : 
     533             :         /*
     534             :         ** It seems that some files are improperly generated in twos
     535             :         ** complement form for negatives.  For these, redo the job
     536             :         ** in twos complement.  eg. w_069_s50.dt0
     537             :         */
     538           0 :         if (!psDInfo->bAssumeConformant && (*panVal < -16000) &&
     539           0 :             (*panVal != DTED_NODATA_VALUE))
     540             :         {
     541           0 :             *panVal = (pabyData[0] << 8) | pabyData[1];
     542             : 
     543           0 :             if (!bWarnedTwoComplement)
     544             :             {
     545           0 :                 bWarnedTwoComplement = TRUE;
     546             : #ifndef AVOID_CPL
     547           0 :                 CPLError(
     548             :                     CE_Warning, CPLE_AppDefined,
     549             : #else
     550             :                 fprintf(
     551             :                     stderr,
     552             : #endif
     553             :                     "The DTED driver found values less than -16000, and has "
     554             :                     "adjusted\n"
     555             :                     "them assuming they are improperly two-complemented.  If "
     556             :                     "you wish to\n"
     557             :                     "disable this behavior, set the DTED_ASSUME_CONFORMANT "
     558             :                     "configuration\n"
     559             :                     "option to YES. No more warnings will be issued in this "
     560             :                     "session\n"
     561             :                     "about this operation.");
     562             :             }
     563             :         }
     564             :     }
     565             : 
     566           0 :     return TRUE;
     567             : }
     568             : 
     569             : /************************************************************************/
     570             : /*                          DTEDReadProfile()                           */
     571             : /*                                                                      */
     572             : /*      Read one profile line.  These are organized in bottom to top    */
     573             : /*      order starting from the leftmost column (0).                    */
     574             : /************************************************************************/
     575             : 
     576           0 : int DTEDReadProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData)
     577             : {
     578           0 :     return DTEDReadProfileEx(psDInfo, nColumnOffset, panData, FALSE);
     579             : }
     580             : 
     581        3758 : int DTEDReadProfileEx(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData,
     582             :                       int bVerifyChecksum)
     583             : {
     584             :     int nOffset;
     585             :     int i;
     586             :     GByte *pabyRecord;
     587             :     int nLongitudeCount;
     588             : 
     589             :     /* -------------------------------------------------------------------- */
     590             :     /*      Read data record from disk.                                     */
     591             :     /* -------------------------------------------------------------------- */
     592        3758 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     593             :     {
     594         242 :         nOffset = psDInfo->panMapLogicalColsToOffsets[nColumnOffset];
     595         242 :         if (nOffset < 0)
     596             :         {
     597       29036 :             for (i = 0; i < psDInfo->nYSize; i++)
     598             :             {
     599       28798 :                 panData[i] = DTED_NODATA_VALUE;
     600             :             }
     601         238 :             return TRUE;
     602             :         }
     603             :     }
     604             :     else
     605        3516 :         nOffset =
     606        3516 :             psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2);
     607             : 
     608        3520 :     pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2);
     609             : 
     610        7040 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     611        3520 :         VSIFReadL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1)
     612             :     {
     613             : #ifndef AVOID_CPL
     614           0 :         CPLError(CE_Failure, CPLE_FileIO,
     615             : #else
     616             :         fprintf(stderr,
     617             : #endif
     618             :                  "Failed to seek to, or read profile %d at offset %d\n"
     619             :                  "in DTED file.\n",
     620             :                  nColumnOffset, nOffset);
     621           0 :         CPLFree(pabyRecord);
     622           0 :         return FALSE;
     623             :     }
     624             : 
     625        3520 :     nLongitudeCount = (pabyRecord[4] << 8) | pabyRecord[5];
     626        3520 :     if (nLongitudeCount != nColumnOffset)
     627             :     {
     628             : #ifndef AVOID_CPL
     629           0 :         CPLError(
     630             :             CE_Warning, CPLE_AppDefined,
     631             : #else
     632             :         fprintf(
     633             :             stderr,
     634             : #endif
     635             :             "Longitude count (%d) of column %d doesn't match expected value.\n",
     636             :             nLongitudeCount, nColumnOffset);
     637             :     }
     638             : 
     639             :     /* -------------------------------------------------------------------- */
     640             :     /*      Translate data values from "signed magnitude" to standard       */
     641             :     /*      binary.                                                         */
     642             :     /* -------------------------------------------------------------------- */
     643     1078520 :     for (i = 0; i < psDInfo->nYSize; i++)
     644             :     {
     645     1075000 :         panData[i] =
     646     1075000 :             ((pabyRecord[8 + i * 2] & 0x7f) << 8) | pabyRecord[8 + i * 2 + 1];
     647             : 
     648     1075000 :         if (pabyRecord[8 + i * 2] & 0x80)
     649             :         {
     650           0 :             panData[i] *= -1;
     651             : 
     652             :             /*
     653             :             ** It seems that some files are improperly generated in twos
     654             :             ** complement form for negatives.  For these, redo the job
     655             :             ** in twos complement.  eg. w_069_s50.dt0
     656             :             */
     657           0 :             if ((panData[i] < -16000) && (panData[i] != DTED_NODATA_VALUE))
     658             :             {
     659           0 :                 panData[i] =
     660           0 :                     (pabyRecord[8 + i * 2] << 8) | pabyRecord[8 + i * 2 + 1];
     661             : 
     662           0 :                 if (!bWarnedTwoComplement)
     663             :                 {
     664           0 :                     bWarnedTwoComplement = TRUE;
     665             : #ifndef AVOID_CPL
     666           0 :                     CPLError(
     667             :                         CE_Warning, CPLE_AppDefined,
     668             : #else
     669             :                     fprintf(
     670             :                         stderr,
     671             : #endif
     672             :                         "The DTED driver found values less than -16000, and "
     673             :                         "has adjusted\n"
     674             :                         "them assuming they are improperly two-complemented.  "
     675             :                         "No more warnings\n"
     676             :                         "will be issued in this session about this operation.");
     677             :                 }
     678             :             }
     679             :         }
     680             :     }
     681             : 
     682        3520 :     if (bVerifyChecksum)
     683             :     {
     684           1 :         unsigned int nCheckSum = 0;
     685             :         unsigned int fileCheckSum;
     686             : 
     687             :         /* --------------------------------------------------------------------
     688             :          */
     689             :         /*      Verify the checksum. */
     690             :         /* --------------------------------------------------------------------
     691             :          */
     692             : 
     693         251 :         for (i = 0; i < psDInfo->nYSize * 2 + 8; i++)
     694         250 :             nCheckSum += pabyRecord[i];
     695             : 
     696           1 :         fileCheckSum = (pabyRecord[8 + psDInfo->nYSize * 2 + 0] << 24) |
     697           1 :                        (pabyRecord[8 + psDInfo->nYSize * 2 + 1] << 16) |
     698           1 :                        (pabyRecord[8 + psDInfo->nYSize * 2 + 2] << 8) |
     699           1 :                        pabyRecord[8 + psDInfo->nYSize * 2 + 3];
     700             : 
     701           1 :         if (fileCheckSum > 0xff * (8 + (unsigned int)psDInfo->nYSize * 2))
     702             :         {
     703             :             static int bWarned = FALSE;
     704           0 :             if (!bWarned)
     705             :             {
     706           0 :                 bWarned = TRUE;
     707             : #ifndef AVOID_CPL
     708           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     709             : #else
     710             :                 fprintf(stderr,
     711             : #endif
     712             :                          "The DTED driver has read from the file a checksum "
     713             :                          "with an impossible value (0x%X) at column %d.\n"
     714             :                          "Check with your file producer.\n"
     715             :                          "No more warnings will be issued in this session "
     716             :                          "about this operation.",
     717             :                          fileCheckSum, nColumnOffset);
     718             :             }
     719             :         }
     720           1 :         else if (fileCheckSum != nCheckSum)
     721             :         {
     722             : #ifndef AVOID_CPL
     723           1 :             CPLError(
     724             :                 CE_Failure, CPLE_AppDefined,
     725             : #else
     726             :             fprintf(
     727             :                 stderr,
     728             : #endif
     729             :                 "The DTED driver has found a computed and read checksum "
     730             :                 "that do not match at column %d. Computed 0x%X, read 0x%X\n",
     731             :                 nColumnOffset, nCheckSum, fileCheckSum);
     732           1 :             CPLFree(pabyRecord);
     733           1 :             return FALSE;
     734             :         }
     735             :     }
     736             : 
     737        3519 :     CPLFree(pabyRecord);
     738             : 
     739        3519 :     return TRUE;
     740             : }
     741             : 
     742             : /************************************************************************/
     743             : /*                          DTEDWriteProfile()                          */
     744             : /************************************************************************/
     745             : 
     746         964 : int DTEDWriteProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData)
     747             : 
     748             : {
     749             :     int nOffset;
     750         964 :     int i, nCheckSum = 0;
     751             :     GByte *pabyRecord;
     752             : 
     753         964 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     754             :     {
     755             : #ifndef AVOID_CPL
     756           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     757             : #else
     758             :         fprintf(stderr,
     759             : #endif
     760             :                  "Write to partial file not supported.\n");
     761           0 :         return FALSE;
     762             :     }
     763             : 
     764             :     /* -------------------------------------------------------------------- */
     765             :     /*      Format the data record.                                         */
     766             :     /* -------------------------------------------------------------------- */
     767         964 :     pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2);
     768             : 
     769      766688 :     for (i = 0; i < psDInfo->nYSize; i++)
     770             :     {
     771      765724 :         int nABSVal = CPL_ABS(panData[psDInfo->nYSize - i - 1]);
     772      765724 :         pabyRecord[8 + i * 2] = (GByte)((nABSVal >> 8) & 0x7f);
     773      765724 :         pabyRecord[8 + i * 2 + 1] = (GByte)(nABSVal & 0xff);
     774             : 
     775      765724 :         if (panData[psDInfo->nYSize - i - 1] < 0)
     776           0 :             pabyRecord[8 + i * 2] |= 0x80;
     777             :     }
     778             : 
     779         964 :     pabyRecord[0] = 0xaa;
     780         964 :     pabyRecord[1] = 0;
     781         964 :     pabyRecord[2] = (GByte)(nColumnOffset / 256);
     782         964 :     pabyRecord[3] = (GByte)(nColumnOffset % 256);
     783         964 :     pabyRecord[4] = (GByte)(nColumnOffset / 256);
     784         964 :     pabyRecord[5] = (GByte)(nColumnOffset % 256);
     785         964 :     pabyRecord[6] = 0;
     786         964 :     pabyRecord[7] = 0;
     787             : 
     788             :     /* -------------------------------------------------------------------- */
     789             :     /*      Compute the checksum.                                           */
     790             :     /* -------------------------------------------------------------------- */
     791     1540120 :     for (i = 0; i < psDInfo->nYSize * 2 + 8; i++)
     792     1539160 :         nCheckSum += pabyRecord[i];
     793             : 
     794         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 0] = (GByte)((nCheckSum >> 24) & 0xff);
     795         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 1] = (GByte)((nCheckSum >> 16) & 0xff);
     796         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 2] = (GByte)((nCheckSum >> 8) & 0xff);
     797         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 3] = (GByte)(nCheckSum & 0xff);
     798             : 
     799             :     /* -------------------------------------------------------------------- */
     800             :     /*      Write the record.                                               */
     801             :     /* -------------------------------------------------------------------- */
     802         964 :     nOffset = psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2);
     803             : 
     804        1928 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     805         964 :         VSIFWriteL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1)
     806             :     {
     807             : #ifndef AVOID_CPL
     808           0 :         CPLError(CE_Failure, CPLE_FileIO,
     809             : #else
     810             :         fprintf(stderr,
     811             : #endif
     812             :                  "Failed to seek to, or write profile %d at offset %d\n"
     813             :                  "in DTED file.\n",
     814             :                  nColumnOffset, nOffset);
     815           0 :         CPLFree(pabyRecord);
     816           0 :         return FALSE;
     817             :     }
     818             : 
     819         964 :     CPLFree(pabyRecord);
     820             : 
     821         964 :     return TRUE;
     822             : }
     823             : 
     824             : /************************************************************************/
     825             : /*                      DTEDGetMetadataLocation()                       */
     826             : /************************************************************************/
     827             : 
     828        1261 : static void DTEDGetMetadataLocation(DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
     829             :                                     char **ppszLocation, int *pnLength)
     830             : {
     831        1261 :     int bIsWeirdDTED = psDInfo->pachUHLRecord[4] == ' ';
     832             : 
     833        1261 :     switch (eCode)
     834             :     {
     835          48 :         case DTEDMD_ORIGINLONG:
     836          48 :             if (bIsWeirdDTED)
     837           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 8;
     838             :             else
     839          48 :                 *ppszLocation = psDInfo->pachUHLRecord + 4;
     840          48 :             *pnLength = 8;
     841          48 :             break;
     842             : 
     843          48 :         case DTEDMD_ORIGINLAT:
     844          48 :             if (bIsWeirdDTED)
     845           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 24;
     846             :             else
     847          48 :                 *ppszLocation = psDInfo->pachUHLRecord + 12;
     848          48 :             *pnLength = 8;
     849          48 :             break;
     850             : 
     851          51 :         case DTEDMD_VERTACCURACY_UHL:
     852          51 :             if (bIsWeirdDTED)
     853           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 56;
     854             :             else
     855          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 28;
     856          51 :             *pnLength = 4;
     857          51 :             break;
     858             : 
     859          51 :         case DTEDMD_SECURITYCODE_UHL:
     860          51 :             if (bIsWeirdDTED)
     861           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 60;
     862             :             else
     863          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 32;
     864          51 :             *pnLength = 3;
     865          51 :             break;
     866             : 
     867          51 :         case DTEDMD_UNIQUEREF_UHL:
     868          51 :             if (bIsWeirdDTED)
     869           0 :                 *ppszLocation = NULL;
     870             :             else
     871          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 35;
     872          51 :             *pnLength = 12;
     873          51 :             break;
     874             : 
     875          51 :         case DTEDMD_DATA_EDITION:
     876          51 :             if (bIsWeirdDTED)
     877           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 174;
     878             :             else
     879          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 87;
     880          51 :             *pnLength = 2;
     881          51 :             break;
     882             : 
     883          51 :         case DTEDMD_MATCHMERGE_VERSION:
     884          51 :             if (bIsWeirdDTED)
     885           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 176;
     886             :             else
     887          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 89;
     888          51 :             *pnLength = 1;
     889          51 :             break;
     890             : 
     891          51 :         case DTEDMD_MAINT_DATE:
     892          51 :             if (bIsWeirdDTED)
     893           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 177;
     894             :             else
     895          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 90;
     896          51 :             *pnLength = 4;
     897          51 :             break;
     898             : 
     899          51 :         case DTEDMD_MATCHMERGE_DATE:
     900          51 :             if (bIsWeirdDTED)
     901           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 181;
     902             :             else
     903          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 94;
     904          51 :             *pnLength = 4;
     905          51 :             break;
     906             : 
     907          51 :         case DTEDMD_MAINT_DESCRIPTION:
     908          51 :             if (bIsWeirdDTED)
     909           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 185;
     910             :             else
     911          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 98;
     912          51 :             *pnLength = 4;
     913          51 :             break;
     914             : 
     915          51 :         case DTEDMD_PRODUCER:
     916          51 :             if (bIsWeirdDTED)
     917           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 189;
     918             :             else
     919          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 102;
     920          51 :             *pnLength = 8;
     921          51 :             break;
     922             : 
     923          51 :         case DTEDMD_VERTDATUM:
     924          51 :             if (bIsWeirdDTED)
     925           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 267;
     926             :             else
     927          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 141;
     928          51 :             *pnLength = 3;
     929          51 :             break;
     930             : 
     931          51 :         case DTEDMD_HORIZDATUM:
     932          51 :             if (bIsWeirdDTED)
     933           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 270;
     934             :             else
     935          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 144;
     936          51 :             *pnLength = 5;
     937          51 :             break;
     938             : 
     939          51 :         case DTEDMD_DIGITIZING_SYS:
     940          51 :             if (bIsWeirdDTED)
     941           0 :                 *ppszLocation = NULL;
     942             :             else
     943          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 149;
     944          51 :             *pnLength = 10;
     945          51 :             break;
     946             : 
     947          51 :         case DTEDMD_COMPILATION_DATE:
     948          51 :             if (bIsWeirdDTED)
     949           0 :                 *ppszLocation = NULL;
     950             :             else
     951          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 159;
     952          51 :             *pnLength = 4;
     953          51 :             break;
     954             : 
     955          51 :         case DTEDMD_HORIZACCURACY:
     956          51 :             *ppszLocation = psDInfo->pachACCRecord + 3;
     957          51 :             *pnLength = 4;
     958          51 :             break;
     959             : 
     960          51 :         case DTEDMD_REL_HORIZACCURACY:
     961          51 :             *ppszLocation = psDInfo->pachACCRecord + 11;
     962          51 :             *pnLength = 4;
     963          51 :             break;
     964             : 
     965          51 :         case DTEDMD_REL_VERTACCURACY:
     966          51 :             *ppszLocation = psDInfo->pachACCRecord + 15;
     967          51 :             *pnLength = 4;
     968          51 :             break;
     969             : 
     970          51 :         case DTEDMD_VERTACCURACY_ACC:
     971          51 :             *ppszLocation = psDInfo->pachACCRecord + 7;
     972          51 :             *pnLength = 4;
     973          51 :             break;
     974             : 
     975          51 :         case DTEDMD_SECURITYCODE_DSI:
     976          51 :             *ppszLocation = psDInfo->pachDSIRecord + 3;
     977          51 :             *pnLength = 1;
     978          51 :             break;
     979             : 
     980          51 :         case DTEDMD_UNIQUEREF_DSI:
     981          51 :             if (bIsWeirdDTED)
     982           0 :                 *ppszLocation = NULL;
     983             :             else
     984          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 64;
     985          51 :             *pnLength = 15;
     986          51 :             break;
     987             : 
     988          48 :         case DTEDMD_NIMA_DESIGNATOR:
     989          48 :             if (bIsWeirdDTED)
     990           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 118;
     991             :             else
     992          48 :                 *ppszLocation = psDInfo->pachDSIRecord + 59;
     993          48 :             *pnLength = 5;
     994          48 :             break;
     995             : 
     996          52 :         case DTEDMD_PARTIALCELL_DSI:
     997          52 :             if (bIsWeirdDTED)
     998           0 :                 *ppszLocation = NULL;
     999             :             else
    1000          52 :                 *ppszLocation = psDInfo->pachDSIRecord + 289;
    1001          52 :             *pnLength = 2;
    1002          52 :             break;
    1003             : 
    1004          48 :         case DTEDMD_SECURITYCONTROL:
    1005          48 :             *ppszLocation = psDInfo->pachDSIRecord + 4;
    1006          48 :             *pnLength = 2;
    1007          48 :             break;
    1008             : 
    1009          48 :         case DTEDMD_SECURITYHANDLING:
    1010          48 :             *ppszLocation = psDInfo->pachDSIRecord + 6;
    1011          48 :             *pnLength = 27;
    1012          48 :             break;
    1013             : 
    1014           0 :         default:
    1015           0 :             *ppszLocation = NULL;
    1016           0 :             *pnLength = 0;
    1017             :     }
    1018        1261 : }
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                          DTEDGetMetadata()                           */
    1022             : /************************************************************************/
    1023             : 
    1024        1200 : char *DTEDGetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode)
    1025             : 
    1026             : {
    1027             :     int nFieldLen;
    1028             :     char *pszFieldSrc;
    1029             :     char *pszResult;
    1030             : 
    1031        1200 :     DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen);
    1032        1200 :     if (pszFieldSrc == NULL)
    1033           0 :         return CPLStrdup("");
    1034             : 
    1035        1200 :     pszResult = (char *)CPLMalloc(nFieldLen + 1);
    1036        1200 :     strncpy(pszResult, pszFieldSrc, nFieldLen);
    1037        1200 :     pszResult[nFieldLen] = '\0';
    1038             : 
    1039        1200 :     return pszResult;
    1040             : }
    1041             : 
    1042             : /************************************************************************/
    1043             : /*                          DTEDSetMetadata()                           */
    1044             : /************************************************************************/
    1045             : 
    1046          61 : int DTEDSetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
    1047             :                     const char *pszNewValue)
    1048             : 
    1049             : {
    1050             :     int nFieldLen;
    1051             :     char *pszFieldSrc;
    1052             :     size_t nLenToCopy;
    1053             : 
    1054          61 :     if (!psDInfo->bUpdate)
    1055           0 :         return FALSE;
    1056             : 
    1057             :     /* -------------------------------------------------------------------- */
    1058             :     /*      Get the location in the headers to update.                      */
    1059             :     /* -------------------------------------------------------------------- */
    1060          61 :     DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen);
    1061          61 :     if (pszFieldSrc == NULL)
    1062           0 :         return FALSE;
    1063             : 
    1064             :     /* -------------------------------------------------------------------- */
    1065             :     /*      Update it, padding with spaces.                                 */
    1066             :     /* -------------------------------------------------------------------- */
    1067          61 :     nLenToCopy = CPL_MIN((size_t)nFieldLen, strlen(pszNewValue));
    1068          61 :     memcpy(pszFieldSrc, pszNewValue, nLenToCopy);
    1069          61 :     if (nLenToCopy < (size_t)nFieldLen)
    1070           0 :         memset(pszFieldSrc + nLenToCopy, ' ', nFieldLen - nLenToCopy);
    1071             : 
    1072             :     /* Turn the flag on, so that the headers are rewritten at file */
    1073             :     /* closing */
    1074          61 :     psDInfo->bRewriteHeaders = TRUE;
    1075             : 
    1076          61 :     return TRUE;
    1077             : }
    1078             : 
    1079             : /************************************************************************/
    1080             : /*                             DTEDClose()                              */
    1081             : /************************************************************************/
    1082             : 
    1083          63 : void DTEDClose(DTEDInfo *psDInfo)
    1084             : 
    1085             : {
    1086          63 :     if (psDInfo->bRewriteHeaders)
    1087             :     {
    1088             :         /* --------------------------------------------------------------------
    1089             :          */
    1090             :         /*      Write all headers back to disk. */
    1091             :         /* --------------------------------------------------------------------
    1092             :          */
    1093           4 :         CPL_IGNORE_RET_VAL_INT(
    1094           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nUHLOffset, SEEK_SET));
    1095           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1096           4 :             VSIFWriteL(psDInfo->pachUHLRecord, 1, DTED_UHL_SIZE, psDInfo->fp));
    1097             : 
    1098           4 :         CPL_IGNORE_RET_VAL_INT(
    1099           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nDSIOffset, SEEK_SET));
    1100           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1101           4 :             VSIFWriteL(psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, psDInfo->fp));
    1102             : 
    1103           4 :         CPL_IGNORE_RET_VAL_INT(
    1104           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nACCOffset, SEEK_SET));
    1105           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1106           4 :             VSIFWriteL(psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, psDInfo->fp));
    1107             :     }
    1108             : 
    1109          63 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(psDInfo->fp));
    1110             : 
    1111          63 :     CPLFree(psDInfo->pachUHLRecord);
    1112          63 :     CPLFree(psDInfo->pachDSIRecord);
    1113          63 :     CPLFree(psDInfo->pachACCRecord);
    1114             : 
    1115          63 :     CPLFree(psDInfo->panMapLogicalColsToOffsets);
    1116             : 
    1117          63 :     CPLFree(psDInfo);
    1118          63 : }

Generated by: LCOV version 1.14