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

Generated by: LCOV version 1.14