LCOV - code coverage report
Current view: top level - frmts/nitf - nitfdes.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 154 300 51.3 %
Date: 2025-01-18 12:42:00 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NITF Read/Write Library
       4             :  * Purpose:  Module responsible for implementation of DE segments.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2010-2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal.h"
      14             : #include "nitflib.h"
      15             : #include "cpl_vsi.h"
      16             : #include "cpl_conv.h"
      17             : #include "cpl_string.h"
      18             : 
      19             : #ifndef CPL_IGNORE_RET_VAL_INT_defined
      20             : #define CPL_IGNORE_RET_VAL_INT_defined
      21             : 
      22           0 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      23             : {
      24           0 : }
      25             : #endif
      26             : 
      27             : /************************************************************************/
      28             : /*                          NITFDESAccess()                             */
      29             : /************************************************************************/
      30             : 
      31          15 : NITFDES *NITFDESAccess(NITFFile *psFile, int iSegment)
      32             : 
      33             : {
      34             :     NITFDES *psDES;
      35             :     char *pachHeader;
      36             :     NITFSegmentInfo *psSegInfo;
      37             :     char szDESID[26];
      38             :     int nOffset;
      39             :     int bHasDESOFLW;
      40             :     int nDESSHL;
      41             : 
      42             :     /* -------------------------------------------------------------------- */
      43             :     /*      Verify segment, and return existing DES accessor if there       */
      44             :     /*      is one.                                                         */
      45             :     /* -------------------------------------------------------------------- */
      46          15 :     if (iSegment < 0 || iSegment >= psFile->nSegmentCount)
      47           0 :         return NULL;
      48             : 
      49          15 :     psSegInfo = psFile->pasSegmentInfo + iSegment;
      50             : 
      51          15 :     if (!EQUAL(psSegInfo->szSegmentType, "DE"))
      52           0 :         return NULL;
      53             : 
      54          15 :     if (psSegInfo->hAccess != NULL)
      55           0 :         return (NITFDES *)psSegInfo->hAccess;
      56             : 
      57             :     /* -------------------------------------------------------------------- */
      58             :     /*      Read the DES subheader.                                         */
      59             :     /* -------------------------------------------------------------------- */
      60          15 :     if (psSegInfo->nSegmentHeaderSize < 200)
      61             :     {
      62           0 :         CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
      63           0 :         return NULL;
      64             :     }
      65             : 
      66          15 :     pachHeader = (char *)VSI_MALLOC_VERBOSE(psSegInfo->nSegmentHeaderSize);
      67          15 :     if (pachHeader == NULL)
      68             :     {
      69           0 :         return NULL;
      70             :     }
      71             : 
      72          15 : retry:
      73          15 :     if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentHeaderStart, SEEK_SET) != 0 ||
      74          15 :         VSIFReadL(pachHeader, 1, psSegInfo->nSegmentHeaderSize, psFile->fp) !=
      75          15 :             psSegInfo->nSegmentHeaderSize)
      76             :     {
      77           0 :         CPLError(CE_Failure, CPLE_FileIO,
      78             :                  "Failed to read %u byte DES subheader from " CPL_FRMT_GUIB ".",
      79             :                  psSegInfo->nSegmentHeaderSize, psSegInfo->nSegmentHeaderStart);
      80           0 :         CPLFree(pachHeader);
      81           0 :         return NULL;
      82             :     }
      83             : 
      84          15 :     if (!STARTS_WITH_CI(pachHeader, "DE"))
      85             :     {
      86           0 :         if (STARTS_WITH_CI(pachHeader + 4, "DERegistered"))
      87             :         {
      88             :             /* BAO_46_Ed1/rpf/conc/concz10/000fz010.ona and cie are buggy */
      89           0 :             CPLDebug("NITF",
      90             :                      "Patching nSegmentHeaderStart and nSegmentStart for DE "
      91             :                      "segment %d",
      92             :                      iSegment);
      93           0 :             psSegInfo->nSegmentHeaderStart += 4;
      94           0 :             psSegInfo->nSegmentStart += 4;
      95           0 :             goto retry;
      96             :         }
      97             : 
      98           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      99             :                  "Invalid segment prefix for DE segment %d", iSegment);
     100             : 
     101           0 :         CPLFree(pachHeader);
     102           0 :         return NULL;
     103             :     }
     104             : 
     105             :     /* -------------------------------------------------------------------- */
     106             :     /*      Initialize DES object.                                          */
     107             :     /* -------------------------------------------------------------------- */
     108          15 :     psDES = (NITFDES *)CPLCalloc(sizeof(NITFDES), 1);
     109             : 
     110          15 :     psDES->psFile = psFile;
     111          15 :     psDES->iSegment = iSegment;
     112          15 :     psDES->pachHeader = pachHeader;
     113             : 
     114          15 :     psSegInfo->hAccess = psDES;
     115             : 
     116             : /* -------------------------------------------------------------------- */
     117             : /*      Collect a variety of information as metadata.                   */
     118             : /* -------------------------------------------------------------------- */
     119             : #define GetMD(length, name)                                                    \
     120             :     do                                                                         \
     121             :     {                                                                          \
     122             :         NITFExtractMetadata(&(psDES->papszMetadata), pachHeader, nOffset,      \
     123             :                             length, #name);                                    \
     124             :         nOffset += length;                                                     \
     125             :     } while (0)
     126             : 
     127          15 :     nOffset = 2;
     128          15 :     GetMD(25, DESID);
     129          15 :     GetMD(2, DESVER);
     130          15 :     GetMD(1, DECLAS);
     131          15 :     GetMD(2, DESCLSY);
     132          15 :     GetMD(11, DESCODE);
     133          15 :     GetMD(2, DESCTLH);
     134          15 :     GetMD(20, DESREL);
     135          15 :     GetMD(2, DESDCTP);
     136          15 :     GetMD(8, DESDCDT);
     137          15 :     GetMD(4, DESDCXM);
     138          15 :     GetMD(1, DESDG);
     139          15 :     GetMD(8, DESDGDT);
     140          15 :     GetMD(43, DESCLTX);
     141          15 :     GetMD(1, DESCATP);
     142          15 :     GetMD(40, DESCAUT);
     143          15 :     GetMD(1, DESCRSN);
     144          15 :     GetMD(8, DESSRDT);
     145          15 :     GetMD(15, DESCTLN);
     146             : 
     147             :     /* Load DESID */
     148          15 :     NITFGetField(szDESID, pachHeader, 2, 25);
     149             : 
     150             :     /* For NITF < 02.10, we cannot rely on DESID=TRE_OVERFLOW to detect */
     151             :     /* if DESOFLW and DESITEM are present. So if the next 4 bytes are non */
     152             :     /* numeric, we'll assume that DESOFLW is there */
     153          15 :     bHasDESOFLW =
     154          27 :         STARTS_WITH_CI(szDESID, "TRE_OVERFLOW") ||
     155          12 :         (!((pachHeader[nOffset + 0] >= '0' && pachHeader[nOffset + 0] <= '9') &&
     156          12 :            (pachHeader[nOffset + 1] >= '0' && pachHeader[nOffset + 1] <= '9') &&
     157          12 :            (pachHeader[nOffset + 2] >= '0' && pachHeader[nOffset + 2] <= '9') &&
     158          12 :            (pachHeader[nOffset + 3] >= '0' && pachHeader[nOffset + 3] <= '9')));
     159             : 
     160          15 :     if (bHasDESOFLW)
     161             :     {
     162           3 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 6 + 3)
     163             :         {
     164           0 :             CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
     165           0 :             NITFDESDeaccess(psDES);
     166           0 :             return NULL;
     167             :         }
     168           3 :         GetMD(6, DESOFLW);
     169           3 :         GetMD(3, DESITEM);
     170             :     }
     171             : 
     172          15 :     if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4)
     173             :     {
     174           0 :         CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
     175           0 :         NITFDESDeaccess(psDES);
     176           0 :         return NULL;
     177             :     }
     178             : 
     179          15 :     GetMD(4, DESSHL);
     180          15 :     nDESSHL = atoi(CSLFetchNameValue(psDES->papszMetadata, "DESSHL"));
     181             : 
     182          15 :     if (nDESSHL < 0)
     183             :     {
     184           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for DESSHL");
     185           0 :         NITFDESDeaccess(psDES);
     186           0 :         return NULL;
     187             :     }
     188          15 :     if ((int)psSegInfo->nSegmentHeaderSize < nOffset + nDESSHL)
     189             :     {
     190           0 :         CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
     191           0 :         NITFDESDeaccess(psDES);
     192           0 :         return NULL;
     193             :     }
     194             : 
     195          15 :     if (nDESSHL > 0)
     196          10 :         GetMD(nDESSHL, DESSHF);
     197             : 
     198          15 :     if ((int)psSegInfo->nSegmentHeaderSize > nOffset)
     199             :     {
     200           0 :         char *pszEscapedDESDATA = CPLEscapeString(
     201           0 :             pachHeader + nOffset, (int)psSegInfo->nSegmentHeaderSize - nOffset,
     202             :             CPLES_BackslashQuotable);
     203           0 :         psDES->papszMetadata =
     204           0 :             CSLSetNameValue(psDES->papszMetadata, "DESDATA", pszEscapedDESDATA);
     205           0 :         CPLFree(pszEscapedDESDATA);
     206             :     }
     207             :     else
     208             :     {
     209             : 
     210             : #define TEN_MEGABYTES 10485760
     211             : 
     212          15 :         if (psSegInfo->nSegmentSize > TEN_MEGABYTES)
     213             :         {
     214           0 :             const char *pszOffset = CPLSPrintf(
     215           0 :                 CPL_FRMT_GUIB, psFile->pasSegmentInfo[iSegment].nSegmentStart);
     216           0 :             const char *pszSize = CPLSPrintf(
     217           0 :                 CPL_FRMT_GUIB, psFile->pasSegmentInfo[iSegment].nSegmentSize);
     218             : 
     219           0 :             psDES->papszMetadata = CSLSetNameValue(psDES->papszMetadata,
     220             :                                                    "DESDATA_OFFSET", pszOffset);
     221           0 :             psDES->papszMetadata = CSLSetNameValue(psDES->papszMetadata,
     222             :                                                    "DESDATA_LENGTH", pszSize);
     223             :         }
     224             :         else
     225             :         {
     226             :             char *pachData =
     227          15 :                 (char *)VSI_MALLOC_VERBOSE((size_t)psSegInfo->nSegmentSize);
     228          15 :             if (pachData == NULL)
     229             :             {
     230             :                 /* nothing */
     231             :             }
     232          15 :             else if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart,
     233          15 :                                SEEK_SET) != 0 ||
     234          15 :                      VSIFReadL(pachData, 1, (size_t)psSegInfo->nSegmentSize,
     235          15 :                                psFile->fp) != psSegInfo->nSegmentSize)
     236             :             {
     237           0 :                 CPLDebug("NITF",
     238             :                          "Failed to read " CPL_FRMT_GUIB
     239             :                          " bytes DES data from " CPL_FRMT_GUIB ".",
     240             :                          psSegInfo->nSegmentSize, psSegInfo->nSegmentStart);
     241             :             }
     242             :             else
     243             :             {
     244             :                 char *pszEscapedDESDATA =
     245          15 :                     CPLEscapeString(pachData, (int)psSegInfo->nSegmentSize,
     246             :                                     CPLES_BackslashQuotable);
     247          15 :                 psDES->papszMetadata = CSLSetNameValue(
     248             :                     psDES->papszMetadata, "DESDATA", pszEscapedDESDATA);
     249          15 :                 CPLFree(pszEscapedDESDATA);
     250             :             }
     251          15 :             CPLFree(pachData);
     252             :         }
     253             : 
     254             : #ifdef notdef
     255             :         /* Disabled because might generate a huge amount of elements */
     256             :         if (STARTS_WITH_CI(szDESID, "CSATTA DES"))
     257             :         {
     258             :             int nNumAtt = atoi(
     259             :                 CSLFetchNameValueDef(psDES->papszMetadata, "NUM_ATT", "0"));
     260             :             if (nNumAtt * 8 * 4 == psSegInfo->nSegmentSize)
     261             :             {
     262             :                 int nMDSize = CSLCount(psDES->papszMetadata);
     263             :                 char **papszMD = (char **)VSIRealloc(
     264             :                     psDES->papszMetadata,
     265             :                     (nMDSize + nNumAtt * 4 + 1) * sizeof(char *));
     266             :                 if (papszMD)
     267             :                 {
     268             :                     int i, j;
     269             :                     const GByte *pachDataIter = pachData;
     270             : 
     271             :                     psDES->papszMetadata = papszMD;
     272             :                     for (i = 0; i < nNumAtt; i++)
     273             :                     {
     274             :                         char szAttrNameValue[64 + 1 + 256 + 1];
     275             :                         double dfVal;
     276             :                         for (j = 0; j < 4; j++)
     277             :                         {
     278             :                             memcpy(&dfVal, pachDataIter, 8);
     279             :                             CPL_MSBPTR64(&dfVal);
     280             :                             pachDataIter += 8;
     281             :                             CPLsprintf(szAttrNameValue, "ATT_Q%d_%d=%.16g",
     282             :                                        j + 1, i, dfVal);
     283             :                             papszMD[nMDSize + i * 4 + j] =
     284             :                                 CPLStrdup(szAttrNameValue);
     285             :                         }
     286             :                     }
     287             :                     papszMD[nMDSize + nNumAtt * 4] = NULL;
     288             :                 }
     289             :             }
     290             :         }
     291             : #endif
     292             :     }
     293             : 
     294          15 :     return psDES;
     295             : }
     296             : 
     297             : /************************************************************************/
     298             : /*                           NITFDESDeaccess()                          */
     299             : /************************************************************************/
     300             : 
     301          15 : void NITFDESDeaccess(NITFDES *psDES)
     302             : 
     303             : {
     304          15 :     CPLAssert(psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess == psDES);
     305             : 
     306          15 :     psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess = NULL;
     307             : 
     308          15 :     CPLFree(psDES->pachHeader);
     309          15 :     CSLDestroy(psDES->papszMetadata);
     310             : 
     311          15 :     CPLFree(psDES);
     312          15 : }
     313             : 
     314             : /************************************************************************/
     315             : /*                              NITFDESGetTRE()                         */
     316             : /************************************************************************/
     317             : 
     318             : /**
     319             :  * Return the TRE located at nOffset.
     320             :  *
     321             :  * @param psDES          descriptor of the DE segment
     322             :  * @param nOffset        offset of the TRE relative to the beginning of the
     323             :  * segment data
     324             :  * @param szTREName      will be filled with the TRE name
     325             :  * @param ppabyTREData   will be allocated by the function and filled with the
     326             :  * TRE content (in raw form)
     327             :  * @param pnFoundTRESize will be filled with the TRE size (excluding the first
     328             :  * 11 bytes)
     329             :  * @return TRUE if a TRE was found
     330             :  */
     331             : 
     332           9 : int NITFDESGetTRE(NITFDES *psDES, int nOffset, char szTREName[7],
     333             :                   char **ppabyTREData, int *pnFoundTRESize)
     334             : {
     335             :     char szTREHeader[12];
     336             :     char szTRETempName[7];
     337             :     NITFSegmentInfo *psSegInfo;
     338             :     VSILFILE *fp;
     339             :     int nTRESize;
     340             : 
     341           9 :     memset(szTREName, '\0', 7);
     342           9 :     if (ppabyTREData)
     343           9 :         *ppabyTREData = NULL;
     344           9 :     if (pnFoundTRESize)
     345           9 :         *pnFoundTRESize = 0;
     346             : 
     347           9 :     if (nOffset < 0)
     348           0 :         return FALSE;
     349             : 
     350           9 :     if (psDES == NULL)
     351           0 :         return FALSE;
     352             : 
     353           9 :     if (CSLFetchNameValue(psDES->papszMetadata, "DESOFLW") == NULL)
     354           2 :         return FALSE;
     355             : 
     356           7 :     psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
     357           7 :     fp = psDES->psFile->fp;
     358             : 
     359           7 :     if ((size_t)nOffset >= psSegInfo->nSegmentSize)
     360           2 :         return FALSE;
     361             : 
     362          10 :     if (VSIFSeekL(fp, psSegInfo->nSegmentStart + nOffset, SEEK_SET) != 0 ||
     363           5 :         VSIFReadL(szTREHeader, 1, 11, fp) != 11)
     364             :     {
     365             :         /* Some files have a nSegmentSize larger than what it is in reality */
     366             :         /* So exit silently if we're at end of file */
     367           0 :         if (VSIFSeekL(fp, 0, SEEK_END) != 0 ||
     368           0 :             VSIFTellL(fp) == psSegInfo->nSegmentStart + nOffset)
     369           0 :             return FALSE;
     370             : 
     371           0 :         CPLError(CE_Failure, CPLE_FileIO,
     372             :                  "Cannot get 11 bytes at offset " CPL_FRMT_GUIB ".",
     373           0 :                  psSegInfo->nSegmentStart + nOffset);
     374           0 :         return FALSE;
     375             :     }
     376           5 :     szTREHeader[11] = '\0';
     377             : 
     378           5 :     memcpy(szTRETempName, szTREHeader, 6);
     379           5 :     szTRETempName[6] = '\0';
     380             : 
     381           5 :     nTRESize = atoi(szTREHeader + 6);
     382           5 :     if (nTRESize < 0)
     383             :     {
     384           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
     385             :                  nTRESize, szTRETempName);
     386           0 :         return FALSE;
     387             :     }
     388           5 :     if ((size_t)(nOffset + 11 + nTRESize) > psSegInfo->nSegmentSize)
     389             :     {
     390           0 :         CPLError(
     391             :             CE_Failure, CPLE_AppDefined,
     392             :             "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
     393           0 :             szTRETempName, (int)(psSegInfo->nSegmentSize - (nOffset + 11)),
     394             :             nTRESize);
     395           0 :         return FALSE;
     396             :     }
     397             : 
     398           5 :     if (ppabyTREData)
     399             :     {
     400             :         /* Allocate one extra byte for the NULL terminating character */
     401           5 :         *ppabyTREData = (char *)VSI_MALLOC_VERBOSE(nTRESize + 1);
     402           5 :         if (*ppabyTREData == NULL)
     403             :         {
     404           0 :             return FALSE;
     405             :         }
     406           5 :         (*ppabyTREData)[nTRESize] = '\0';
     407             : 
     408           5 :         if ((int)VSIFReadL(*ppabyTREData, 1, nTRESize, fp) != nTRESize)
     409             :         {
     410           0 :             CPLError(CE_Failure, CPLE_FileIO,
     411             :                      "Cannot get %d bytes at offset " CPL_FRMT_GUIB ".",
     412             :                      nTRESize, VSIFTellL(fp));
     413           0 :             VSIFree(*ppabyTREData);
     414           0 :             *ppabyTREData = NULL;
     415           0 :             return FALSE;
     416             :         }
     417             :     }
     418             : 
     419           5 :     strcpy(szTREName, szTRETempName);
     420           5 :     if (pnFoundTRESize)
     421           5 :         *pnFoundTRESize = nTRESize;
     422             : 
     423           5 :     return TRUE;
     424             : }
     425             : 
     426             : /************************************************************************/
     427             : /*                           NITFDESFreeTREData()                       */
     428             : /************************************************************************/
     429             : 
     430           5 : void NITFDESFreeTREData(char *pabyTREData)
     431             : {
     432           5 :     VSIFree(pabyTREData);
     433           5 : }
     434             : 
     435             : /************************************************************************/
     436             : /*                        NITFDESExtractShapefile()                     */
     437             : /************************************************************************/
     438             : 
     439           0 : int NITFDESExtractShapefile(NITFDES *psDES, const char *pszRadixFileName)
     440             : {
     441             :     NITFSegmentInfo *psSegInfo;
     442           0 :     const char *apszExt[3] = {NULL};
     443           0 :     int anOffset[4] = {0};
     444             :     int iShpFile;
     445             :     char *pszFilename;
     446             :     size_t nFilenameLen;
     447           0 :     char *pachHeader = psDES->pachHeader;
     448             : 
     449           0 :     int nDESSHL = atoi(CSLFetchNameValue(psDES->papszMetadata, "DESSHL"));
     450           0 :     if (nDESSHL != 62 && nDESSHL != 80)
     451             :     {
     452           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid DESSHL for CSSHPA DES");
     453           0 :         return FALSE;
     454             :     }
     455             : 
     456           0 :     char **papszMetadataBackup = CSLDuplicate(psDES->papszMetadata);
     457           0 :     psDES->papszMetadata = NULL;
     458           0 :     int nOffset = 200 + 25 + 10;
     459           0 :     if (nDESSHL == 80)
     460           0 :         nOffset += 18;
     461           0 :     GetMD(3, SHAPE1_NAME);
     462           0 :     GetMD(6, SHAPE1_START);
     463           0 :     GetMD(3, SHAPE2_NAME);
     464           0 :     GetMD(6, SHAPE2_START);
     465           0 :     GetMD(3, SHAPE3_NAME);
     466           0 :     GetMD(6, SHAPE3_START);
     467             : 
     468           0 :     psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
     469             : 
     470           0 :     apszExt[0] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE1_NAME");
     471           0 :     anOffset[0] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE1_START"));
     472           0 :     apszExt[1] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE2_NAME");
     473           0 :     anOffset[1] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE2_START"));
     474           0 :     apszExt[2] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE3_NAME");
     475           0 :     anOffset[2] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE3_START"));
     476           0 :     anOffset[3] = (int)psSegInfo->nSegmentSize;
     477             : 
     478           0 :     int ret = FALSE;
     479           0 :     for (iShpFile = 0; iShpFile < 3; iShpFile++)
     480             :     {
     481           0 :         if (!EQUAL(apszExt[iShpFile], "SHP") &&
     482           0 :             !EQUAL(apszExt[iShpFile], "SHX") &&
     483           0 :             !EQUAL(apszExt[iShpFile], "DBF"))
     484           0 :             goto end;
     485             : 
     486           0 :         if (anOffset[iShpFile] < 0 ||
     487           0 :             anOffset[iShpFile] >= anOffset[iShpFile + 1])
     488           0 :             goto end;
     489             :     }
     490             : 
     491           0 :     nFilenameLen = strlen(pszRadixFileName) + 4 + 1;
     492           0 :     pszFilename = (char *)VSI_MALLOC_VERBOSE(nFilenameLen);
     493           0 :     if (pszFilename == NULL)
     494           0 :         goto end;
     495             : 
     496           0 :     for (iShpFile = 0; iShpFile < 3; iShpFile++)
     497             :     {
     498             :         VSILFILE *fp;
     499             :         GByte *pabyBuffer;
     500           0 :         int nSize = anOffset[iShpFile + 1] - anOffset[iShpFile];
     501             : 
     502           0 :         pabyBuffer = (GByte *)VSI_MALLOC_VERBOSE(nSize);
     503           0 :         if (pabyBuffer == NULL)
     504             :         {
     505           0 :             VSIFree(pszFilename);
     506           0 :             goto end;
     507             :         }
     508             : 
     509           0 :         if (VSIFSeekL(psDES->psFile->fp,
     510           0 :                       psSegInfo->nSegmentStart + anOffset[iShpFile],
     511           0 :                       SEEK_SET) != 0 ||
     512           0 :             VSIFReadL(pabyBuffer, 1, nSize, psDES->psFile->fp) != (size_t)nSize)
     513             :         {
     514           0 :             VSIFree(pabyBuffer);
     515           0 :             VSIFree(pszFilename);
     516           0 :             goto end;
     517             :         }
     518             : 
     519           0 :         snprintf(pszFilename, nFilenameLen, "%s.%s", pszRadixFileName,
     520             :                  apszExt[iShpFile]);
     521           0 :         fp = VSIFOpenL(pszFilename, "wb");
     522           0 :         if (fp == NULL)
     523             :         {
     524           0 :             VSIFree(pabyBuffer);
     525           0 :             VSIFree(pszFilename);
     526           0 :             goto end;
     527             :         }
     528             : 
     529           0 :         if ((int)VSIFWriteL(pabyBuffer, 1, nSize, fp) != nSize)
     530             :         {
     531           0 :             CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     532           0 :             VSIFree(pabyBuffer);
     533           0 :             VSIFree(pszFilename);
     534           0 :             goto end;
     535             :         }
     536           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     537           0 :         VSIFree(pabyBuffer);
     538             :     }
     539             : 
     540           0 :     VSIFree(pszFilename);
     541             : 
     542           0 :     ret = TRUE;
     543           0 : end:
     544           0 :     CSLDestroy(psDES->papszMetadata);
     545           0 :     psDES->papszMetadata = papszMetadataBackup;
     546           0 :     return ret;
     547             : }
     548             : 
     549             : /************************************************************************/
     550             : /*                              NITFDESGetXml()                         */
     551             : /************************************************************************/
     552             : 
     553          11 : CPLXMLNode *NITFDESGetXml(NITFFile *psFile, int iSegment, bool bValidate,
     554             :                           bool *pbGotError)
     555             : {
     556             :     CPLXMLNode *psDesNode;
     557             :     char **papszTmp;
     558          11 :     NITFDES *psDes = NITFDESAccess(psFile, iSegment);
     559             : 
     560          11 :     if (psDes == NULL)
     561             :     {
     562           0 :         return NULL;
     563             :     }
     564             : 
     565          11 :     if (psDes->papszMetadata == NULL)
     566             :     {
     567           0 :         NITFDESDeaccess(psDes);
     568           0 :         return NULL;
     569             :     }
     570             : 
     571          11 :     psDesNode = CPLCreateXMLNode(NULL, CXT_Element, "des");
     572          11 :     papszTmp = psDes->papszMetadata;
     573             : 
     574          11 :     bool bIsXML_DATA_CONTENT = false;
     575         241 :     while (papszTmp != NULL && *papszTmp != NULL)
     576             :     {
     577             :         CPLXMLNode *psFieldNode;
     578             :         CPLXMLNode *psNameNode;
     579             : 
     580             :         const char *pszMDval;
     581             :         const char *pszMDsep;
     582             : 
     583         230 :         if ((pszMDsep = strchr(*papszTmp, '=')) == NULL)
     584             :         {
     585           0 :             NITFDESDeaccess(psDes);
     586           0 :             CPLDestroyXMLNode(psDesNode);
     587           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     588             :                      "NITF DES metadata item missing separator");
     589           0 :             return NULL;
     590             :         }
     591             : 
     592         230 :         pszMDval = pszMDsep + 1;
     593             : 
     594         230 :         if (papszTmp == psDes->papszMetadata)
     595             :         {
     596          11 :             bIsXML_DATA_CONTENT = strcmp(pszMDval, "XML_DATA_CONTENT") == 0;
     597          11 :             CPLCreateXMLNode(CPLCreateXMLNode(psDesNode, CXT_Attribute, "name"),
     598             :                              CXT_Text, pszMDval);
     599             :         }
     600             :         else
     601             :         {
     602         219 :             char *pszMDname = (char *)CPLMalloc(pszMDsep - *papszTmp + 1);
     603         219 :             CPLStrlcpy(pszMDname, *papszTmp, pszMDsep - *papszTmp + 1);
     604             : 
     605         219 :             psFieldNode = CPLCreateXMLNode(psDesNode, CXT_Element, "field");
     606         219 :             psNameNode = CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
     607         219 :             CPLCreateXMLNode(psNameNode, CXT_Text, pszMDname);
     608             : 
     609         219 :             if (strcmp(pszMDname, "DESSHF") == 0)
     610             :             {
     611           8 :                 CPLAddXMLAttributeAndValue(psFieldNode, "value", pszMDval);
     612           8 :                 CPLXMLNode *psChild = NITFCreateXMLDesUserDefinedSubHeader(
     613             :                     psFile, psDes, bValidate, pbGotError);
     614           8 :                 if (psChild)
     615             :                 {
     616           4 :                     CPLAddXMLChild(psFieldNode, psChild);
     617             :                 }
     618             :             }
     619         211 :             else if (strcmp(pszMDname, "DESDATA") == 0)
     620             :             {
     621             :                 int nLen;
     622             :                 char *pszUnescaped =
     623          11 :                     CPLUnescapeString(pszMDval, &nLen, CPLES_BackslashQuotable);
     624             :                 char *pszBase64 =
     625          11 :                     CPLBase64Encode(nLen, (const GByte *)pszUnescaped);
     626             : 
     627          11 :                 if (pszBase64 == NULL)
     628             :                 {
     629           0 :                     NITFDESDeaccess(psDes);
     630           0 :                     CPLDestroyXMLNode(psDesNode);
     631           0 :                     CPLFree(pszMDname);
     632           0 :                     CPLFree(pszUnescaped);
     633           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     634             :                              "NITF DES data could not be encoded");
     635           0 :                     return NULL;
     636             :                 }
     637             : 
     638          11 :                 CPLXMLNode *psChild = NITFCreateXMLDesDataFields(
     639             :                     psFile, psDes, (GByte *)pszUnescaped, nLen, bValidate,
     640             :                     pbGotError);
     641          11 :                 if (psChild)
     642             :                 {
     643           1 :                     CPLAddXMLAttributeAndValue(psFieldNode, "value", pszBase64);
     644           1 :                     CPLAddXMLChild(psFieldNode, psChild);
     645             :                 }
     646          10 :                 else if (bIsXML_DATA_CONTENT)
     647             :                 {
     648           2 :                     CPLXMLNode *psXML = CPLParseXMLString(pszUnescaped);
     649           2 :                     if (psXML)
     650             :                     {
     651           1 :                         CPLXMLNode *psXMLContent = CPLCreateXMLNode(
     652             :                             psFieldNode, CXT_Element, "xml_content");
     653           1 :                         CPLAddXMLChild(psXMLContent, psXML);
     654             :                     }
     655             :                     else
     656             :                     {
     657           1 :                         CPLAddXMLAttributeAndValue(psFieldNode, "value",
     658             :                                                    pszBase64);
     659             :                     }
     660             :                 }
     661             :                 else
     662             :                 {
     663           8 :                     CPLAddXMLAttributeAndValue(psFieldNode, "value", pszBase64);
     664             :                 }
     665             : 
     666          11 :                 CPLFree(pszBase64);
     667          11 :                 CPLFree(pszUnescaped);
     668             :             }
     669             :             else
     670             :             {
     671         200 :                 CPLAddXMLAttributeAndValue(psFieldNode, "value", pszMDval);
     672             :             }
     673             : 
     674         219 :             CPLFree(pszMDname);
     675             :         }
     676             : 
     677         230 :         ++papszTmp;
     678             :     }
     679             : 
     680          11 :     NITFDESDeaccess(psDes);
     681             : 
     682          11 :     return psDesNode;
     683             : }
     684             : 
     685             : #undef GetMD

Generated by: LCOV version 1.14