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

Generated by: LCOV version 1.14