LCOV - code coverage report
Current view: top level - frmts/dted - dted_api.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 359 476 75.4 %
Date: 2024-11-21 22:18:42 Functions: 13 15 86.7 %

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

Generated by: LCOV version 1.14