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: 2024-11-21 22:18:42 Functions: 5 7 71.4 %

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

Generated by: LCOV version 1.14