LCOV - code coverage report
Current view: top level - frmts/dted - dted_api.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 361 479 75.4 %
Date: 2025-05-31 00:00:17 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, nLongitudeCount;
     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 :             nLongitudeCount = (pabyRecordHeader[4] << 8) | pabyRecordHeader[5];
     459           4 :             if (nLongitudeCount < 0 || nLongitudeCount >= psDInfo->nXSize)
     460             :             {
     461           0 :                 CPLDebug("DTED",
     462             :                          "Invalid longitude count (%d) at physical column %d",
     463             :                          nLongitudeCount, i);
     464           0 :                 return;
     465             :             }
     466             : 
     467           4 :             psDInfo->panMapLogicalColsToOffsets[nLongitudeCount] =
     468           4 :                 psDInfo->nDataOffset + i * nColByteSize;
     469             :         }
     470             :     }
     471             : }
     472             : 
     473             : /************************************************************************/
     474             : /*                            DTEDReadPoint()                           */
     475             : /*                                                                      */
     476             : /*      Read one single sample. The coordinates are given from the      */
     477             : /*      top-left corner of the file (contrary to the internal           */
     478             : /*      organization or a DTED file)                                    */
     479             : /************************************************************************/
     480             : 
     481           0 : int DTEDReadPoint(DTEDInfo *psDInfo, int nXOff, int nYOff, GInt16 *panVal)
     482             : {
     483             :     int nOffset;
     484             :     GByte pabyData[2];
     485             : 
     486           0 :     if (nYOff < 0 || nXOff < 0 || nYOff >= psDInfo->nYSize ||
     487           0 :         nXOff >= psDInfo->nXSize)
     488             :     {
     489             : #ifndef AVOID_CPL
     490           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     491             : #else
     492             :         fprintf(stderr,
     493             : #endif
     494             :                  "Invalid raster coordinates (%d,%d) in DTED file.\n", nXOff,
     495             :                  nYOff);
     496           0 :         return FALSE;
     497             :     }
     498             : 
     499           0 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     500             :     {
     501           0 :         nOffset = psDInfo->panMapLogicalColsToOffsets[nXOff];
     502           0 :         if (nOffset < 0)
     503             :         {
     504           0 :             *panVal = DTED_NODATA_VALUE;
     505           0 :             return TRUE;
     506             :         }
     507             :     }
     508             :     else
     509           0 :         nOffset = psDInfo->nDataOffset + nXOff * (12 + psDInfo->nYSize * 2);
     510           0 :     nOffset += 8 + 2 * (psDInfo->nYSize - 1 - nYOff);
     511             : 
     512           0 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     513           0 :         VSIFReadL(pabyData, 2, 1, psDInfo->fp) != 1)
     514             :     {
     515             : #ifndef AVOID_CPL
     516           0 :         CPLError(CE_Failure, CPLE_FileIO,
     517             : #else
     518             :         fprintf(stderr,
     519             : #endif
     520             :                  "Failed to seek to, or read (%d,%d) at offset %d\n"
     521             :                  "in DTED file.\n",
     522             :                  nXOff, nYOff, nOffset);
     523           0 :         return FALSE;
     524             :     }
     525             : 
     526           0 :     *panVal = ((pabyData[0] & 0x7f) << 8) | pabyData[1];
     527             : 
     528           0 :     if (pabyData[0] & 0x80)
     529             :     {
     530           0 :         *panVal *= -1;
     531             : 
     532             :         /*
     533             :         ** It seems that some files are improperly generated in twos
     534             :         ** complement form for negatives.  For these, redo the job
     535             :         ** in twos complement.  eg. w_069_s50.dt0
     536             :         */
     537           0 :         if (!psDInfo->bAssumeConformant && (*panVal < -16000) &&
     538           0 :             (*panVal != DTED_NODATA_VALUE))
     539             :         {
     540           0 :             *panVal = (pabyData[0] << 8) | pabyData[1];
     541             : 
     542           0 :             if (!bWarnedTwoComplement)
     543             :             {
     544           0 :                 bWarnedTwoComplement = TRUE;
     545             : #ifndef AVOID_CPL
     546           0 :                 CPLError(
     547             :                     CE_Warning, CPLE_AppDefined,
     548             : #else
     549             :                 fprintf(
     550             :                     stderr,
     551             : #endif
     552             :                     "The DTED driver found values less than -16000, and has "
     553             :                     "adjusted\n"
     554             :                     "them assuming they are improperly two-complemented.  If "
     555             :                     "you wish to\n"
     556             :                     "disable this behavior, set the DTED_ASSUME_CONFORMANT "
     557             :                     "configuration\n"
     558             :                     "option to YES. No more warnings will be issued in this "
     559             :                     "session\n"
     560             :                     "about this operation.");
     561             :             }
     562             :         }
     563             :     }
     564             : 
     565           0 :     return TRUE;
     566             : }
     567             : 
     568             : /************************************************************************/
     569             : /*                          DTEDReadProfile()                           */
     570             : /*                                                                      */
     571             : /*      Read one profile line.  These are organized in bottom to top    */
     572             : /*      order starting from the leftmost column (0).                    */
     573             : /************************************************************************/
     574             : 
     575           0 : int DTEDReadProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData)
     576             : {
     577           0 :     return DTEDReadProfileEx(psDInfo, nColumnOffset, panData, FALSE);
     578             : }
     579             : 
     580        3758 : int DTEDReadProfileEx(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData,
     581             :                       int bVerifyChecksum)
     582             : {
     583             :     int nOffset;
     584             :     int i;
     585             :     GByte *pabyRecord;
     586             :     int nLongitudeCount;
     587             : 
     588             :     /* -------------------------------------------------------------------- */
     589             :     /*      Read data record from disk.                                     */
     590             :     /* -------------------------------------------------------------------- */
     591        3758 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     592             :     {
     593         242 :         nOffset = psDInfo->panMapLogicalColsToOffsets[nColumnOffset];
     594         242 :         if (nOffset < 0)
     595             :         {
     596       29036 :             for (i = 0; i < psDInfo->nYSize; i++)
     597             :             {
     598       28798 :                 panData[i] = DTED_NODATA_VALUE;
     599             :             }
     600         238 :             return TRUE;
     601             :         }
     602             :     }
     603             :     else
     604        3516 :         nOffset =
     605        3516 :             psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2);
     606             : 
     607        3520 :     pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2);
     608             : 
     609        7040 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     610        3520 :         VSIFReadL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1)
     611             :     {
     612             : #ifndef AVOID_CPL
     613           0 :         CPLError(CE_Failure, CPLE_FileIO,
     614             : #else
     615             :         fprintf(stderr,
     616             : #endif
     617             :                  "Failed to seek to, or read profile %d at offset %d\n"
     618             :                  "in DTED file.\n",
     619             :                  nColumnOffset, nOffset);
     620           0 :         CPLFree(pabyRecord);
     621           0 :         return FALSE;
     622             :     }
     623             : 
     624        3520 :     nLongitudeCount = (pabyRecord[4] << 8) | pabyRecord[5];
     625        3520 :     if (nLongitudeCount != nColumnOffset)
     626             :     {
     627             : #ifndef AVOID_CPL
     628           0 :         CPLError(
     629             :             CE_Warning, CPLE_AppDefined,
     630             : #else
     631             :         fprintf(
     632             :             stderr,
     633             : #endif
     634             :             "Longitude count (%d) of column %d doesn't match expected value.\n",
     635             :             nLongitudeCount, nColumnOffset);
     636             :     }
     637             : 
     638             :     /* -------------------------------------------------------------------- */
     639             :     /*      Translate data values from "signed magnitude" to standard       */
     640             :     /*      binary.                                                         */
     641             :     /* -------------------------------------------------------------------- */
     642     1078520 :     for (i = 0; i < psDInfo->nYSize; i++)
     643             :     {
     644     1075000 :         panData[i] =
     645     1075000 :             ((pabyRecord[8 + i * 2] & 0x7f) << 8) | pabyRecord[8 + i * 2 + 1];
     646             : 
     647     1075000 :         if (pabyRecord[8 + i * 2] & 0x80)
     648             :         {
     649           0 :             panData[i] *= -1;
     650             : 
     651             :             /*
     652             :             ** It seems that some files are improperly generated in twos
     653             :             ** complement form for negatives.  For these, redo the job
     654             :             ** in twos complement.  eg. w_069_s50.dt0
     655             :             */
     656           0 :             if ((panData[i] < -16000) && (panData[i] != DTED_NODATA_VALUE))
     657             :             {
     658           0 :                 panData[i] =
     659           0 :                     (pabyRecord[8 + i * 2] << 8) | pabyRecord[8 + i * 2 + 1];
     660             : 
     661           0 :                 if (!bWarnedTwoComplement)
     662             :                 {
     663           0 :                     bWarnedTwoComplement = TRUE;
     664             : #ifndef AVOID_CPL
     665           0 :                     CPLError(
     666             :                         CE_Warning, CPLE_AppDefined,
     667             : #else
     668             :                     fprintf(
     669             :                         stderr,
     670             : #endif
     671             :                         "The DTED driver found values less than -16000, and "
     672             :                         "has adjusted\n"
     673             :                         "them assuming they are improperly two-complemented.  "
     674             :                         "No more warnings\n"
     675             :                         "will be issued in this session about this operation.");
     676             :                 }
     677             :             }
     678             :         }
     679             :     }
     680             : 
     681        3520 :     if (bVerifyChecksum)
     682             :     {
     683           1 :         unsigned int nCheckSum = 0;
     684             :         unsigned int fileCheckSum;
     685             : 
     686             :         /* --------------------------------------------------------------------
     687             :          */
     688             :         /*      Verify the checksum. */
     689             :         /* --------------------------------------------------------------------
     690             :          */
     691             : 
     692         251 :         for (i = 0; i < psDInfo->nYSize * 2 + 8; i++)
     693         250 :             nCheckSum += pabyRecord[i];
     694             : 
     695           1 :         fileCheckSum = (pabyRecord[8 + psDInfo->nYSize * 2 + 0] << 24) |
     696           1 :                        (pabyRecord[8 + psDInfo->nYSize * 2 + 1] << 16) |
     697           1 :                        (pabyRecord[8 + psDInfo->nYSize * 2 + 2] << 8) |
     698           1 :                        pabyRecord[8 + psDInfo->nYSize * 2 + 3];
     699             : 
     700           1 :         if (fileCheckSum > 0xff * (8 + (unsigned int)psDInfo->nYSize * 2))
     701             :         {
     702             :             static int bWarned = FALSE;
     703           0 :             if (!bWarned)
     704             :             {
     705           0 :                 bWarned = TRUE;
     706             : #ifndef AVOID_CPL
     707           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     708             : #else
     709             :                 fprintf(stderr,
     710             : #endif
     711             :                          "The DTED driver has read from the file a checksum "
     712             :                          "with an impossible value (0x%X) at column %d.\n"
     713             :                          "Check with your file producer.\n"
     714             :                          "No more warnings will be issued in this session "
     715             :                          "about this operation.",
     716             :                          fileCheckSum, nColumnOffset);
     717             :             }
     718             :         }
     719           1 :         else if (fileCheckSum != nCheckSum)
     720             :         {
     721             : #ifndef AVOID_CPL
     722           1 :             CPLError(
     723             :                 CE_Failure, CPLE_AppDefined,
     724             : #else
     725             :             fprintf(
     726             :                 stderr,
     727             : #endif
     728             :                 "The DTED driver has found a computed and read checksum "
     729             :                 "that do not match at column %d. Computed 0x%X, read 0x%X\n",
     730             :                 nColumnOffset, nCheckSum, fileCheckSum);
     731           1 :             CPLFree(pabyRecord);
     732           1 :             return FALSE;
     733             :         }
     734             :     }
     735             : 
     736        3519 :     CPLFree(pabyRecord);
     737             : 
     738        3519 :     return TRUE;
     739             : }
     740             : 
     741             : /************************************************************************/
     742             : /*                          DTEDWriteProfile()                          */
     743             : /************************************************************************/
     744             : 
     745         964 : int DTEDWriteProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData)
     746             : 
     747             : {
     748             :     int nOffset;
     749         964 :     int i, nCheckSum = 0;
     750             :     GByte *pabyRecord;
     751             : 
     752         964 :     if (psDInfo->panMapLogicalColsToOffsets != NULL)
     753             :     {
     754             : #ifndef AVOID_CPL
     755           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     756             : #else
     757             :         fprintf(stderr,
     758             : #endif
     759             :                  "Write to partial file not supported.\n");
     760           0 :         return FALSE;
     761             :     }
     762             : 
     763             :     /* -------------------------------------------------------------------- */
     764             :     /*      Format the data record.                                         */
     765             :     /* -------------------------------------------------------------------- */
     766         964 :     pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2);
     767             : 
     768      766688 :     for (i = 0; i < psDInfo->nYSize; i++)
     769             :     {
     770      765724 :         int nABSVal = ABS(panData[psDInfo->nYSize - i - 1]);
     771      765724 :         pabyRecord[8 + i * 2] = (GByte)((nABSVal >> 8) & 0x7f);
     772      765724 :         pabyRecord[8 + i * 2 + 1] = (GByte)(nABSVal & 0xff);
     773             : 
     774      765724 :         if (panData[psDInfo->nYSize - i - 1] < 0)
     775           0 :             pabyRecord[8 + i * 2] |= 0x80;
     776             :     }
     777             : 
     778         964 :     pabyRecord[0] = 0xaa;
     779         964 :     pabyRecord[1] = 0;
     780         964 :     pabyRecord[2] = (GByte)(nColumnOffset / 256);
     781         964 :     pabyRecord[3] = (GByte)(nColumnOffset % 256);
     782         964 :     pabyRecord[4] = (GByte)(nColumnOffset / 256);
     783         964 :     pabyRecord[5] = (GByte)(nColumnOffset % 256);
     784         964 :     pabyRecord[6] = 0;
     785         964 :     pabyRecord[7] = 0;
     786             : 
     787             :     /* -------------------------------------------------------------------- */
     788             :     /*      Compute the checksum.                                           */
     789             :     /* -------------------------------------------------------------------- */
     790     1540120 :     for (i = 0; i < psDInfo->nYSize * 2 + 8; i++)
     791     1539160 :         nCheckSum += pabyRecord[i];
     792             : 
     793         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 0] = (GByte)((nCheckSum >> 24) & 0xff);
     794         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 1] = (GByte)((nCheckSum >> 16) & 0xff);
     795         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 2] = (GByte)((nCheckSum >> 8) & 0xff);
     796         964 :     pabyRecord[8 + psDInfo->nYSize * 2 + 3] = (GByte)(nCheckSum & 0xff);
     797             : 
     798             :     /* -------------------------------------------------------------------- */
     799             :     /*      Write the record.                                               */
     800             :     /* -------------------------------------------------------------------- */
     801         964 :     nOffset = psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2);
     802             : 
     803        1928 :     if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 ||
     804         964 :         VSIFWriteL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1)
     805             :     {
     806             : #ifndef AVOID_CPL
     807           0 :         CPLError(CE_Failure, CPLE_FileIO,
     808             : #else
     809             :         fprintf(stderr,
     810             : #endif
     811             :                  "Failed to seek to, or write profile %d at offset %d\n"
     812             :                  "in DTED file.\n",
     813             :                  nColumnOffset, nOffset);
     814           0 :         CPLFree(pabyRecord);
     815           0 :         return FALSE;
     816             :     }
     817             : 
     818         964 :     CPLFree(pabyRecord);
     819             : 
     820         964 :     return TRUE;
     821             : }
     822             : 
     823             : /************************************************************************/
     824             : /*                      DTEDGetMetadataLocation()                       */
     825             : /************************************************************************/
     826             : 
     827        1261 : static void DTEDGetMetadataLocation(DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
     828             :                                     char **ppszLocation, int *pnLength)
     829             : {
     830        1261 :     int bIsWeirdDTED = psDInfo->pachUHLRecord[4] == ' ';
     831             : 
     832        1261 :     switch (eCode)
     833             :     {
     834          48 :         case DTEDMD_ORIGINLONG:
     835          48 :             if (bIsWeirdDTED)
     836           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 8;
     837             :             else
     838          48 :                 *ppszLocation = psDInfo->pachUHLRecord + 4;
     839          48 :             *pnLength = 8;
     840          48 :             break;
     841             : 
     842          48 :         case DTEDMD_ORIGINLAT:
     843          48 :             if (bIsWeirdDTED)
     844           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 24;
     845             :             else
     846          48 :                 *ppszLocation = psDInfo->pachUHLRecord + 12;
     847          48 :             *pnLength = 8;
     848          48 :             break;
     849             : 
     850          51 :         case DTEDMD_VERTACCURACY_UHL:
     851          51 :             if (bIsWeirdDTED)
     852           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 56;
     853             :             else
     854          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 28;
     855          51 :             *pnLength = 4;
     856          51 :             break;
     857             : 
     858          51 :         case DTEDMD_SECURITYCODE_UHL:
     859          51 :             if (bIsWeirdDTED)
     860           0 :                 *ppszLocation = psDInfo->pachUHLRecord + 60;
     861             :             else
     862          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 32;
     863          51 :             *pnLength = 3;
     864          51 :             break;
     865             : 
     866          51 :         case DTEDMD_UNIQUEREF_UHL:
     867          51 :             if (bIsWeirdDTED)
     868           0 :                 *ppszLocation = NULL;
     869             :             else
     870          51 :                 *ppszLocation = psDInfo->pachUHLRecord + 35;
     871          51 :             *pnLength = 12;
     872          51 :             break;
     873             : 
     874          51 :         case DTEDMD_DATA_EDITION:
     875          51 :             if (bIsWeirdDTED)
     876           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 174;
     877             :             else
     878          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 87;
     879          51 :             *pnLength = 2;
     880          51 :             break;
     881             : 
     882          51 :         case DTEDMD_MATCHMERGE_VERSION:
     883          51 :             if (bIsWeirdDTED)
     884           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 176;
     885             :             else
     886          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 89;
     887          51 :             *pnLength = 1;
     888          51 :             break;
     889             : 
     890          51 :         case DTEDMD_MAINT_DATE:
     891          51 :             if (bIsWeirdDTED)
     892           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 177;
     893             :             else
     894          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 90;
     895          51 :             *pnLength = 4;
     896          51 :             break;
     897             : 
     898          51 :         case DTEDMD_MATCHMERGE_DATE:
     899          51 :             if (bIsWeirdDTED)
     900           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 181;
     901             :             else
     902          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 94;
     903          51 :             *pnLength = 4;
     904          51 :             break;
     905             : 
     906          51 :         case DTEDMD_MAINT_DESCRIPTION:
     907          51 :             if (bIsWeirdDTED)
     908           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 185;
     909             :             else
     910          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 98;
     911          51 :             *pnLength = 4;
     912          51 :             break;
     913             : 
     914          51 :         case DTEDMD_PRODUCER:
     915          51 :             if (bIsWeirdDTED)
     916           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 189;
     917             :             else
     918          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 102;
     919          51 :             *pnLength = 8;
     920          51 :             break;
     921             : 
     922          51 :         case DTEDMD_VERTDATUM:
     923          51 :             if (bIsWeirdDTED)
     924           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 267;
     925             :             else
     926          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 141;
     927          51 :             *pnLength = 3;
     928          51 :             break;
     929             : 
     930          51 :         case DTEDMD_HORIZDATUM:
     931          51 :             if (bIsWeirdDTED)
     932           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 270;
     933             :             else
     934          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 144;
     935          51 :             *pnLength = 5;
     936          51 :             break;
     937             : 
     938          51 :         case DTEDMD_DIGITIZING_SYS:
     939          51 :             if (bIsWeirdDTED)
     940           0 :                 *ppszLocation = NULL;
     941             :             else
     942          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 149;
     943          51 :             *pnLength = 10;
     944          51 :             break;
     945             : 
     946          51 :         case DTEDMD_COMPILATION_DATE:
     947          51 :             if (bIsWeirdDTED)
     948           0 :                 *ppszLocation = NULL;
     949             :             else
     950          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 159;
     951          51 :             *pnLength = 4;
     952          51 :             break;
     953             : 
     954          51 :         case DTEDMD_HORIZACCURACY:
     955          51 :             *ppszLocation = psDInfo->pachACCRecord + 3;
     956          51 :             *pnLength = 4;
     957          51 :             break;
     958             : 
     959          51 :         case DTEDMD_REL_HORIZACCURACY:
     960          51 :             *ppszLocation = psDInfo->pachACCRecord + 11;
     961          51 :             *pnLength = 4;
     962          51 :             break;
     963             : 
     964          51 :         case DTEDMD_REL_VERTACCURACY:
     965          51 :             *ppszLocation = psDInfo->pachACCRecord + 15;
     966          51 :             *pnLength = 4;
     967          51 :             break;
     968             : 
     969          51 :         case DTEDMD_VERTACCURACY_ACC:
     970          51 :             *ppszLocation = psDInfo->pachACCRecord + 7;
     971          51 :             *pnLength = 4;
     972          51 :             break;
     973             : 
     974          51 :         case DTEDMD_SECURITYCODE_DSI:
     975          51 :             *ppszLocation = psDInfo->pachDSIRecord + 3;
     976          51 :             *pnLength = 1;
     977          51 :             break;
     978             : 
     979          51 :         case DTEDMD_UNIQUEREF_DSI:
     980          51 :             if (bIsWeirdDTED)
     981           0 :                 *ppszLocation = NULL;
     982             :             else
     983          51 :                 *ppszLocation = psDInfo->pachDSIRecord + 64;
     984          51 :             *pnLength = 15;
     985          51 :             break;
     986             : 
     987          48 :         case DTEDMD_NIMA_DESIGNATOR:
     988          48 :             if (bIsWeirdDTED)
     989           0 :                 *ppszLocation = psDInfo->pachDSIRecord + 118;
     990             :             else
     991          48 :                 *ppszLocation = psDInfo->pachDSIRecord + 59;
     992          48 :             *pnLength = 5;
     993          48 :             break;
     994             : 
     995          52 :         case DTEDMD_PARTIALCELL_DSI:
     996          52 :             if (bIsWeirdDTED)
     997           0 :                 *ppszLocation = NULL;
     998             :             else
     999          52 :                 *ppszLocation = psDInfo->pachDSIRecord + 289;
    1000          52 :             *pnLength = 2;
    1001          52 :             break;
    1002             : 
    1003          48 :         case DTEDMD_SECURITYCONTROL:
    1004          48 :             *ppszLocation = psDInfo->pachDSIRecord + 4;
    1005          48 :             *pnLength = 2;
    1006          48 :             break;
    1007             : 
    1008          48 :         case DTEDMD_SECURITYHANDLING:
    1009          48 :             *ppszLocation = psDInfo->pachDSIRecord + 6;
    1010          48 :             *pnLength = 27;
    1011          48 :             break;
    1012             : 
    1013           0 :         default:
    1014           0 :             *ppszLocation = NULL;
    1015           0 :             *pnLength = 0;
    1016             :     }
    1017        1261 : }
    1018             : 
    1019             : /************************************************************************/
    1020             : /*                          DTEDGetMetadata()                           */
    1021             : /************************************************************************/
    1022             : 
    1023        1200 : char *DTEDGetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode)
    1024             : 
    1025             : {
    1026             :     int nFieldLen;
    1027             :     char *pszFieldSrc;
    1028             :     char *pszResult;
    1029             : 
    1030        1200 :     DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen);
    1031        1200 :     if (pszFieldSrc == NULL)
    1032           0 :         return CPLStrdup("");
    1033             : 
    1034        1200 :     pszResult = (char *)CPLMalloc(nFieldLen + 1);
    1035        1200 :     strncpy(pszResult, pszFieldSrc, nFieldLen);
    1036        1200 :     pszResult[nFieldLen] = '\0';
    1037             : 
    1038        1200 :     return pszResult;
    1039             : }
    1040             : 
    1041             : /************************************************************************/
    1042             : /*                          DTEDSetMetadata()                           */
    1043             : /************************************************************************/
    1044             : 
    1045          61 : int DTEDSetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
    1046             :                     const char *pszNewValue)
    1047             : 
    1048             : {
    1049             :     int nFieldLen;
    1050             :     char *pszFieldSrc;
    1051             :     size_t nLenToCopy;
    1052             : 
    1053          61 :     if (!psDInfo->bUpdate)
    1054           0 :         return FALSE;
    1055             : 
    1056             :     /* -------------------------------------------------------------------- */
    1057             :     /*      Get the location in the headers to update.                      */
    1058             :     /* -------------------------------------------------------------------- */
    1059          61 :     DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen);
    1060          61 :     if (pszFieldSrc == NULL)
    1061           0 :         return FALSE;
    1062             : 
    1063             :     /* -------------------------------------------------------------------- */
    1064             :     /*      Update it, padding with spaces.                                 */
    1065             :     /* -------------------------------------------------------------------- */
    1066          61 :     nLenToCopy = MIN((size_t)nFieldLen, strlen(pszNewValue));
    1067          61 :     memcpy(pszFieldSrc, pszNewValue, nLenToCopy);
    1068          61 :     if (nLenToCopy < (size_t)nFieldLen)
    1069           0 :         memset(pszFieldSrc + nLenToCopy, ' ', nFieldLen - nLenToCopy);
    1070             : 
    1071             :     /* Turn the flag on, so that the headers are rewritten at file */
    1072             :     /* closing */
    1073          61 :     psDInfo->bRewriteHeaders = TRUE;
    1074             : 
    1075          61 :     return TRUE;
    1076             : }
    1077             : 
    1078             : /************************************************************************/
    1079             : /*                             DTEDClose()                              */
    1080             : /************************************************************************/
    1081             : 
    1082          63 : void DTEDClose(DTEDInfo *psDInfo)
    1083             : 
    1084             : {
    1085          63 :     if (psDInfo->bRewriteHeaders)
    1086             :     {
    1087             :         /* --------------------------------------------------------------------
    1088             :          */
    1089             :         /*      Write all headers back to disk. */
    1090             :         /* --------------------------------------------------------------------
    1091             :          */
    1092           4 :         CPL_IGNORE_RET_VAL_INT(
    1093           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nUHLOffset, SEEK_SET));
    1094           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1095           4 :             VSIFWriteL(psDInfo->pachUHLRecord, 1, DTED_UHL_SIZE, psDInfo->fp));
    1096             : 
    1097           4 :         CPL_IGNORE_RET_VAL_INT(
    1098           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nDSIOffset, SEEK_SET));
    1099           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1100           4 :             VSIFWriteL(psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, psDInfo->fp));
    1101             : 
    1102           4 :         CPL_IGNORE_RET_VAL_INT(
    1103           4 :             VSIFSeekL(psDInfo->fp, psDInfo->nACCOffset, SEEK_SET));
    1104           4 :         CPL_IGNORE_RET_VAL_SIZET(
    1105           4 :             VSIFWriteL(psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, psDInfo->fp));
    1106             :     }
    1107             : 
    1108          63 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(psDInfo->fp));
    1109             : 
    1110          63 :     CPLFree(psDInfo->pachUHLRecord);
    1111          63 :     CPLFree(psDInfo->pachDSIRecord);
    1112          63 :     CPLFree(psDInfo->pachACCRecord);
    1113             : 
    1114          63 :     CPLFree(psDInfo->panMapLogicalColsToOffsets);
    1115             : 
    1116          63 :     CPLFree(psDInfo);
    1117          63 : }

Generated by: LCOV version 1.14