LCOV - code coverage report
Current view: directory - frmts/nitf - nitffile.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1188 1001 84.3 %
Date: 2011-12-18 Functions: 23 22 95.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $
       3                 :  *
       4                 :  * Project:  NITF Read/Write Library
       5                 :  * Purpose:  Module responsible for opening NITF file, populating NITFFile
       6                 :  *           structure, and instantiating segment specific access objects.
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  **********************************************************************
      10                 :  * Copyright (c) 2002, Frank Warmerdam
      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 "nitflib.h"
      32                 : #include "cpl_vsi.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : 
      36                 : CPL_CVSID("$Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $");
      37                 : 
      38                 : static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
      39                 :                             vsi_l_offset nOffsetTRE, 
      40                 :                             int *pnOffset,
      41                 :                             char **papszOptions );
      42                 : static int NITFWriteTREsFromOptions(
      43                 :     VSILFILE* fp,
      44                 :     vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
      45                 :     int *pnOffset,
      46                 :     char **papszOptions,
      47                 :     const char* pszTREPrefix);
      48                 : 
      49                 : static int 
      50                 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLenSize, int nOffset,
      51                 :                         const char szType[3],
      52                 :                         int nHeaderLenSize, int nDataLenSize, 
      53                 :                         GUIntBig *pnNextData );
      54                 : 
      55                 : /************************************************************************/
      56                 : /*                              NITFOpen()                              */
      57                 : /************************************************************************/
      58                 : 
      59             589 : NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
      60                 : 
      61                 : {
      62                 :     VSILFILE  *fp;
      63                 :     char        *pachHeader;
      64                 :     NITFFile    *psFile;
      65                 :     int         nHeaderLen, nOffset, nHeaderLenOffset;
      66                 :     GUIntBig    nNextData;
      67                 :     char        szTemp[128], achFSDWNG[6];
      68                 :     GIntBig     currentPos;
      69             589 :     int         bTriedStreamingFileHeader = FALSE;
      70                 : 
      71                 : /* -------------------------------------------------------------------- */
      72                 : /*      Open the file.                                                  */
      73                 : /* -------------------------------------------------------------------- */
      74             589 :     if( bUpdatable )
      75             211 :         fp = VSIFOpenL( pszFilename, "r+b" );
      76                 :     else
      77             378 :         fp = VSIFOpenL( pszFilename, "rb" );
      78                 : 
      79             589 :     if( fp == NULL )
      80                 :     {
      81               0 :         CPLError( CE_Failure, CPLE_OpenFailed, 
      82                 :                   "Failed to open file %s.", 
      83                 :                   pszFilename );
      84               0 :         return NULL;
      85                 :     }
      86                 : 
      87                 : /* -------------------------------------------------------------------- */
      88                 : /*      Check file type.                                                */
      89                 : /* -------------------------------------------------------------------- */
      90             589 :     VSIFReadL( szTemp, 1, 9, fp );
      91                 : 
      92             589 :     if( !EQUALN(szTemp,"NITF",4) && !EQUALN(szTemp,"NSIF",4) )
      93                 :     {
      94               0 :         CPLError( CE_Failure, CPLE_AppDefined, 
      95                 :                   "The file %s is not an NITF file.", 
      96                 :                   pszFilename );
      97               0 :         VSIFCloseL(fp);
      98               0 :         return NULL;
      99                 :     }
     100                 : 
     101                 : /* -------------------------------------------------------------------- */
     102                 : /*      Read the FSDWNG field.                                          */
     103                 : /* -------------------------------------------------------------------- */
     104            1178 :     if( VSIFSeekL( fp, 280, SEEK_SET ) != 0 
     105            1178 :         || VSIFReadL( achFSDWNG, 1, 6, fp ) != 6 )
     106                 :     {
     107               1 :         CPLError( CE_Failure, CPLE_NotSupported, 
     108                 :                   "Unable to read FSDWNG field from NITF file.  File is either corrupt\n"
     109                 :                   "or empty." );
     110               1 :         VSIFCloseL(fp);
     111               1 :         return NULL;
     112                 :     }
     113                 : 
     114                 : /* -------------------------------------------------------------------- */
     115                 : /*      Get header length.                                              */
     116                 : /* -------------------------------------------------------------------- */
     117             597 :     if( EQUALN(szTemp,"NITF01.",7) || EQUALN(achFSDWNG,"999998",6) )
     118               9 :         nHeaderLenOffset = 394;
     119                 :     else
     120             579 :         nHeaderLenOffset = 354;
     121                 : 
     122            1176 :     if( VSIFSeekL( fp, nHeaderLenOffset, SEEK_SET ) != 0 
     123            1176 :         || VSIFReadL( szTemp, 1, 6, fp ) != 6 )
     124                 :     {
     125               2 :         CPLError( CE_Failure, CPLE_NotSupported, 
     126                 :                   "Unable to read header length from NITF file.  File is either corrupt\n"
     127                 :                   "or empty." );
     128               2 :         VSIFCloseL(fp);
     129               2 :         return NULL;
     130                 :     }
     131                 : 
     132             586 :     szTemp[6] = '\0';
     133             586 :     nHeaderLen = atoi(szTemp);
     134                 : 
     135             586 :     VSIFSeekL( fp, nHeaderLen, SEEK_SET );
     136             586 :     currentPos = VSIFTellL( fp ) ;
     137             586 :     if( nHeaderLen < nHeaderLenOffset || nHeaderLen > currentPos )
     138                 :     {
     139               1 :         CPLError( CE_Failure, CPLE_NotSupported, 
     140                 :                   "NITF Header Length (%d) seems to be corrupt.",
     141                 :                   nHeaderLen );
     142               1 :         VSIFCloseL(fp);
     143               1 :         return NULL;
     144                 :     }
     145                 : 
     146                 : /* -------------------------------------------------------------------- */
     147                 : /*      Read the whole file header.                                     */
     148                 : /* -------------------------------------------------------------------- */
     149             585 :     pachHeader = (char *) VSIMalloc(nHeaderLen);
     150             585 :     if (pachHeader == NULL)
     151                 :     {
     152               0 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     153                 :                   "Cannot allocate memory for NITF header");
     154               0 :         VSIFCloseL(fp);
     155               0 :         return NULL;
     156                 :     }
     157             585 :     VSIFSeekL( fp, 0, SEEK_SET );
     158             585 :     if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
     159                 :     {
     160               1 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     161                 :                   "Cannot read %d bytes for NITF header", (nHeaderLen));
     162               1 :         VSIFCloseL(fp);
     163               1 :         CPLFree(pachHeader);
     164               1 :         return NULL;
     165                 :     }
     166                 : 
     167                 : /* -------------------------------------------------------------------- */
     168                 : /*      Create and initialize info structure about file.                */
     169                 : /* -------------------------------------------------------------------- */
     170             584 :     psFile = (NITFFile *) CPLCalloc(sizeof(NITFFile),1);
     171             584 :     psFile->fp = fp;
     172             584 :     psFile->pachHeader = pachHeader;
     173                 : 
     174                 : retry_read_header:
     175                 : /* -------------------------------------------------------------------- */
     176                 : /*      Get version.                                                    */
     177                 : /* -------------------------------------------------------------------- */
     178             585 :     NITFGetField( psFile->szVersion, pachHeader, 0, 9 );
     179                 : 
     180                 : /* -------------------------------------------------------------------- */
     181                 : /*      Collect a variety of information as metadata.                   */
     182                 : /* -------------------------------------------------------------------- */
     183                 : #define GetMD( target, hdr, start, length, name )              \
     184                 :     NITFExtractMetadata( &(target->papszMetadata), hdr,       \
     185                 :                          start, length,                        \
     186                 :                          "NITF_" #name );
     187                 :        
     188            1188 :     if( EQUAL(psFile->szVersion,"NITF02.10") 
     189              58 :         || EQUAL(psFile->szVersion,"NSIF01.00") )
     190                 :     {
     191                 :         char szWork[100];
     192                 : 
     193             545 :         GetMD( psFile, pachHeader,   0,   9, FHDR   );
     194             545 :         GetMD( psFile, pachHeader,   9,   2, CLEVEL );
     195             545 :         GetMD( psFile, pachHeader,  11,   4, STYPE  );
     196             545 :         GetMD( psFile, pachHeader,  15,  10, OSTAID );
     197             545 :         GetMD( psFile, pachHeader,  25,  14, FDT    );
     198             545 :         GetMD( psFile, pachHeader,  39,  80, FTITLE );
     199             545 :         GetMD( psFile, pachHeader, 119,   1, FSCLAS );
     200             545 :         GetMD( psFile, pachHeader, 120,   2, FSCLSY );
     201             545 :         GetMD( psFile, pachHeader, 122,  11, FSCODE );
     202             545 :         GetMD( psFile, pachHeader, 133,   2, FSCTLH );
     203             545 :         GetMD( psFile, pachHeader, 135,  20, FSREL  );
     204             545 :         GetMD( psFile, pachHeader, 155,   2, FSDCTP );
     205             545 :         GetMD( psFile, pachHeader, 157,   8, FSDCDT );
     206             545 :         GetMD( psFile, pachHeader, 165,   4, FSDCXM );
     207             545 :         GetMD( psFile, pachHeader, 169,   1, FSDG   );
     208             545 :         GetMD( psFile, pachHeader, 170,   8, FSDGDT );
     209             545 :         GetMD( psFile, pachHeader, 178,  43, FSCLTX );
     210             545 :         GetMD( psFile, pachHeader, 221,   1, FSCATP );
     211             545 :         GetMD( psFile, pachHeader, 222,  40, FSCAUT );
     212             545 :         GetMD( psFile, pachHeader, 262,   1, FSCRSN );
     213             545 :         GetMD( psFile, pachHeader, 263,   8, FSSRDT );
     214             545 :         GetMD( psFile, pachHeader, 271,  15, FSCTLN );
     215             545 :         GetMD( psFile, pachHeader, 286,   5, FSCOP  );
     216             545 :         GetMD( psFile, pachHeader, 291,   5, FSCPYS );
     217             545 :         GetMD( psFile, pachHeader, 296,   1, ENCRYP );
     218            1635 :         sprintf( szWork, "%3d,%3d,%3d", 
     219             545 :                  ((GByte *)pachHeader)[297], 
     220             545 :                  ((GByte *)pachHeader)[298], 
     221             545 :                  ((GByte *)pachHeader)[299] );
     222             545 :         GetMD( psFile, szWork, 0, 11, FBKGC );
     223             545 :         GetMD( psFile, pachHeader, 300,  24, ONAME  );
     224             545 :         GetMD( psFile, pachHeader, 324,  18, OPHONE );
     225             545 :         NITFGetField(szTemp, pachHeader, 342, 12);
     226                 :     }
     227              40 :     else if( EQUAL(psFile->szVersion,"NITF02.00") )
     228                 :     {
     229              34 :         int nCOff = 0;
     230                 : 
     231              34 :         GetMD( psFile, pachHeader,   0,   9, FHDR   );
     232              34 :         GetMD( psFile, pachHeader,   9,   2, CLEVEL );
     233              34 :         GetMD( psFile, pachHeader,  11,   4, STYPE  );
     234              34 :         GetMD( psFile, pachHeader,  15,  10, OSTAID );
     235              34 :         GetMD( psFile, pachHeader,  25,  14, FDT    );
     236              34 :         GetMD( psFile, pachHeader,  39,  80, FTITLE );
     237              34 :         GetMD( psFile, pachHeader, 119,   1, FSCLAS );
     238              34 :         GetMD( psFile, pachHeader, 120,  40, FSCODE );
     239              34 :         GetMD( psFile, pachHeader, 160,  40, FSCTLH );
     240              34 :         GetMD( psFile, pachHeader, 200,  40, FSREL  );
     241              34 :         GetMD( psFile, pachHeader, 240,  20, FSCAUT );
     242              34 :         GetMD( psFile, pachHeader, 260,  20, FSCTLN );
     243              34 :         GetMD( psFile, pachHeader, 280,   6, FSDWNG );
     244              34 :         if( EQUALN(pachHeader+280,"999998",6) )
     245                 :         {
     246               2 :             GetMD( psFile, pachHeader, 286,  40, FSDEVT );
     247               2 :             nCOff += 40;
     248                 :         }
     249              34 :         GetMD( psFile, pachHeader, 286+nCOff,   5, FSCOP  );
     250              34 :         GetMD( psFile, pachHeader, 291+nCOff,   5, FSCPYS );
     251              34 :         GetMD( psFile, pachHeader, 296+nCOff,   1, ENCRYP );
     252              34 :         GetMD( psFile, pachHeader, 297+nCOff,  27, ONAME  );
     253              34 :         GetMD( psFile, pachHeader, 324+nCOff,  18, OPHONE );
     254              34 :         NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
     255                 :     }
     256                 : 
     257            1169 :     if (!bTriedStreamingFileHeader &&
     258             584 :          EQUAL(szTemp, "999999999999"))
     259                 :     {
     260                 :         GUIntBig nFileSize;
     261                 :         GByte abyDELIM2_L2[12];
     262                 :         GByte abyL1_DELIM1[11];
     263                 : 
     264               1 :         bTriedStreamingFileHeader = TRUE;
     265               1 :         CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
     266                 : 
     267               1 :         VSIFSeekL( fp, 0, SEEK_END );
     268               1 :         nFileSize = VSIFTellL(fp);
     269                 : 
     270               1 :         VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
     271               1 :         abyDELIM2_L2[11] = '\0';
     272                 : 
     273               5 :         if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
     274               2 :             abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
     275               2 :             abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
     276                 :         {
     277               1 :             int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
     278               1 :             if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
     279                 :             {
     280               1 :                 VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
     281                 : 
     282               6 :                 if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
     283               2 :                      abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
     284               2 :                      abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
     285               1 :                      memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
     286                 :                 {
     287               1 :                     if (SFHL2 == nHeaderLen)
     288                 :                     {
     289               1 :                         CSLDestroy(psFile->papszMetadata);
     290               1 :                         psFile->papszMetadata = NULL;
     291                 : 
     292               1 :                         if ( (int)VSIFReadL( pachHeader, 1, SFHL2, fp ) != SFHL2 )
     293                 :                         {
     294               0 :                             VSIFCloseL(fp);
     295               0 :                             CPLFree(pachHeader);
     296               0 :                             CPLFree(psFile);
     297               0 :                             return NULL;
     298                 :                         }
     299                 : 
     300               1 :                         goto retry_read_header;
     301                 :                     }
     302                 :                 }
     303                 :             }
     304                 :         }
     305                 :     }
     306                 : 
     307                 : /* -------------------------------------------------------------------- */
     308                 : /*      Collect segment info for the types we care about.               */
     309                 : /* -------------------------------------------------------------------- */
     310             584 :     nNextData = nHeaderLen;
     311                 : 
     312             584 :     nOffset = nHeaderLenOffset + 6;
     313                 : 
     314             584 :     nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
     315                 : 
     316             584 :     if (nOffset != -1)
     317             580 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
     318                 : 
     319                 :     /* LA Called NUMX in NITF 2.1 */
     320             584 :     if (nOffset != -1)
     321             580 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
     322                 : 
     323             584 :     if (nOffset != -1)
     324             580 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
     325                 : 
     326             584 :     if (nOffset != -1)
     327             580 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
     328                 : 
     329             584 :     if (nOffset != -1)
     330             580 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
     331                 :     else
     332                 :     {
     333               4 :         NITFClose(psFile);
     334               4 :         return NULL;
     335                 :     }
     336                 : 
     337                 : /* -------------------------------------------------------------------- */
     338                 : /*      Is there User Define Header Data? (TREs)                        */
     339                 : /* -------------------------------------------------------------------- */
     340             580 :     if (nHeaderLen < nOffset + 5)
     341                 :     {
     342               1 :         CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     343               1 :         NITFClose(psFile);
     344               1 :         return NULL;
     345                 :     }
     346                 : 
     347             579 :     psFile->nTREBytes = 
     348             579 :         atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
     349             579 :     if (psFile->nTREBytes < 0)
     350                 :     {
     351               1 :         CPLError(CE_Failure, CPLE_AppDefined,
     352                 :                  "Invalid TRE size : %d", psFile->nTREBytes);
     353               1 :         NITFClose(psFile);
     354               1 :         return NULL;
     355                 :     }
     356             578 :     nOffset += 5;
     357                 : 
     358             578 :     if( psFile->nTREBytes == 3 )
     359                 :     {
     360               0 :         nOffset += 3; /* UDHOFL */
     361               0 :         psFile->nTREBytes = 0;
     362                 :     }
     363             578 :     else if( psFile->nTREBytes > 3 )
     364                 :     {
     365              28 :         nOffset += 3; /* UDHOFL */
     366              28 :         psFile->nTREBytes -= 3;
     367                 : 
     368              28 :         if (nHeaderLen < nOffset + psFile->nTREBytes)
     369                 :         {
     370               0 :             CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     371               0 :             NITFClose(psFile);
     372               0 :             return NULL;
     373                 :         }
     374                 : 
     375              28 :         psFile->pachTRE = (char *) VSIMalloc(psFile->nTREBytes);
     376              28 :         if (psFile->pachTRE == NULL)
     377                 :         {
     378               0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     379                 :                      "Cannot allocate %d bytes", psFile->nTREBytes);
     380               0 :             NITFClose(psFile);
     381               0 :             return NULL;
     382                 :         }
     383              28 :         memcpy( psFile->pachTRE, pachHeader + nOffset, 
     384              28 :                 psFile->nTREBytes );
     385                 :     }
     386                 : 
     387                 : /* -------------------------------------------------------------------- */
     388                 : /*      Is there Extended Header Data?  (More TREs)                     */
     389                 : /* -------------------------------------------------------------------- */
     390             578 :     if( nHeaderLen > nOffset + 8 )
     391                 :     {
     392                 :         int nXHDL = 
     393              43 :             atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
     394              43 :         if (nXHDL < 0)
     395                 :         {
     396               1 :             CPLError(CE_Failure, CPLE_AppDefined,
     397                 :                     "Invalid XHDL value : %d", nXHDL);
     398               1 :             NITFClose(psFile);
     399               1 :             return NULL;
     400                 :         }
     401                 : 
     402              42 :         nOffset += 5; /* XHDL */
     403                 : 
     404              42 :         if( nXHDL > 3 )
     405                 :         {
     406                 :             char* pachNewTRE;
     407                 : 
     408              14 :             nOffset += 3; /* XHDLOFL */
     409              14 :             nXHDL -= 3;
     410                 : 
     411              14 :             if (nHeaderLen < nOffset + nXHDL)
     412                 :             {
     413               1 :                 CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     414               1 :                 NITFClose(psFile);
     415               1 :                 return NULL;
     416                 :             }
     417                 : 
     418              26 :             pachNewTRE = (char *) 
     419              13 :                 VSIRealloc( psFile->pachTRE, 
     420              13 :                             psFile->nTREBytes + nXHDL );
     421              13 :             if (pachNewTRE == NULL)
     422                 :             {
     423               0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     424                 :                      "Cannot allocate %d bytes", psFile->nTREBytes + nXHDL);
     425               0 :                 NITFClose(psFile);
     426               0 :                 return NULL;
     427                 :             }
     428              13 :             psFile->pachTRE = pachNewTRE;
     429              13 :             memcpy( psFile->pachTRE, pachHeader + nOffset, nXHDL );
     430              13 :             psFile->nTREBytes += nXHDL;
     431                 :         }
     432                 :     }
     433                 : 
     434             576 :     return psFile;
     435                 : }
     436                 : 
     437                 : /************************************************************************/
     438                 : /*                             NITFClose()                              */
     439                 : /************************************************************************/
     440                 : 
     441             584 : void NITFClose( NITFFile *psFile )
     442                 : 
     443                 : {
     444                 :     int  iSegment;
     445                 : 
     446            6915 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
     447                 :     {
     448            6331 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
     449                 : 
     450            6331 :         if( psSegInfo->hAccess == NULL )
     451            1755 :             continue;
     452                 : 
     453            4576 :         if( EQUAL(psSegInfo->szSegmentType,"IM"))
     454            4576 :             NITFImageDeaccess( (NITFImage *) psSegInfo->hAccess );
     455               0 :         else if( EQUAL(psSegInfo->szSegmentType,"DE"))
     456               0 :             NITFDESDeaccess( (NITFDES *) psSegInfo->hAccess );
     457                 :         else
     458                 :         {
     459               0 :             CPLAssert( FALSE );
     460                 :         }
     461                 :     }
     462                 : 
     463             584 :     CPLFree( psFile->pasSegmentInfo );
     464             584 :     if( psFile->fp != NULL )
     465             584 :         VSIFCloseL( psFile->fp );
     466             584 :     CPLFree( psFile->pachHeader );
     467             584 :     CSLDestroy( psFile->papszMetadata );
     468             584 :     CPLFree( psFile->pachTRE );
     469                 : 
     470             584 :     if (psFile->psNITFSpecNode)
     471             546 :         CPLDestroyXMLNode(psFile->psNITFSpecNode);
     472                 : 
     473             584 :     CPLFree( psFile );
     474             584 : }
     475                 : 
     476          285562 : static void NITFGotoOffset(VSILFILE* fp, GUIntBig nLocation)
     477                 : {
     478          285562 :     GUIntBig nCurrentLocation = VSIFTellL(fp);
     479          285562 :     if (nLocation > nCurrentLocation)
     480                 :     {
     481                 :         GUIntBig nFileSize;
     482                 :         int iFill;
     483          173771 :         char cSpace = ' ';
     484                 : 
     485          173771 :         VSIFSeekL(fp, 0, SEEK_END);
     486          173771 :         nFileSize = VSIFTellL(fp);
     487          173771 :         if (nLocation > nFileSize)
     488                 :         {
     489         1318453 :             for(iFill = 0; iFill < nLocation - nFileSize; iFill++)
     490         1146920 :                 VSIFWriteL(&cSpace, 1, 1, fp);
     491                 :         }
     492                 :         else
     493            2238 :             VSIFSeekL(fp, nLocation, SEEK_SET);
     494                 :     }
     495          111791 :     else if (nLocation < nCurrentLocation)
     496                 :     {
     497            2633 :         VSIFSeekL(fp, nLocation, SEEK_SET);
     498                 :     }
     499                 : 
     500          285562 : }
     501                 : 
     502                 : /************************************************************************/
     503                 : /*                             NITFCreate()                             */
     504                 : /*                                                                      */
     505                 : /*      Create a new uncompressed NITF file.                            */
     506                 : /************************************************************************/
     507                 : 
     508             210 : int NITFCreate( const char *pszFilename, 
     509                 :                       int nPixels, int nLines, int nBands, 
     510                 :                       int nBitsPerSample, const char *pszPVType,
     511                 :                       char **papszOptions )
     512                 : 
     513                 : {
     514                 :     VSILFILE  *fp;
     515             210 :     GUIntBig    nCur = 0;
     516             210 :     int         nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
     517                 :     GIntBig     nImageSize;
     518                 :     int         nNBPR, nNBPC;
     519                 :     const char *pszIREP;
     520             210 :     const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
     521                 :     int nCLevel;
     522                 :     const char *pszNUMT;
     523             210 :     int nHL, nNUMT = 0;
     524                 :     int nUDIDLOffset;
     525                 :     const char *pszVersion;
     526             210 :     int iIM, nIM = 1;
     527                 :     const char *pszNUMI;
     528             210 :     int iGS, nGS = 0; // number of graphic segment
     529                 :     const char *pszNUMS; // graphic segment option string
     530                 : 
     531             210 :     if (nBands <= 0 || nBands > 99999)
     532                 :     {
     533               2 :         CPLError(CE_Failure, CPLE_NotSupported,
     534                 :                  "Invalid band number : %d", nBands);
     535               2 :         return FALSE;
     536                 :     }
     537                 : 
     538             208 :     if( pszIC == NULL )
     539             198 :         pszIC = "NC";
     540                 : 
     541                 : /* -------------------------------------------------------------------- */
     542                 : /*      Fetch some parameter overrides.                                 */
     543                 : /* -------------------------------------------------------------------- */
     544             208 :     pszIREP = CSLFetchNameValue( papszOptions, "IREP" );
     545             208 :     if( pszIREP == NULL )
     546             161 :         pszIREP = "MONO";
     547                 : 
     548             208 :     pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
     549             208 :     if( pszNUMT != NULL )
     550                 :     {
     551               5 :         nNUMT = atoi(pszNUMT);
     552               5 :         if (nNUMT < 0 || nNUMT > 999)
     553                 :         {
     554               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     555                 :                     "Invalid NUMT value : %s", pszNUMT);
     556               1 :             return FALSE;
     557                 :         }
     558                 :     }
     559                 : 
     560             207 :     pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
     561             207 :     if (pszNUMI != NULL)
     562                 :     {
     563               4 :         nIM = atoi(pszNUMI);
     564               4 :         if (nIM < 1 || nIM > 999)
     565                 :         {
     566               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     567                 :                     "Invalid NUMI value : %s", pszNUMI);
     568               1 :             return FALSE;
     569                 :         }
     570               3 :         if (nIM != 1 && !EQUAL(pszIC, "NC"))
     571                 :         {
     572               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     573                 :                     "Unable to create file with multiple images and compression at the same time");
     574               1 :             return FALSE;
     575                 :         }
     576                 :     }
     577                 :     
     578                 :     // Reads and validates graphics segment number option
     579             205 :     pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
     580             205 :     if (pszNUMS != NULL)
     581                 :     {
     582               9 :         nGS = atoi(pszNUMS);
     583               9 :         if (nGS < 0 || nGS > 999)
     584                 :         {
     585               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
     586                 :                             pszNUMS);
     587               1 :             return FALSE;
     588                 :         }
     589                 :     }
     590                 : 
     591                 : 
     592                 : 
     593                 : /* -------------------------------------------------------------------- */
     594                 : /*      Compute raw image size, blocking factors and so forth.          */
     595                 : /* -------------------------------------------------------------------- */
     596             204 :     nNPPBH = nPixels;
     597             204 :     nNPPBV = nLines;
     598                 : 
     599             204 :     if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
     600               4 :         nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
     601                 : 
     602             204 :     if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
     603               6 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
     604                 : 
     605             204 :     if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
     606               4 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
     607                 :     
     608             204 :     if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
     609               0 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
     610                 :     
     611             204 :     if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
     612               0 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
     613                 :         
     614                 :         
     615             208 :     if (EQUAL(pszIC, "NC") &&
     616                 :         (nPixels > 8192 || nLines > 8192) && 
     617                 :         nNPPBH == nPixels && nNPPBV == nLines)
     618                 :     {
     619                 :         /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
     620               4 :         nNBPR = 1;
     621               4 :         nNBPC = 1;
     622               4 :         nNPPBH = 0;
     623               4 :         nNPPBV = 0;
     624                 :         
     625               4 :         nImageSize = 
     626               8 :             ((nBitsPerSample)/8) 
     627               4 :             * ((GIntBig) nPixels *nLines)
     628               8 :             * nBands;
     629                 :     }
     630             200 :     else if (EQUAL(pszIC, "NC") &&
     631                 :              nPixels > 8192 && nNPPBH == nPixels)
     632                 :     {
     633                 :         /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
     634               0 :         nNBPR = 1;
     635               0 :         nNPPBH = 0;
     636               0 :         nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
     637                 : 
     638               0 :         if ( nNBPC > 9999 )
     639                 :         {
     640               0 :             CPLError( CE_Failure, CPLE_AppDefined,
     641                 :                       "Unable to create file %s,\n"
     642                 :                       "Too many blocks : %d x %d",
     643                 :                      pszFilename, nNBPR, nNBPC);
     644               0 :             return FALSE;
     645                 :         }
     646                 : 
     647               0 :         nImageSize =
     648               0 :             ((nBitsPerSample)/8)
     649               0 :             * ((GIntBig) nPixels * (nNBPC * nNPPBV))
     650               0 :             * nBands;
     651                 :     }
     652             201 :     else if (EQUAL(pszIC, "NC") &&
     653                 :              nLines > 8192 && nNPPBV == nLines)
     654                 :     {
     655                 :         /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
     656               1 :         nNBPC = 1;
     657               1 :         nNPPBV = 0;
     658               1 :         nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
     659                 : 
     660               1 :         if ( nNBPR > 9999 )
     661                 :         {
     662               0 :             CPLError( CE_Failure, CPLE_AppDefined,
     663                 :                       "Unable to create file %s,\n"
     664                 :                       "Too many blocks : %d x %d",
     665                 :                      pszFilename, nNBPR, nNBPC);
     666               0 :             return FALSE;
     667                 :         }
     668                 : 
     669               1 :         nImageSize =
     670               2 :             ((nBitsPerSample)/8)
     671               1 :             * ((GIntBig) nLines * (nNBPR * nNPPBH))
     672               2 :             * nBands;
     673                 :     }
     674                 :     else
     675                 :     {
     676             199 :         if( nNPPBH <= 0 || nNPPBV <= 0 ||
     677                 :             nNPPBH > 9999 || nNPPBV > 9999  )
     678               0 :             nNPPBH = nNPPBV = 256;
     679                 : 
     680             199 :         nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
     681             199 :         nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
     682             199 :         if ( nNBPR > 9999 || nNBPC > 9999 )
     683                 :         {
     684               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     685                 :                       "Unable to create file %s,\n"
     686                 :                       "Too many blocks : %d x %d",
     687                 :                      pszFilename, nNBPR, nNBPC);
     688               1 :             return FALSE;
     689                 :         }
     690                 : 
     691             198 :         nImageSize = 
     692             396 :             ((nBitsPerSample)/8) 
     693             198 :             * ((GIntBig) nNBPR * nNBPC)
     694             396 :             * nNPPBH * nNPPBV * nBands;
     695                 :     }
     696                 : 
     697             203 :     if (EQUAL(pszIC, "NC"))
     698                 :     {
     699             195 :         if ((double)nImageSize >= 1e10 - 1)
     700                 :         {
     701               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     702                 :                     "Unable to create file %s,\n"
     703                 :                     "Too big image size : " CPL_FRMT_GUIB,
     704                 :                     pszFilename, nImageSize );
     705               1 :             return FALSE;
     706                 :         }
     707             194 :         if ((double)(nImageSize * nIM) >= 1e12 - 1)
     708                 :         {
     709               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     710                 :                     "Unable to create file %s,\n"
     711                 :                     "Too big file size : " CPL_FRMT_GUIB,
     712                 :                     pszFilename, nImageSize * nIM );
     713               1 :             return FALSE;
     714                 :         }
     715                 :     }
     716                 : 
     717                 : /* -------------------------------------------------------------------- */
     718                 : /*      Open new file.                                                  */
     719                 : /* -------------------------------------------------------------------- */
     720             201 :     fp = VSIFOpenL( pszFilename, "wb+" );
     721             201 :     if( fp == NULL )
     722                 :     {
     723               3 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     724                 :                   "Unable to create file %s,\n"
     725                 :                   "check path and permissions.",
     726                 :                   pszFilename );
     727               3 :         return FALSE;
     728                 :     }
     729                 : 
     730                 : 
     731                 : /* -------------------------------------------------------------------- */
     732                 : /*      Work out the version we are producing.  For now we really       */
     733                 : /*      only support creating NITF02.10 or the nato analog              */
     734                 : /*      NSIF01.00.                                                      */
     735                 : /* -------------------------------------------------------------------- */
     736             198 :     pszVersion = CSLFetchNameValue( papszOptions, "FHDR" );
     737             198 :     if( pszVersion == NULL )
     738             192 :         pszVersion = "NITF02.10";
     739               8 :     else if( !EQUAL(pszVersion,"NITF02.10") 
     740               2 :              && !EQUAL(pszVersion,"NSIF01.00") )
     741                 :     {
     742               1 :         CPLError( CE_Warning, CPLE_AppDefined, 
     743                 :                   "FHDR=%s not supported, switching to NITF02.10.",
     744                 :                   pszVersion );
     745               1 :         pszVersion = "NITF02.10";
     746                 :     }
     747                 : 
     748                 : /* -------------------------------------------------------------------- */
     749                 : /*      Prepare the file header.                                        */
     750                 : /* -------------------------------------------------------------------- */
     751                 : 
     752                 : #define PLACE(location,name,text)  { \
     753                 :     const char* _text = text; \
     754                 :     NITFGotoOffset(fp, location); \
     755                 :     VSIFWriteL(_text, 1, strlen(_text), fp); }
     756                 : 
     757                 : #define OVR(width,location,name,text) {         \
     758                 :     const char* _text = text; \
     759                 :     const char *pszParmValue;             \
     760                 :     pszParmValue = CSLFetchNameValue( papszOptions, #name );    \
     761                 :     if( pszParmValue == NULL )            \
     762                 :         pszParmValue = _text;           \
     763                 :     NITFGotoOffset(fp, location); \
     764                 :     VSIFWriteL(pszParmValue, 1, MIN(width,strlen(pszParmValue)), fp); }
     765                 : 
     766                 : #define WRITE_BYTE(location, val) { \
     767                 :     char cVal = val; \
     768                 :     NITFGotoOffset(fp, location); \
     769                 :     VSIFWriteL(&cVal, 1, 1, fp); }
     770                 : 
     771             198 :     VSIFSeekL(fp, 0, SEEK_SET);
     772                 : 
     773             198 :     PLACE (  0, FDHR_FVER,    pszVersion                      );
     774             198 :     OVR( 2,  9, CLEVEL,       "03"                            );  /* Patched at the end */
     775             198 :     PLACE ( 11, STYPE        ,"BF01"                          );
     776             198 :     OVR(10, 15, OSTAID       ,"GDAL"                          );
     777             198 :     OVR(14, 25, FDT          ,"20021216151629"                );
     778             198 :     OVR(80, 39, FTITLE       ,""                              );
     779             198 :     OVR( 1,119, FSCLAS       ,"U"                             );
     780             198 :     OVR( 2,120, FSCLSY       ,""                              );
     781             198 :     OVR(11,122, FSCODE       ,""                              );
     782             198 :     OVR( 2,133, FSCTLH       ,""                              );
     783             198 :     OVR(20,135, FSREL        ,""                              );
     784             198 :     OVR( 2,155, FSDCTP       ,""                              );
     785             198 :     OVR( 8,157, FSDCDT       ,""                              );
     786             198 :     OVR( 4,165, FSDCXM       ,""                              );
     787             198 :     OVR( 1,169, FSDG         ,""                              );
     788             198 :     OVR( 8,170, FSDGDT       ,""                              );
     789             198 :     OVR(43,178, FSCLTX       ,""                              );
     790             198 :     OVR( 1,221, FSCATP       ,""                              );
     791             198 :     OVR(40,222, FSCAUT       ,""                              );
     792             198 :     OVR( 1,262, FSCRSN       ,""                              );
     793             198 :     OVR( 8,263, FSSRDT       ,""                              );
     794             198 :     OVR(15,271, FSCTLN       ,""                              );
     795             198 :     OVR( 5,286, FSCOP        ,"00000"                         );
     796             198 :     OVR( 5,291, FSCPYS       ,"00000"                         );
     797             198 :     PLACE (296, ENCRYP       ,"0"                             );
     798             198 :     WRITE_BYTE(297, 0x00); /* FBKGC */
     799             198 :     WRITE_BYTE(298, 0x00);
     800             198 :     WRITE_BYTE(299, 0x00);
     801             198 :     OVR(24,300, ONAME        ,""                              );
     802             198 :     OVR(18,324, OPHONE       ,""                              );
     803             198 :     PLACE (342, FL           ,"????????????"                  );
     804             198 :     PLACE (354, HL           ,"??????"                        );
     805             198 :     PLACE (360, NUMI         ,CPLSPrintf("%03d", nIM)         );
     806                 : 
     807             198 :     nHL = 363;
     808            1394 :     for(iIM=0;iIM<nIM;iIM++)
     809                 :     {
     810            1196 :         PLACE (nHL,     LISHi    ,"??????"                        );
     811            1196 :         PLACE (nHL + 6, LIi      ,CPLSPrintf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "d", nImageSize)  );
     812            1196 :         nHL += 6 + 10;
     813                 :     }
     814                 : 
     815                 :     // Creates Header entries for graphic segment
     816                 :     //    NUMS: number of segment
     817                 :     // For each segment:
     818                 :     //    LSSH[i]: subheader length (4 byte), set to be 258, the size for
     819                 :     //        minimal amount of information.
     820                 :     //    LS[i] data length (6 byte)
     821             198 :     PLACE (nHL,     NUMS         ,CPLSPrintf("%03d",nGS)        );
     822             198 :     nHL += 3; // Move three characters
     823             202 :     for (iGS = 0; iGS < nGS; iGS++)
     824                 :     {
     825               4 :         PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
     826               4 :         PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
     827               4 :         nHL += 4 + 6;
     828                 :     }
     829                 : 
     830             198 :     PLACE (nHL, NUMX         ,"000"                           );
     831             198 :     PLACE (nHL + 3, NUMT         ,CPLSPrintf("%03d",nNUMT)        );
     832                 : 
     833             198 :     PLACE (nHL + 6, LTSHnLTn     ,""                              );
     834                 : 
     835             198 :     nHL += 6 + (4+5) * nNUMT;
     836                 : 
     837             198 :     PLACE (nHL, NUMDES       ,"000"                           );
     838             198 :     nHL += 3;
     839             198 :     PLACE (nHL, NUMRES       ,"000"                           );
     840             198 :     nHL += 3;
     841             198 :     PLACE (nHL, UDHDL        ,"00000"                         );
     842             198 :     nHL += 5;
     843             198 :     PLACE (nHL, XHDL         ,"00000"                         );
     844             198 :     nHL += 5;
     845                 : 
     846             198 :     if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
     847                 :     {
     848               8 :         NITFWriteTREsFromOptions(
     849                 :             fp,
     850               4 :             nHL - 10,
     851                 :             nHL,
     852                 :             &nHL,
     853                 :             papszOptions, "FILE_TRE=" );
     854                 :     }
     855                 : 
     856             198 :     if (nHL > 999999)
     857                 :     {
     858               0 :         CPLError(CE_Failure, CPLE_AppDefined,
     859                 :                  "Too big file header length : %d", nHL);
     860               0 :         VSIFCloseL( fp );
     861               0 :         return FALSE;
     862                 :     }
     863                 : 
     864                 :     // update header length
     865             198 :     PLACE (354, HL           ,CPLSPrintf("%06d",nHL)          );
     866                 : 
     867             198 :     nCur = nHL;
     868                 : 
     869                 : /* -------------------------------------------------------------------- */
     870                 : /*      Prepare the image header.                                       */
     871                 : /* -------------------------------------------------------------------- */
     872            1394 :   for(iIM=0;iIM<nIM;iIM++)
     873                 :   {
     874            1196 :     char** papszIREPBANDTokens = NULL;
     875            1196 :     char** papszISUBCATTokens = NULL;
     876                 : 
     877            1196 :     if( CSLFetchNameValue(papszOptions,"IREPBAND") != NULL )
     878                 :     {
     879               0 :         papszIREPBANDTokens = CSLTokenizeStringComplex(
     880                 :             CSLFetchNameValue(papszOptions,"IREPBAND"), ",", 0, 0 );
     881               0 :         if( papszIREPBANDTokens != NULL && CSLCount( papszIREPBANDTokens ) != nBands)
     882                 :         {
     883               0 :             CSLDestroy(  papszIREPBANDTokens );
     884               0 :             papszIREPBANDTokens = NULL;
     885                 :         }
     886                 :     }
     887            1196 :     if( CSLFetchNameValue(papszOptions,"ISUBCAT") != NULL )
     888                 :     {
     889               0 :         papszISUBCATTokens = CSLTokenizeStringComplex(
     890                 :             CSLFetchNameValue(papszOptions,"ISUBCAT"), ",", 0, 0 );
     891               0 :         if( papszISUBCATTokens != NULL && CSLCount( papszISUBCATTokens ) != nBands)
     892                 :         {
     893               0 :             CSLDestroy( papszISUBCATTokens );
     894               0 :             papszISUBCATTokens = NULL;
     895                 :         }
     896                 :     }
     897                 : 
     898            1196 :     VSIFSeekL(fp, nCur, SEEK_SET);
     899                 : 
     900            1196 :     PLACE (nCur+  0, IM           , "IM"                           );
     901            1196 :     OVR(10,nCur+  2, IID1         , "Missing"                      );
     902            1196 :     OVR(14,nCur+ 12, IDATIM       , "20021216151629"               );
     903            1196 :     OVR(17,nCur+ 26, TGTID        , ""                             );
     904            1196 :     OVR(80,nCur+ 43, IID2         , ""                             );
     905            1196 :     OVR( 1,nCur+123, ISCLAS       , "U"                            );
     906            1196 :     OVR( 2,nCur+124, ISCLSY       , ""                             );
     907            1196 :     OVR(11,nCur+126, ISCODE       , ""                             );
     908            1196 :     OVR( 2,nCur+137, ISCTLH       , ""                             );
     909            1196 :     OVR(20,nCur+139, ISREL        , ""                             );
     910            1196 :     OVR( 2,nCur+159, ISDCTP       , ""                             );
     911            1196 :     OVR( 8,nCur+161, ISDCDT       , ""                             );
     912            1196 :     OVR( 4,nCur+169, ISDCXM       , ""                             );
     913            1196 :     OVR( 1,nCur+173, ISDG         , ""                             );
     914            1196 :     OVR( 8,nCur+174, ISDGDT       , ""                             );
     915            1196 :     OVR(43,nCur+182, ISCLTX       , ""                             );
     916            1196 :     OVR( 1,nCur+225, ISCATP       , ""                             );
     917            1196 :     OVR(40,nCur+226, ISCAUT       , ""                             );
     918            1196 :     OVR( 1,nCur+266, ISCRSN       , ""                             );
     919            1196 :     OVR( 8,nCur+267, ISSRDT       , ""                             );
     920            1196 :     OVR(15,nCur+275, ISCTLN       , ""                             );
     921            1196 :     PLACE (nCur+290, ENCRYP       , "0"                            );
     922            1196 :     OVR(42,nCur+291, ISORCE       , "Unknown"                      );
     923            1196 :     PLACE (nCur+333, NROWS        , CPLSPrintf("%08d", nLines)     );
     924            1196 :     PLACE (nCur+341, NCOLS        , CPLSPrintf("%08d", nPixels)    );
     925            1196 :     PLACE (nCur+349, PVTYPE       , pszPVType                      );
     926            1196 :     PLACE (nCur+352, IREP         , pszIREP                        );
     927            1196 :     OVR( 8,nCur+360, ICAT         , "VIS"                          );
     928            1196 :     OVR( 2,nCur+368, ABPP         , CPLSPrintf("%02d",nBitsPerSample) );
     929            1196 :     OVR( 1,nCur+370, PJUST        , "R"                            );
     930            1196 :     OVR( 1,nCur+371, ICORDS       , " "                            );
     931                 : 
     932            1196 :     nOffset = 372;
     933                 : 
     934                 :     {
     935                 :         const char *pszParmValue;
     936            1196 :         pszParmValue = CSLFetchNameValue( papszOptions, "ICORDS" );
     937            1196 :         if( pszParmValue == NULL )
     938            1147 :             pszParmValue = " ";
     939            1196 :         if( *pszParmValue != ' ' )
     940                 :         {
     941              49 :             OVR(60,nCur+nOffset, IGEOLO, ""                            );
     942              49 :             nOffset += 60;
     943                 :         }
     944                 :     }
     945                 : 
     946                 :     {
     947            1196 :         const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
     948            1196 :         if (pszICOM != NULL)
     949                 :         {
     950               1 :             int nLenICOM = strlen(pszICOM);
     951               1 :             int nICOM = (79 + nLenICOM) / 80;
     952               1 :             if (nICOM > 9)
     953                 :             {
     954               0 :                 CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
     955               0 :                 nICOM = 9;
     956                 :             }
     957               1 :             PLACE (nCur+nOffset, NICOM    , CPLSPrintf("%01d",nICOM) );
     958               1 :             VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
     959               1 :             nOffset += nICOM * 80;
     960                 :         }
     961                 :         else
     962                 :         {
     963            1195 :             PLACE (nCur+nOffset, NICOM    , "0"                            );
     964                 :         }
     965                 :     }
     966                 : 
     967            1196 :     OVR( 2,nCur+nOffset+1, IC     , "NC"                           );
     968                 : 
     969            1196 :     if( pszIC[0] != 'N' )
     970                 :     {
     971               8 :         OVR( 4,nCur+nOffset+3, COMRAT , "    "                     );
     972               8 :         nOffset += 4;
     973                 :     }
     974                 : 
     975            1196 :     if (nBands <= 9)
     976                 :     {
     977            1193 :         PLACE (nCur+nOffset+3, NBANDS , CPLSPrintf("%d",nBands)        );
     978                 :     }
     979                 :     else
     980                 :     {
     981               3 :         PLACE (nCur+nOffset+3, NBANDS , "0"        );
     982               3 :         PLACE (nCur+nOffset+4, XBANDS , CPLSPrintf("%05d",nBands)        );
     983               3 :         nOffset += 5;
     984                 :     }
     985                 : 
     986            1196 :     nOffset += 4;
     987                 : 
     988                 : /* -------------------------------------------------------------------- */
     989                 : /*      Per band info                                                   */
     990                 : /* -------------------------------------------------------------------- */
     991           72483 :     for( iBand = 0; iBand < nBands; iBand++ )
     992                 :     {
     993           71287 :         const char *pszIREPBAND = "M";
     994                 : 
     995           71287 :         if( papszIREPBANDTokens != NULL )
     996                 :         {
     997               0 :             if (strlen(papszIREPBANDTokens[iBand]) > 2)
     998                 :             {
     999               0 :                 papszIREPBANDTokens[iBand][2] = '\0';
    1000               0 :                 CPLError(CE_Warning, CPLE_NotSupported,
    1001                 :                          "Truncating IREPBAND[%d] to '%s'",
    1002               0 :                          iBand + 1, papszIREPBANDTokens[iBand]);
    1003                 :             }
    1004               0 :             pszIREPBAND = papszIREPBANDTokens[iBand];
    1005                 :         }
    1006           71287 :         else if( EQUAL(pszIREP,"RGB/LUT") )
    1007               5 :             pszIREPBAND = "LU";
    1008           71282 :         else if( EQUAL(pszIREP,"RGB") )
    1009                 :         {
    1010              13 :             if( iBand == 0 )
    1011               4 :                 pszIREPBAND = "R";
    1012               9 :             else if( iBand == 1 )
    1013               4 :                 pszIREPBAND = "G";
    1014               5 :             else if( iBand == 2 )
    1015               4 :                 pszIREPBAND = "B";
    1016                 :         }
    1017           71269 :         else if( EQUALN(pszIREP,"YCbCr",5) )
    1018                 :         {
    1019               9 :             if( iBand == 0 )
    1020               3 :                 pszIREPBAND = "Y";
    1021               6 :             else if( iBand == 1 )
    1022               3 :                 pszIREPBAND = "Cb";
    1023               3 :             else if( iBand == 2 )
    1024               3 :                 pszIREPBAND = "Cr";
    1025                 :         }
    1026                 : 
    1027           71287 :         PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND                 );
    1028                 : 
    1029           71287 :         if( papszISUBCATTokens != NULL )
    1030                 :         {
    1031               0 :             if (strlen(papszISUBCATTokens[iBand]) > 6)
    1032                 :             {
    1033               0 :                 papszISUBCATTokens[iBand][6] = '\0';
    1034               0 :                 CPLError(CE_Warning, CPLE_NotSupported,
    1035                 :                          "Truncating ISUBCAT[%d] to '%s'",
    1036               0 :                          iBand + 1, papszISUBCATTokens[iBand]);
    1037                 :             }
    1038               0 :             PLACE(nCur+nOffset+ 2, ISUBCATn, papszISUBCATTokens[iBand] );
    1039                 :         }
    1040                 : //      else
    1041                 : //          PLACE(nCur+nOffset+ 2, ISUBCATn, ""                           );
    1042                 : 
    1043           71287 :         PLACE(nCur+nOffset+ 8, IFCn  , "N"                            );
    1044                 : //      PLACE(nCur+nOffset+ 9, IMFLTn, ""                             );
    1045                 : 
    1046           71287 :         if( !EQUAL(pszIREP,"RGB/LUT") )
    1047                 :         {
    1048           71282 :             PLACE(nCur+nOffset+12, NLUTSn, "0"                        );
    1049           71282 :             nOffset += 13;
    1050                 :         }
    1051                 :         else
    1052                 :         {
    1053               5 :             int iC, nCount=256;
    1054                 : 
    1055               5 :             if( CSLFetchNameValue(papszOptions,"LUT_SIZE") != NULL )
    1056               5 :                 nCount = atoi(CSLFetchNameValue(papszOptions,"LUT_SIZE"));
    1057                 : 
    1058               5 :             if (!(nCount >= 0 && nCount <= 99999))
    1059                 :             {
    1060               1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1061                 :                          "Invalid LUT value : %d. Defaulting to 256", nCount);
    1062               1 :                 nCount = 256;
    1063                 :             }
    1064               5 :             PLACE(nCur+nOffset+12, NLUTSn, "3"                        );
    1065               5 :             PLACE(nCur+nOffset+13, NELUTn, CPLSPrintf("%05d",nCount)  );
    1066                 : 
    1067            1030 :             for( iC = 0; iC < nCount; iC++ )
    1068                 :             {
    1069            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+       0, (char) iC);
    1070            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+nCount*1, (char) iC);
    1071            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+nCount*2, (char) iC);
    1072                 :             }
    1073               5 :             nOffset += 18 + nCount*3;
    1074                 :         }
    1075                 :     }
    1076                 : 
    1077            1196 :     CSLDestroy(papszIREPBANDTokens);
    1078            1196 :     CSLDestroy(papszISUBCATTokens);
    1079                 : 
    1080                 : /* -------------------------------------------------------------------- */
    1081                 : /*      Remainder of image header info.                                 */
    1082                 : /* -------------------------------------------------------------------- */
    1083            1196 :     PLACE(nCur+nOffset+  0, ISYNC , "0"                            );
    1084                 : 
    1085                 :     /* RGB JPEG compressed NITF requires IMODE=P (see #3345) */
    1086            1199 :     if (nBands >= 3 && (EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3")))
    1087                 :     {
    1088               3 :         PLACE(nCur+nOffset+  1, IMODE , "P"                            );
    1089                 :     }
    1090                 :     else
    1091                 :     {
    1092            1193 :         PLACE(nCur+nOffset+  1, IMODE , "B"                            );
    1093                 :     }
    1094            1196 :     PLACE(nCur+nOffset+  2, NBPR  , CPLSPrintf("%04d",nNBPR)       );
    1095            1196 :     PLACE(nCur+nOffset+  6, NBPC  , CPLSPrintf("%04d",nNBPC)       );
    1096            1196 :     PLACE(nCur+nOffset+ 10, NPPBH , CPLSPrintf("%04d",nNPPBH)      );
    1097            1196 :     PLACE(nCur+nOffset+ 14, NPPBV , CPLSPrintf("%04d",nNPPBV)      );
    1098            1196 :     PLACE(nCur+nOffset+ 18, NBPP  , CPLSPrintf("%02d",nBitsPerSample) );
    1099            1196 :     PLACE(nCur+nOffset+ 20, IDLVL , "001"                          );
    1100            1196 :     PLACE(nCur+nOffset+ 23, IALVL , "000"                          );
    1101            1196 :     PLACE(nCur+nOffset+ 26, ILOC  , "0000000000"                   );
    1102            1196 :     PLACE(nCur+nOffset+ 36, IMAG  , "1.0 "                         );
    1103            1196 :     PLACE(nCur+nOffset+ 40, UDIDL , "00000"                        );
    1104            1196 :     PLACE(nCur+nOffset+ 45, IXSHDL, "00000"                        );
    1105                 : 
    1106            1196 :     nUDIDLOffset = nOffset + 40;
    1107            1196 :     nOffset += 50;
    1108                 : 
    1109                 : /* -------------------------------------------------------------------- */
    1110                 : /*      Add BLOCKA TRE if requested.                                    */
    1111                 : /* -------------------------------------------------------------------- */
    1112            1196 :     if( CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL )
    1113                 :     {
    1114               3 :         NITFWriteBLOCKA( fp,
    1115                 :                          nCur + (GUIntBig)nUDIDLOffset, 
    1116                 :                          nCur + (GUIntBig)nOffset, 
    1117                 :                          &nOffset, 
    1118                 :                          papszOptions );
    1119                 :     }
    1120                 : 
    1121            1196 :     if( CSLFetchNameValue(papszOptions,"TRE") != NULL )
    1122                 :     {
    1123              16 :         NITFWriteTREsFromOptions(
    1124                 :             fp,
    1125                 :             nCur + (GUIntBig)nUDIDLOffset, 
    1126                 :             nCur + (GUIntBig)nOffset, 
    1127                 :             &nOffset, 
    1128                 :             papszOptions, "TRE=" );
    1129                 :     }
    1130                 : 
    1131                 : /* -------------------------------------------------------------------- */
    1132                 : /*      Update the image header length in the file header.              */
    1133                 : /* -------------------------------------------------------------------- */
    1134            1196 :     nIHSize = nOffset;
    1135                 : 
    1136            1196 :     if (nIHSize > 999999)
    1137                 :     {
    1138               0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1139                 :                  "Too big image header length : %d", nIHSize);
    1140               0 :         VSIFCloseL( fp );
    1141               0 :         return FALSE;
    1142                 :     }
    1143                 : 
    1144            1196 :     PLACE( 363 + iIM * 16, LISH1, CPLSPrintf("%06d",nIHSize)      );
    1145                 : 
    1146            1196 :     nCur += nIHSize + nImageSize;
    1147                 :   }
    1148                 : 
    1149                 : /* -------------------------------------------------------------------- */
    1150                 : /*      Compute and update CLEVEL ("complexity" level).                 */
    1151                 : /*      See: http://164.214.2.51/ntb/baseline/docs/2500b/2500b_not2.pdf */
    1152                 : /*            page 96u                                                  */
    1153                 : /* -------------------------------------------------------------------- */
    1154             198 :     nCLevel = 3;
    1155             198 :     if (nBands > 9 || nIM > 20 || nPixels > 2048 || nLines > 2048 ||
    1156                 :         nNPPBH > 2048 || nNPPBV > 2048 || nCur > 52428799 )
    1157                 :     {
    1158              10 :         nCLevel = 5;
    1159                 :     }
    1160             198 :     if (nPixels > 8192 || nLines > 8192 ||
    1161                 :         nNPPBH > 8192 || nNPPBV > 8192 || nCur > 1073741833)
    1162                 :     {
    1163               4 :         nCLevel = 6;
    1164                 :     }
    1165             198 :     if (nBands > 256 || nPixels > 65536 || nLines > 65536 ||
    1166                 :         nCur > 2147483647)
    1167                 :     {
    1168               2 :         nCLevel = 7;
    1169                 :     }
    1170             198 :     OVR( 2,  9, CLEVEL,       CPLSPrintf("%02d", nCLevel)     );
    1171                 : 
    1172                 : /* -------------------------------------------------------------------- */
    1173                 : /*      Update total file length                                        */
    1174                 : /* -------------------------------------------------------------------- */
    1175                 : 
    1176                 :     /* According to the spec, CLEVEL 7 supports up to 10,737,418,330 bytes */
    1177                 :     /* but we can support technically much more */
    1178             198 :     if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12 - 1)
    1179                 :     {
    1180               0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1181                 :                  "Too big file : " CPL_FRMT_GUIB, nCur);
    1182               0 :         VSIFCloseL( fp );
    1183               0 :         return FALSE;
    1184                 :     }
    1185                 : 
    1186             198 :     PLACE( 342, FL,
    1187                 :           CPLSPrintf( "%012" CPL_FRMT_GB_WITHOUT_PREFIX "d", nCur) );
    1188                 : 
    1189                 : /* -------------------------------------------------------------------- */
    1190                 : /*      Grow file to full required size by writing one byte at the end. */
    1191                 : /* -------------------------------------------------------------------- */
    1192             198 :     if( EQUAL(pszIC,"NC") )
    1193                 :     {
    1194             190 :         char cNul = 0;
    1195             190 :         VSIFSeekL( fp, nCur-1, SEEK_SET );
    1196             190 :         VSIFWriteL( &cNul, 1, 1, fp );
    1197                 :     }
    1198                 : 
    1199             198 :     VSIFCloseL( fp );
    1200                 : 
    1201             198 :     return TRUE;
    1202                 : }
    1203                 : 
    1204                 : /************************************************************************/
    1205                 : /*                            NITFWriteTRE()                            */
    1206                 : /************************************************************************/
    1207                 : 
    1208              23 : static int NITFWriteTRE( VSILFILE* fp,
    1209                 :                          vsi_l_offset nOffsetUDIDL, 
    1210                 :                          vsi_l_offset nOffsetTREInHeader, 
    1211                 :                          int  *pnOffset,
    1212                 :                          const char *pszTREName, char *pabyTREData, int nTREDataSize )
    1213                 : 
    1214                 : {
    1215                 :     char szTemp[12];
    1216                 :     int  nOldOffset;
    1217                 : 
    1218                 : /* -------------------------------------------------------------------- */
    1219                 : /*      Update IXSHDL.                                                  */
    1220                 : /* -------------------------------------------------------------------- */
    1221              23 :     VSIFSeekL(fp, nOffsetUDIDL + 5, SEEK_SET);
    1222              23 :     VSIFReadL(szTemp, 1, 5, fp);
    1223              23 :     szTemp[5] = 0;
    1224              23 :     nOldOffset = atoi(szTemp);
    1225                 : 
    1226              23 :     if( nOldOffset == 0 )
    1227                 :     {
    1228              20 :         nOldOffset = 3;
    1229              20 :         PLACE(nOffsetUDIDL+10, IXSOFL, "000" );
    1230              20 :         *pnOffset += 3;
    1231                 :     }
    1232                 : 
    1233              23 :     if (nOldOffset + 11 + nTREDataSize > 99999 || nTREDataSize > 99999)
    1234                 :     {
    1235               2 :         CPLError(CE_Failure, CPLE_AppDefined, "Too big TRE to be written");
    1236               2 :         return FALSE;
    1237                 :     }
    1238                 : 
    1239              21 :     sprintf( szTemp, "%05d", nOldOffset + 11 + nTREDataSize );
    1240              21 :     PLACE( nOffsetUDIDL + 5, IXSHDL, szTemp );
    1241                 : 
    1242                 : /* -------------------------------------------------------------------- */
    1243                 : /*      Create TRE prefix.                                              */
    1244                 : /* -------------------------------------------------------------------- */
    1245              21 :     sprintf( szTemp, "%-6s%05d", 
    1246                 :              pszTREName, nTREDataSize );
    1247              21 :     VSIFSeekL(fp, nOffsetTREInHeader + nOldOffset, SEEK_SET);
    1248              21 :     VSIFWriteL(szTemp, 11, 1, fp);
    1249              21 :     VSIFWriteL(pabyTREData, nTREDataSize, 1, fp);
    1250                 : 
    1251                 : /* -------------------------------------------------------------------- */
    1252                 : /*      Increment values.                                               */
    1253                 : /* -------------------------------------------------------------------- */
    1254              21 :     *pnOffset += nTREDataSize + 11;
    1255                 : 
    1256              21 :     return TRUE;
    1257                 : }
    1258                 : 
    1259                 : /************************************************************************/
    1260                 : /*                   NITFWriteTREsFromOptions()                         */
    1261                 : /************************************************************************/
    1262                 : 
    1263              20 : static int NITFWriteTREsFromOptions(
    1264                 :     VSILFILE* fp,
    1265                 :     vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
    1266                 :     int *pnOffset,
    1267                 :     char **papszOptions, const char* pszTREPrefix )    
    1268                 : 
    1269                 : {
    1270                 :     int bIgnoreBLOCKA = 
    1271              20 :         CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
    1272                 :     int iOption;
    1273              20 :     int nTREPrefixLen = strlen(pszTREPrefix);
    1274                 : 
    1275              20 :     if( papszOptions == NULL )
    1276               0 :         return TRUE;
    1277                 : 
    1278              68 :     for( iOption = 0; papszOptions[iOption] != NULL; iOption++ )
    1279                 :     {
    1280                 :         const char *pszEscapedContents;
    1281                 :         char *pszUnescapedContents;
    1282                 :         char *pszTREName;
    1283                 :         int  nContentLength;
    1284                 :         const char* pszSpace;
    1285                 : 
    1286              51 :         if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
    1287              28 :             continue;
    1288                 : 
    1289              23 :         if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
    1290                 :             && bIgnoreBLOCKA )
    1291               1 :             continue;
    1292                 :         
    1293                 :         /* We do no longer use CPLParseNameValue() as it removes leading spaces */
    1294                 :         /* from the value (see #3088) */
    1295              22 :         pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
    1296              22 :         if (pszSpace == NULL)
    1297                 :         {
    1298               1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1299               1 :                      "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
    1300               1 :             return FALSE;
    1301                 :         }
    1302                 :         
    1303              21 :         pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
    1304              21 :         pszTREName[MIN(6, pszSpace - (papszOptions[iOption]+nTREPrefixLen))] = '\0';
    1305              21 :         pszEscapedContents = pszSpace + 1;
    1306                 : 
    1307              21 :         pszUnescapedContents = 
    1308              21 :             CPLUnescapeString( pszEscapedContents, &nContentLength,
    1309                 :                                CPLES_BackslashQuotable );
    1310                 : 
    1311              21 :         if( !NITFWriteTRE( fp,
    1312                 :                            nOffsetUDIDL, nOffsetTRE,
    1313                 :                            pnOffset,
    1314                 :                            pszTREName, pszUnescapedContents, 
    1315                 :                            nContentLength ) )
    1316                 :         {
    1317               2 :             CPLFree( pszTREName );
    1318               2 :             CPLFree( pszUnescapedContents );
    1319               2 :             return FALSE;
    1320                 :         }
    1321                 :         
    1322              19 :         CPLFree( pszTREName );
    1323              19 :         CPLFree( pszUnescapedContents );
    1324                 : 
    1325                 :     }
    1326                 : 
    1327              17 :     return TRUE;
    1328                 : }
    1329                 : 
    1330                 : /************************************************************************/
    1331                 : /*                          NITFWriteBLOCKA()                           */
    1332                 : /************************************************************************/
    1333                 : 
    1334               3 : static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
    1335                 :                             vsi_l_offset nOffsetTRE, 
    1336                 :                             int *pnOffset,
    1337                 :                             char **papszOptions )
    1338                 : 
    1339                 : {
    1340                 :     static const char *apszFields[] = { 
    1341                 :         "BLOCK_INSTANCE", "0", "2",
    1342                 :         "N_GRAY",         "2", "5",
    1343                 :         "L_LINES",        "7", "5",
    1344                 :         "LAYOVER_ANGLE",  "12", "3",
    1345                 :         "SHADOW_ANGLE",   "15", "3",
    1346                 :         "BLANKS",         "18", "16",
    1347                 :         "FRLC_LOC",       "34", "21",
    1348                 :         "LRLC_LOC",       "55", "21",
    1349                 :         "LRFC_LOC",       "76", "21",
    1350                 :         "FRFC_LOC",       "97", "21",
    1351                 :         NULL,             NULL, NULL };
    1352                 :     int nBlockCount = 
    1353               3 :         atoi(CSLFetchNameValue( papszOptions, "BLOCKA_BLOCK_COUNT" ));
    1354                 :     int iBlock;
    1355                 : 
    1356                 : /* ==================================================================== */
    1357                 : /*      Loop over all the blocks we have metadata for.                  */
    1358                 : /* ==================================================================== */
    1359               5 :     for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
    1360                 :     {
    1361                 :         char szBLOCKA[123];
    1362                 :         int iField;
    1363                 : 
    1364                 : /* -------------------------------------------------------------------- */
    1365                 : /*      Write all fields.                                               */
    1366                 : /* -------------------------------------------------------------------- */
    1367              32 :         for( iField = 0; apszFields[iField*3] != NULL; iField++ )
    1368                 :         {
    1369                 :             char szFullFieldName[64];
    1370              30 :             int  iStart = atoi(apszFields[iField*3+1]);
    1371              30 :             int  iSize = atoi(apszFields[iField*3+2]);
    1372                 :             const char *pszValue;
    1373                 : 
    1374              30 :             sprintf( szFullFieldName, "BLOCKA_%s_%02d", 
    1375              30 :                      apszFields[iField*3 + 0], iBlock );
    1376                 : 
    1377              30 :             pszValue = CSLFetchNameValue( papszOptions, szFullFieldName );
    1378              30 :             if( pszValue == NULL )
    1379              14 :                 pszValue = "";
    1380                 : 
    1381              30 :             if (strlen(pszValue) > (size_t)iSize)
    1382                 :             {
    1383               1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1384                 :                          "Too much data for %s. Got %d bytes, max allowed is %d",
    1385                 :                          szFullFieldName, (int)strlen(pszValue), iSize);
    1386               1 :                 return FALSE;
    1387                 :             }
    1388                 : 
    1389                 :             /* Right align value and left pad with spaces */
    1390              29 :             memset( szBLOCKA + iStart, ' ', iSize );
    1391              29 :             memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
    1392                 :                     pszValue, strlen(pszValue) );
    1393                 :         }
    1394                 : 
    1395                 :         // required field - semantics unknown. 
    1396               2 :         memcpy( szBLOCKA + 118, "010.0", 5);
    1397                 : 
    1398               2 :         if( !NITFWriteTRE( fp,
    1399                 :                            nOffsetUDIDL, nOffsetTRE, 
    1400                 :                            pnOffset,
    1401                 :                            "BLOCKA", szBLOCKA, 123 ) )
    1402               0 :             return FALSE;
    1403                 :     }
    1404                 :     
    1405               2 :     return TRUE;
    1406                 : }
    1407                 :                       
    1408                 : /************************************************************************/
    1409                 : /*                       NITFCollectSegmentInfo()                       */
    1410                 : /*                                                                      */
    1411                 : /*      Collect the information about a set of segments of a            */
    1412                 : /*      particular type from the NITF file header, and add them to      */
    1413                 : /*      the segment list in the NITFFile object.                        */
    1414                 : /************************************************************************/
    1415                 : 
    1416                 : static int 
    1417            3484 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLen, int nOffset, const char szType[3],
    1418                 :                         int nHeaderLenSize, int nDataLenSize, GUIntBig *pnNextData )
    1419                 : 
    1420                 : {
    1421                 :     char szTemp[12];
    1422                 :     int  nCount, nSegDefSize, iSegment;
    1423                 : 
    1424                 : /* -------------------------------------------------------------------- */
    1425                 : /*      Get the segment count, and grow the segmentinfo array           */
    1426                 : /*      accordingly.                                                    */
    1427                 : /* -------------------------------------------------------------------- */
    1428            3484 :     if ( nFileHeaderLen < nOffset + 3 )
    1429                 :     {
    1430               1 :         CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
    1431               1 :         return -1;
    1432                 :     }
    1433                 : 
    1434            3483 :     NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
    1435            3483 :     nCount = atoi(szTemp);
    1436                 : 
    1437            3483 :     if( nCount <= 0 )
    1438            2846 :         return nOffset + 3;
    1439                 : 
    1440             637 :     nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
    1441             637 :     if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
    1442                 :     {
    1443               1 :         CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
    1444               1 :         return -1;
    1445                 :     }
    1446                 : 
    1447             636 :     if( psFile->pasSegmentInfo == NULL )
    1448             582 :         psFile->pasSegmentInfo = (NITFSegmentInfo *)
    1449                 :             CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
    1450                 :     else
    1451             108 :         psFile->pasSegmentInfo = (NITFSegmentInfo *)
    1452              54 :             CPLRealloc( psFile->pasSegmentInfo, 
    1453                 :                         sizeof(NITFSegmentInfo)
    1454              54 :                         * (psFile->nSegmentCount+nCount) );
    1455                 : 
    1456                 : /* -------------------------------------------------------------------- */
    1457                 : /*      Collect detailed about segment.                                 */
    1458                 : /* -------------------------------------------------------------------- */
    1459            6967 :     for( iSegment = 0; iSegment < nCount; iSegment++ )
    1460                 :     {
    1461            6333 :         NITFSegmentInfo *psInfo = psFile->pasSegmentInfo+psFile->nSegmentCount;
    1462                 :         
    1463            6333 :         psInfo->nDLVL = -1;
    1464            6333 :         psInfo->nALVL = -1;
    1465            6333 :         psInfo->nLOC_R = -1;
    1466            6333 :         psInfo->nLOC_C = -1;
    1467            6333 :         psInfo->nCCS_R = -1;
    1468            6333 :         psInfo->nCCS_C = -1;
    1469                 : 
    1470            6333 :         psInfo->hAccess = NULL;
    1471            6333 :         strcpy( psInfo->szSegmentType, szType );
    1472                 :         
    1473            6333 :         psInfo->nSegmentHeaderSize = 
    1474            6333 :             atoi(NITFGetField(szTemp, psFile->pachHeader, 
    1475            6333 :                               nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize), 
    1476                 :                               nHeaderLenSize));
    1477            6333 :         if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
    1478                 :         {
    1479               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
    1480               1 :             return -1;
    1481                 :         }
    1482                 : 
    1483            6332 :         if (strcmp(szType, "DE") == 0 && psInfo->nSegmentHeaderSize == 207)
    1484                 :         {
    1485                 :             /* DMAAC A.TOC files have a wrong header size. It says 207 but it is 209 really */
    1486               0 :             psInfo->nSegmentHeaderSize = 209;
    1487                 :         }
    1488                 : 
    1489            6332 :         psInfo->nSegmentSize = 
    1490            6332 :             CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader, 
    1491            6332 :                               nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize) 
    1492            6332 :                               + nHeaderLenSize,
    1493                 :                               nDataLenSize), nDataLenSize);
    1494            6332 :         if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
    1495                 :         {
    1496               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
    1497               1 :             return -1;
    1498                 :         }
    1499                 : 
    1500            6331 :         psInfo->nSegmentHeaderStart = *pnNextData;
    1501            6331 :         psInfo->nSegmentStart = *pnNextData + psInfo->nSegmentHeaderSize;
    1502                 : 
    1503            6331 :         *pnNextData += (psInfo->nSegmentHeaderSize+psInfo->nSegmentSize);
    1504            6331 :         psFile->nSegmentCount++;
    1505                 :     }
    1506                 : 
    1507             634 :     return nOffset + nSegDefSize + 3;
    1508                 : }
    1509                 : 
    1510                 : /************************************************************************/
    1511                 : /*                            NITFGetField()                            */
    1512                 : /*                                                                      */
    1513                 : /*      Copy a field from a passed in header buffer into a temporary    */
    1514                 : /*      buffer and zero terminate it.                                   */
    1515                 : /************************************************************************/
    1516                 : 
    1517          911251 : char *NITFGetField( char *pszTarget, const char *pszSource, 
    1518                 :                     int nStart, int nLength )
    1519                 : 
    1520                 : {
    1521          911251 :     memcpy( pszTarget, pszSource + nStart, nLength );
    1522          911251 :     pszTarget[nLength] = '\0';
    1523                 : 
    1524          911251 :     return pszTarget;
    1525                 : }
    1526                 : 
    1527                 : /************************************************************************/
    1528                 : /*                            NITFFindTRE()                             */
    1529                 : /************************************************************************/
    1530                 : 
    1531           25182 : const char *NITFFindTRE( const char *pszTREData, int nTREBytes,
    1532                 :                          const char *pszTag, int *pnFoundTRESize )
    1533                 : 
    1534                 : {
    1535                 :     char szTemp[100];
    1536                 : 
    1537          197595 :     while( nTREBytes >= 11 )
    1538                 :     {
    1539          147373 :         int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
    1540          147373 :         if (nThisTRESize < 0)
    1541                 :         {
    1542              32 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1543              32 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
    1544                 :                      nThisTRESize, szTemp);
    1545              32 :             return NULL;
    1546                 :         }
    1547          147341 :         if (nTREBytes - 11 < nThisTRESize)
    1548                 :         {
    1549              32 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1550              32 :             if (EQUALN(szTemp, "RPFIMG",6))
    1551                 :             {
    1552                 :                 /* See #3848 */
    1553               0 :                 CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
    1554               0 :                 nThisTRESize = nTREBytes - 11;
    1555                 :             }
    1556                 :             else
    1557                 :             {
    1558              32 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1559                 :                         "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
    1560                 :                         szTemp, nTREBytes - 11, nThisTRESize);
    1561              32 :                 return NULL;
    1562                 :             }
    1563                 :         }
    1564                 : 
    1565          147309 :         if( EQUALN(pszTREData,pszTag,6) )
    1566                 :         {
    1567              78 :             if( pnFoundTRESize != NULL )
    1568              78 :                 *pnFoundTRESize = nThisTRESize;
    1569                 : 
    1570              78 :             return pszTREData + 11;
    1571                 :         }
    1572                 : 
    1573          147231 :         nTREBytes -= (nThisTRESize + 11);
    1574          147231 :         pszTREData += (nThisTRESize + 11);
    1575                 :     }
    1576                 : 
    1577           25040 :     return NULL;
    1578                 : }
    1579                 : 
    1580                 : /************************************************************************/
    1581                 : /*                     NITFFindTREByIndex()                             */
    1582                 : /************************************************************************/
    1583                 : 
    1584             560 : const char *NITFFindTREByIndex( const char *pszTREData, int nTREBytes,
    1585                 :                                 const char *pszTag, int nTreIndex,
    1586                 :                                 int *pnFoundTRESize )
    1587                 : 
    1588                 : {
    1589                 :     char szTemp[100];
    1590                 : 
    1591            1217 :     while( nTREBytes >= 11 )
    1592                 :     {
    1593             115 :         int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
    1594             115 :         if (nThisTRESize < 0)
    1595                 :         {
    1596               2 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1597               2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
    1598                 :                      nThisTRESize, szTemp);
    1599               2 :             return NULL;
    1600                 :         }
    1601             113 :         if (nTREBytes - 11 < nThisTRESize)
    1602                 :         {
    1603               2 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1604               2 :             if (EQUALN(szTemp, "RPFIMG",6))
    1605                 :             {
    1606                 :                 /* See #3848 */
    1607               0 :                 CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
    1608               0 :                 nThisTRESize = nTREBytes - 11;
    1609                 :             }
    1610                 :             else
    1611                 :             {
    1612               2 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1613                 :                         "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
    1614                 :                         szTemp, nTREBytes - 11, nThisTRESize);
    1615               2 :                 return NULL;
    1616                 :             }
    1617                 :         }
    1618                 : 
    1619             111 :         if( EQUALN(pszTREData,pszTag,6) )
    1620                 :         {
    1621              28 :             if ( nTreIndex <= 0)
    1622                 :             {
    1623              14 :                 if( pnFoundTRESize != NULL )
    1624              14 :                     *pnFoundTRESize = nThisTRESize;
    1625                 : 
    1626              14 :                 return pszTREData + 11;
    1627                 :             }
    1628                 : 
    1629                 :             /* Found a prevoius one - skip it ... */
    1630              14 :             nTreIndex--;
    1631                 :         }
    1632                 : 
    1633              97 :         nTREBytes -= (nThisTRESize + 11);
    1634              97 :         pszTREData += (nThisTRESize + 11);
    1635                 :     }
    1636                 : 
    1637             542 :     return NULL;
    1638                 : }
    1639                 : 
    1640                 : /************************************************************************/
    1641                 : /*                        NITFExtractMetadata()                         */
    1642                 : /************************************************************************/
    1643                 : 
    1644          140409 : void NITFExtractMetadata( char ***ppapszMetadata, const char *pachHeader,
    1645                 :                           int nStart, int nLength, const char *pszName )
    1646                 : 
    1647                 : {
    1648                 :     char szWork[400];
    1649                 :     char* pszWork;
    1650                 : 
    1651          140409 :     if (nLength >= sizeof(szWork) - 1)
    1652               0 :         pszWork = (char*)CPLMalloc(nLength + 1);
    1653                 :     else
    1654          140409 :         pszWork = szWork;
    1655                 : 
    1656                 :     /* trim white space */
    1657         1877273 :     while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
    1658         1596455 :         nLength--;
    1659                 : 
    1660          140409 :     memcpy( pszWork, pachHeader + nStart, nLength );
    1661          140409 :     pszWork[nLength] = '\0';
    1662                 : 
    1663          140409 :     *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, pszWork );
    1664                 : 
    1665          140409 :     if (szWork != pszWork)
    1666               0 :         CPLFree(pszWork);
    1667          140409 : }
    1668                 :                           
    1669                 : /************************************************************************/
    1670                 : /*        NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude()         */
    1671                 : /*                                                                      */
    1672                 : /*      The input is a geocentric latitude in degrees.  The output      */
    1673                 : /*      is a geodetic latitude in degrees.                              */
    1674                 : /************************************************************************/
    1675                 : 
    1676                 : /*
    1677                 :  * "The angle L' is called "geocentric latitude" and is defined as the
    1678                 :  * angle between the equatorial plane and the radius from the geocenter.
    1679                 :  * 
    1680                 :  * The angle L is called "geodetic latitude" and is defined as the angle
    1681                 :  * between the equatorial plane and the normal to the surface of the
    1682                 :  * ellipsoid.  The word "latitude" usually means geodetic latitude.  This
    1683                 :  * is the basis for most of the maps and charts we use.  The normal to the
    1684                 :  * surface is the direction that a plumb bob would hang were it not for
    1685                 :  * local anomalies in the earth's gravitational field."
    1686                 :  */
    1687                 : 
    1688               0 : double NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( double dfLat )
    1689                 : 
    1690                 : {
    1691                 :     /* WGS84 Ellipsoid */
    1692               0 :     double a = 6378137.0;
    1693               0 :     double b = 6356752.3142;
    1694               0 :     double dfPI = 3.14159265358979323;
    1695                 : 
    1696                 :     /* convert to radians */
    1697               0 :     dfLat = dfLat * dfPI / 180.0;
    1698                 : 
    1699                 :     /* convert to geodetic */
    1700               0 :     dfLat = atan( ((a*a)/(b*b)) * tan(dfLat) );
    1701                 : 
    1702                 :     /* convert back to degrees */
    1703               0 :     dfLat = dfLat * 180.0 / dfPI;
    1704                 : 
    1705               0 :     return dfLat;
    1706                 : }
    1707                 : 
    1708                 : 
    1709                 : /************************************************************************/
    1710                 : /*                        NITFGetSeriesInfo()                           */
    1711                 : /************************************************************************/
    1712                 : 
    1713                 : static const NITFSeries nitfSeries[] =
    1714                 : {
    1715                 :     { "GN", "GNC", "1:5M", "Global Navigation Chart", "CADRG"},
    1716                 :     { "JN", "JNC", "1:2M", "Jet Navigation Chart", "CADRG"},
    1717                 :     { "OH", "VHRC", "1:1M", "VFR Helicopter Route Chart", "CADRG"},
    1718                 :     { "ON", "ONC", "1:1M", "Operational Navigation Chart", "CADRG"},
    1719                 :     { "OW", "WAC", "1:1M", "High Flying Chart - Host Nation", "CADRG"},
    1720                 :     { "TP", "TPC", "1:500K", "Tactical Pilotage Chart", "CADRG"},
    1721                 :     { "LF", "LFC-FR (Day)", "1:500K", "Low Flying Chart (Day) - Host Nation", "CADRG"},
    1722                 :     { "L1", "LFC-1", "1:500K", "Low Flying Chart (TED #1)", "CADRG"},
    1723                 :     { "L2", "LFC-2", "1:500K", "Low Flying Chart (TED #2)", "CADRG"},
    1724                 :     { "L3", "LFC-3", "1:500K", "Low Flying Chart (TED #3)", "CADRG"},
    1725                 :     { "L4", "LFC-4", "1:500K", "Low Flying Chart (TED #4)", "CADRG"},
    1726                 :     { "L5", "LFC-5", "1:500K", "Low Flying Chart (TED #5)", "CADRG"},
    1727                 :     { "LN", "LN (Night)", "1:500K", "Low Flying Chart (Night) - Host Nation", "CADRG"},
    1728                 :     { "JG", "JOG", "1:250K", "Joint Operation Graphic", "CADRG"},
    1729                 :     { "JA", "JOG-A", "1:250K", "Joint Operation Graphic - Air", "CADRG"},
    1730                 :     { "JR", "JOG-R", "1:250K", "Joint Operation Graphic - Radar", "CADRG"},
    1731                 :     { "JO", "OPG", "1:250K", "Operational Planning Graphic", "CADRG"},
    1732                 :     { "VT", "VTAC", "1:250K", "VFR Terminal Area Chart", "CADRG"},
    1733                 :     { "F1", "TFC-1", "1:250K", "Transit Flying Chart (TED #1)", "CADRG"},
    1734                 :     { "F2", "TFC-2", "1:250K", "Transit Flying Chart (TED #2)", "CADRG"},
    1735                 :     { "F3", "TFC-3", "1:250K", "Transit Flying Chart (TED #3)", "CADRG"},
    1736                 :     { "F4", "TFC-4", "1:250K", "Transit Flying Chart (TED #4)", "CADRG"},
    1737                 :     { "F5", "TFC-5", "1:250K", "Transit Flying Chart (TED #5)", "CADRG"},
    1738                 :     { "AT", "ATC", "1:200K", "Series 200 Air Target Chart", "CADRG"},
    1739                 :     { "VH", "HRC", "1:125K", "Helicopter Route Chart", "CADRG"},
    1740                 :     { "TN", "TFC (Night)", "1:250K", "Transit Flying Charget (Night) - Host Nation", "CADRG"},
    1741                 :     { "TR", "TLM 200", "1:200K", "Topographic Line Map 1:200,000 scale", "CADRG"},
    1742                 :     { "TC", "TLM 100", "1:100K", "Topographic Line Map 1:100,000 scale", "CADRG"},
    1743                 :     { "RV", "Riverine", "1:50K", "Riverine Map 1:50,000 scale", "CADRG"},
    1744                 :     { "TL", "TLM 50", "1:50K", "Topographic Line Map 1:50,000 scale", "CADRG"},
    1745                 :     { "UL", "TLM 50 - Other", "1:50K", "Topographic Line Map (other 1:50,000 scale)", "CADRG"},
    1746                 :     { "TT", "TLM 25", "1:25K", "Topographic Line Map 1:25,000 scale", "CADRG"},
    1747                 :     { "TQ", "TLM 24", "1:24K", "Topographic Line Map 1:24,000 scale", "CADRG"},
    1748                 :     { "HA", "HA", "Various", "Harbor and Approach Charts", "CADRG"},
    1749                 :     { "CO", "CO", "Various", "Coastal Charts", "CADRG"},
    1750                 :     { "OA", "OPAREA", "Various", "Naval Range Operation Area Chart", "CADRG"},
    1751                 :     { "CG", "CG", "Various", "City Graphics", "CADRG"},
    1752                 :     { "C1", "CG", "1:10000", "City Graphics", "CADRG"},
    1753                 :     { "C2", "CG", "1:10560", "City Graphics", "CADRG"},
    1754                 :     { "C3", "CG", "1:11000", "City Graphics", "CADRG"},
    1755                 :     { "C4", "CG", "1:11800", "City Graphics", "CADRG"},
    1756                 :     { "C5", "CG", "1:12000", "City Graphics", "CADRG"},
    1757                 :     { "C6", "CG", "1:12500", "City Graphics", "CADRG"},
    1758                 :     { "C7", "CG", "1:12800", "City Graphics", "CADRG"},
    1759                 :     { "C8", "CG", "1:14000", "City Graphics", "CADRG"},
    1760                 :     { "C9", "CG", "1:14700", "City Graphics", "CADRG"},
    1761                 :     { "CA", "CG", "1:15000", "City Graphics", "CADRG"},
    1762                 :     { "CB", "CG", "1:15500", "City Graphics", "CADRG"},
    1763                 :     { "CC", "CG", "1:16000", "City Graphics", "CADRG"},
    1764                 :     { "CD", "CG", "1:16666", "City Graphics", "CADRG"},
    1765                 :     { "CE", "CG", "1:17000", "City Graphics", "CADRG"},
    1766                 :     { "CF", "CG", "1:17500", "City Graphics", "CADRG"},
    1767                 :     { "CH", "CG", "1:18000", "City Graphics", "CADRG"},
    1768                 :     { "CJ", "CG", "1:20000", "City Graphics", "CADRG"},
    1769                 :     { "CK", "CG", "1:21000", "City Graphics", "CADRG"},
    1770                 :     { "CL", "CG", "1:21120", "City Graphics", "CADRG"},
    1771                 :     { "CN", "CG", "1:22000", "City Graphics", "CADRG"},
    1772                 :     { "CP", "CG", "1:23000", "City Graphics", "CADRG"},
    1773                 :     { "CQ", "CG", "1:25000", "City Graphics", "CADRG"},
    1774                 :     { "CR", "CG", "1:26000", "City Graphics", "CADRG"},
    1775                 :     { "CS", "CG", "1:35000", "City Graphics", "CADRG"},
    1776                 :     { "CT", "CG", "1:36000", "City Graphics", "CADRG"},
    1777                 :     { "CM", "CM", "Various", "Combat Charts", "CADRG"},
    1778                 :     { "A1", "CM", "1:10K", "Combat Charts (1:10K)", "CADRG"},
    1779                 :     { "A2", "CM", "1:25K", "Combat Charts (1:25K)", "CADRG"},
    1780                 :     { "A3", "CM", "1:50K", "Combat Charts (1:50K)", "CADRG"},
    1781                 :     { "A4", "CM", "1:100K", "Combat Charts (1:100K)", "CADRG"},
    1782                 :     { "MI", "MIM", "1:50K", "Military Installation Maps", "CADRG"},
    1783                 :     { "M1", "MIM", "Various", "Military Installation Maps (TED #1)", "CADRG"},
    1784                 :     { "M2", "MIM", "Various", "Military Installation Maps (TED #2)", "CADRG"},
    1785                 :     { "VN", "VNC", "1:500K", "Visual Navigation Charts", "CADRG"},
    1786                 :     { "MM", "", "Various", "(Miscellaneous Maps & Charts)", "CADRG"},
    1787                 :     
    1788                 :     { "I1", "", "10m", "Imagery, 10 meter resolution", "CIB"},
    1789                 :     { "I2", "", "5m", "Imagery, 5 meter resolution", "CIB"},
    1790                 :     { "I3", "", "2m", "Imagery, 2 meter resolution", "CIB"},
    1791                 :     { "I4", "", "1m", "Imagery, 1 meter resolution", "CIB"},
    1792                 :     { "I5", "", ".5m", "Imagery, .5 (half) meter resolution", "CIB"},
    1793                 :     { "IV", "", "Various > 10m", "Imagery, greater than 10 meter resolution", "CIB"},
    1794                 :     
    1795                 :     { "D1", "", "100m", "Elevation Data from DTED level 1", "CDTED"},
    1796                 :     { "D2", "", "30m", "Elevation Data from DTED level 2", "CDTED"},
    1797                 : };
    1798                 : 
    1799                 : /* See 24111CN1.pdf paragraph 5.1.4 */
    1800             557 : const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
    1801                 : {
    1802                 :     int i;
    1803             557 :     char seriesCode[3] = {0,0,0};
    1804             557 :     if (pszFilename == NULL) return NULL;
    1805            3523 :     for (i=strlen(pszFilename)-1;i>=0;i--)
    1806                 :     {
    1807            3473 :         if (pszFilename[i] == '.')
    1808                 :         {
    1809             512 :             if (i < (int)strlen(pszFilename) - 3)
    1810                 :             {
    1811             507 :                 seriesCode[0] = pszFilename[i+1];
    1812             507 :                 seriesCode[1] = pszFilename[i+2];
    1813           38233 :                 for(i=0;i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
    1814                 :                 {
    1815           37763 :                     if (EQUAL(seriesCode, nitfSeries[i].code))
    1816                 :                     {
    1817              37 :                         return &nitfSeries[i];
    1818                 :                     }
    1819                 :                 }
    1820             470 :                 return NULL;
    1821                 :             }
    1822                 :         }
    1823                 :     }
    1824              50 :     return NULL;
    1825                 : }
    1826                 : 
    1827                 : /************************************************************************/
    1828                 : /*                       NITFCollectAttachments()                       */
    1829                 : /*                                                                      */
    1830                 : /*      Collect attachment, display level and location info into the    */
    1831                 : /*      segmentinfo structures.                                         */
    1832                 : /************************************************************************/
    1833                 : 
    1834             410 : int NITFCollectAttachments( NITFFile *psFile )
    1835                 : 
    1836                 : {
    1837                 :     int iSegment;
    1838                 : 
    1839                 : /* ==================================================================== */
    1840                 : /*      Loop over all segments.                                         */
    1841                 : /* ==================================================================== */
    1842            5551 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    1843                 :     {
    1844            5160 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
    1845                 : 
    1846                 : /* -------------------------------------------------------------------- */
    1847                 : /*      For image segments, we use the normal image access stuff.       */
    1848                 : /* -------------------------------------------------------------------- */
    1849            5160 :         if( EQUAL(psSegInfo->szSegmentType,"IM") )
    1850                 :         {
    1851            4437 :             NITFImage *psImage = NITFImageAccess( psFile, iSegment );
    1852            4437 :             if (psImage == NULL)
    1853              19 :                 return FALSE;
    1854                 :                 
    1855            4418 :             psSegInfo->nDLVL = psImage->nIDLVL;
    1856            4418 :             psSegInfo->nALVL = psImage->nIALVL;
    1857            4418 :             psSegInfo->nLOC_R = psImage->nILOCRow;
    1858            4418 :             psSegInfo->nLOC_C = psImage->nILOCColumn;
    1859                 :         }
    1860                 : /* -------------------------------------------------------------------- */
    1861                 : /*      For graphic file we need to process the header.                 */
    1862                 : /* -------------------------------------------------------------------- */
    1863            1446 :         else if( EQUAL(psSegInfo->szSegmentType,"SY")
    1864             723 :                  || EQUAL(psSegInfo->szSegmentType,"GR") )
    1865                 :         {
    1866                 :             char achSubheader[298];
    1867                 :             int  nSTYPEOffset;
    1868                 :             char szTemp[100];
    1869                 : 
    1870                 : /* -------------------------------------------------------------------- */
    1871                 : /*      Load the graphic subheader.                                     */
    1872                 : /* -------------------------------------------------------------------- */
    1873             722 :             if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart, 
    1874                 :                            SEEK_SET ) != 0 
    1875             361 :                 || VSIFReadL( achSubheader, 1, sizeof(achSubheader), 
    1876             361 :                               psFile->fp ) < 258 )
    1877                 :             {
    1878               1 :                 CPLError( CE_Warning, CPLE_FileIO, 
    1879                 :                           "Failed to read graphic subheader at " CPL_FRMT_GUIB ".", 
    1880                 :                           psSegInfo->nSegmentHeaderStart );
    1881               1 :                 continue;
    1882                 :             }
    1883                 : 
    1884                 :             // NITF 2.0. (also works for NITF 2.1)
    1885             360 :             nSTYPEOffset = 200;
    1886             360 :             if( EQUALN(achSubheader+193,"999998",6) )
    1887             318 :                 nSTYPEOffset += 40;
    1888                 : 
    1889                 : /* -------------------------------------------------------------------- */
    1890                 : /*      Report some standard info.                                      */
    1891                 : /* -------------------------------------------------------------------- */
    1892             360 :             psSegInfo->nDLVL = atoi(NITFGetField(szTemp,achSubheader,
    1893                 :                                                  nSTYPEOffset + 14, 3));
    1894             360 :             psSegInfo->nALVL = atoi(NITFGetField(szTemp,achSubheader,
    1895                 :                                                  nSTYPEOffset + 17, 3));
    1896             360 :             psSegInfo->nLOC_R = atoi(NITFGetField(szTemp,achSubheader,
    1897                 :                                                   nSTYPEOffset + 20, 5));
    1898             360 :             psSegInfo->nLOC_C = atoi(NITFGetField(szTemp,achSubheader,
    1899                 :                                                   nSTYPEOffset + 25, 5));
    1900                 :         }
    1901                 :     }
    1902                 :     
    1903             391 :     return TRUE;
    1904                 : }
    1905                 : 
    1906                 : /************************************************************************/
    1907                 : /*                      NITFReconcileAttachments()                      */
    1908                 : /*                                                                      */
    1909                 : /*      Generate the CCS location information for all the segments      */
    1910                 : /*      if possible.                                                    */
    1911                 : /************************************************************************/
    1912                 : 
    1913             418 : int NITFReconcileAttachments( NITFFile *psFile )
    1914                 : 
    1915                 : {
    1916                 :     int iSegment;
    1917             418 :     int bSuccess = TRUE;
    1918             418 :     int bMadeProgress = FALSE;
    1919                 : 
    1920            5690 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    1921                 :     {
    1922            5272 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
    1923                 :         int iOther;
    1924                 : 
    1925                 :         // already processed?
    1926            5272 :         if( psSegInfo->nCCS_R != -1 )
    1927              48 :             continue;
    1928                 : 
    1929                 :         // unattached segments are straight forward.
    1930            5224 :         if( psSegInfo->nALVL < 1 )
    1931                 :         {
    1932            5059 :             psSegInfo->nCCS_R = psSegInfo->nLOC_R;
    1933            5059 :             psSegInfo->nCCS_C = psSegInfo->nLOC_C;
    1934            5059 :             if( psSegInfo->nCCS_R != -1 )
    1935            4637 :                 bMadeProgress = TRUE;
    1936            5059 :             continue;
    1937                 :         }
    1938                 : 
    1939                 :         // Loc for segment to which we are attached.
    1940             612 :         for( iOther = 0; iOther < psFile->nSegmentCount; iOther++ )
    1941                 :         {
    1942             588 :             NITFSegmentInfo *psOtherSegInfo = psFile->pasSegmentInfo + iOther;
    1943                 :             
    1944             588 :             if( psSegInfo->nALVL == psOtherSegInfo->nDLVL )
    1945                 :             {
    1946             141 :                 if( psOtherSegInfo->nCCS_R != -1 )
    1947                 :                 {
    1948             133 :                     psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
    1949             133 :                     psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
    1950             133 :                     if ( psSegInfo->nCCS_R != -1 )
    1951             133 :                         bMadeProgress = TRUE;
    1952                 :                 }
    1953                 :                 else
    1954                 :                 {
    1955               8 :                     bSuccess = FALSE;
    1956                 :                 }
    1957             141 :                 break;
    1958                 :             }
    1959                 :         }
    1960                 : 
    1961             165 :         if( iOther == psFile->nSegmentCount )
    1962              24 :             bSuccess = FALSE;
    1963                 :     }
    1964                 : 
    1965                 : /* -------------------------------------------------------------------- */
    1966                 : /*      If succeeded or made no progress then return our success        */
    1967                 : /*      flag.  Otherwise make another pass, hopefully filling in        */
    1968                 : /*      more values.                                                    */
    1969                 : /* -------------------------------------------------------------------- */
    1970             418 :     if( bSuccess || !bMadeProgress )
    1971             410 :         return bSuccess;
    1972                 :     else
    1973               8 :         return NITFReconcileAttachments( psFile );
    1974                 : }
    1975                 : 
    1976                 : /************************************************************************/
    1977                 : /*                        NITFFindValFromEnd()                          */
    1978                 : /************************************************************************/
    1979                 : 
    1980              91 : static const char* NITFFindValFromEnd(char** papszMD,
    1981                 :                                       int nMDSize,
    1982                 :                                       const char* pszVar,
    1983                 :                                       const char* pszDefault)
    1984                 : {
    1985              91 :     int nVarLen = strlen(pszVar);
    1986              91 :     int nIter = nMDSize-1;
    1987             495 :     for(;nIter >= 0;nIter--)
    1988                 :     {
    1989             587 :         if (strncmp(papszMD[nIter], pszVar, nVarLen) == 0 &&
    1990              92 :             papszMD[nIter][nVarLen] == '=')
    1991              91 :             return papszMD[nIter] + nVarLen + 1;
    1992                 :     }
    1993               0 :     return NULL;
    1994                 : }
    1995                 : 
    1996                 : /************************************************************************/
    1997                 : /*                  NITFGenericMetadataReadTREInternal()                */
    1998                 : /************************************************************************/
    1999                 : 
    2000             244 : static char** NITFGenericMetadataReadTREInternal(char **papszMD,
    2001                 :                                                  int* pnMDSize,
    2002                 :                                                  int* pnMDAlloc,
    2003                 :                                                  CPLXMLNode* psOutXMLNode,
    2004                 :                                                  const char* pszTREName,
    2005                 :                                                  const char *pachTRE,
    2006                 :                                                  int nTRESize,
    2007                 :                                                  CPLXMLNode* psTreNode,
    2008                 :                                                  int *pnTreOffset,
    2009                 :                                                  const char* pszMDPrefix,
    2010                 :                                                  int *pbError)
    2011                 : {
    2012                 :     CPLXMLNode* psIter;
    2013            4206 :     for(psIter = psTreNode->psChild;
    2014            1859 :         psIter != NULL && *pbError == FALSE;
    2015            1859 :         psIter = psIter->psNext)
    2016                 :     {
    2017            4879 :         if (psIter->eType == CXT_Element &&
    2018            1036 :             psIter->pszValue != NULL &&
    2019            1036 :             strcmp(psIter->pszValue, "field") == 0)
    2020                 :         {
    2021             948 :             const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
    2022             948 :             const char* pszLongName = CPLGetXMLValue(psIter, "longname", NULL);
    2023             948 :             const char* pszLength = CPLGetXMLValue(psIter, "length", NULL);
    2024             948 :             int nLength = -1;
    2025             948 :             if (pszLength != NULL)
    2026             948 :                 nLength = atoi(pszLength);
    2027                 :             else
    2028                 :             {
    2029               0 :                 const char* pszLengthVar = CPLGetXMLValue(psIter, "length_var", NULL);
    2030               0 :                 if (pszLengthVar != NULL)
    2031                 :                 {
    2032               0 :                     char** papszMDIter = papszMD;
    2033               0 :                     while(papszMDIter != NULL && *papszMDIter != NULL)
    2034                 :                     {
    2035               0 :                         if (strstr(*papszMDIter, pszLengthVar) != NULL)
    2036                 :                         {
    2037               0 :                             const char* pszEqual = strchr(*papszMDIter, '=');
    2038               0 :                             if (pszEqual != NULL)
    2039                 :                             {
    2040               0 :                                 nLength = atoi(pszEqual + 1);
    2041               0 :                                 break;
    2042                 :                             }
    2043                 :                         }
    2044               0 :                         papszMDIter ++;
    2045                 :                     }
    2046                 :                 }
    2047                 :             }
    2048            1814 :             if (pszName != NULL && nLength > 0)
    2049                 :             {
    2050                 :                 char* pszMDItemName;
    2051             866 :                 char** papszTmp = NULL;
    2052                 : 
    2053             866 :                 if (*pnTreOffset + nLength > nTRESize)
    2054                 :                 {
    2055               0 :                     *pbError = TRUE;
    2056               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2057                 :                               "Not enough bytes when reading %s TRE "
    2058                 :                               "(at least %d needed, only %d available)",
    2059               0 :                               pszTREName, *pnTreOffset + nLength, nTRESize );
    2060               0 :                     break;
    2061                 :                 }
    2062                 : 
    2063             866 :                 pszMDItemName = CPLStrdup(
    2064                 :                             CPLSPrintf("%s%s", pszMDPrefix, pszName));
    2065                 : 
    2066             866 :                 NITFExtractMetadata( &papszTmp, pachTRE, *pnTreOffset,
    2067                 :                                      nLength, pszMDItemName );
    2068             866 :                 if (*pnMDSize + 1 >= *pnMDAlloc)
    2069                 :                 {
    2070              37 :                     *pnMDAlloc = (*pnMDAlloc * 4 / 3) + 32;
    2071              37 :                     papszMD = (char**)CPLRealloc(papszMD, *pnMDAlloc * sizeof(char**));
    2072                 :                 }
    2073             866 :                 papszMD[*pnMDSize] = papszTmp[0];
    2074             866 :                 papszMD[(*pnMDSize) + 1] = NULL;
    2075             866 :                 (*pnMDSize) ++;
    2076             866 :                 papszTmp[0] = NULL;
    2077             866 :                 CPLFree(papszTmp);
    2078                 : 
    2079             866 :                 if (psOutXMLNode != NULL)
    2080                 :                 {
    2081             766 :                     const char* pszVal = strchr(papszMD[(*pnMDSize) - 1], '=') + 1;
    2082                 :                     CPLXMLNode* psFieldNode;
    2083                 :                     CPLXMLNode* psNameNode;
    2084                 :                     CPLXMLNode* psValueNode;
    2085                 : 
    2086             766 :                     CPLAssert(pszVal != NULL);
    2087             766 :                     psFieldNode =
    2088             766 :                         CPLCreateXMLNode(psOutXMLNode, CXT_Element, "field");
    2089             766 :                     psNameNode =
    2090             766 :                         CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
    2091             766 :                     psValueNode =
    2092             766 :                         CPLCreateXMLNode(psFieldNode, CXT_Attribute, "value");
    2093             766 :                     CPLCreateXMLNode(psNameNode, CXT_Text,
    2094             766 :                        (pszName[0] || pszLongName == NULL) ? pszName : pszLongName);
    2095             766 :                     CPLCreateXMLNode(psValueNode, CXT_Text, pszVal);
    2096                 :                 }
    2097                 : 
    2098             866 :                 CPLFree(pszMDItemName);
    2099                 : 
    2100             866 :                 *pnTreOffset += nLength;
    2101                 :             }
    2102              82 :             else if (nLength > 0)
    2103                 :             {
    2104              82 :                 *pnTreOffset += nLength;
    2105                 :             }
    2106                 :             else
    2107                 :             {
    2108               0 :                 *pbError = TRUE;
    2109               0 :                 CPLError( CE_Warning, CPLE_AppDefined,
    2110                 :                           "Invalid item construct in %s TRE in XML ressource",
    2111                 :                           pszTREName );
    2112               0 :                 break;
    2113                 :             }
    2114                 :         }
    2115            1130 :         else if (psIter->eType == CXT_Element &&
    2116              88 :                  psIter->pszValue != NULL &&
    2117              88 :                  strcmp(psIter->pszValue, "loop") == 0)
    2118                 :         {
    2119              43 :             const char* pszCounter = CPLGetXMLValue(psIter, "counter", NULL);
    2120              43 :             const char* pszIterations = CPLGetXMLValue(psIter, "iterations", NULL);
    2121              43 :             const char* pszFormula = CPLGetXMLValue(psIter, "formula", NULL);
    2122              43 :             const char* pszMDSubPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
    2123              43 :             int nIterations = -1;
    2124                 : 
    2125              43 :             if (pszCounter != NULL)
    2126                 :             {
    2127              40 :                 char* pszMDItemName = CPLStrdup(
    2128              40 :                             CPLSPrintf("%s%s", pszMDPrefix, pszCounter));
    2129              40 :                 nIterations = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
    2130              40 :                 CPLFree(pszMDItemName);
    2131              40 :                 if (nIterations < 0)
    2132                 :                 {
    2133               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2134                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2135                 :                             "invalid 'counter' %s",
    2136                 :                             pszTREName, pszCounter );
    2137               0 :                     *pbError = TRUE;
    2138               0 :                     break;
    2139                 :                 }
    2140                 :             }
    2141               3 :             else if (pszIterations != NULL)
    2142                 :             {
    2143               0 :                 nIterations = atoi(pszIterations);
    2144                 :             }
    2145               7 :             else if (pszFormula != NULL &&
    2146               3 :                      strcmp(pszFormula, "(NPART+1)*(NPART)/2") == 0)
    2147                 :             {
    2148               1 :                 char* pszMDItemName = CPLStrdup(
    2149               1 :                             CPLSPrintf("%s%s", pszMDPrefix, "NPART"));
    2150               1 :                 int NPART = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
    2151               1 :                 CPLFree(pszMDItemName);
    2152               1 :                 if (NPART < 0)
    2153                 :                 {
    2154               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2155                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2156                 :                             "invalid 'counter' %s",
    2157                 :                             pszTREName, "NPART" );
    2158               0 :                     *pbError = TRUE;
    2159               0 :                     break;
    2160                 :                 }
    2161               1 :                 nIterations = NPART * (NPART + 1) / 2;
    2162                 :             }
    2163               5 :             else if (pszFormula != NULL &&
    2164               2 :                      strcmp(pszFormula, "(NUMOPG+1)*(NUMOPG)/2") == 0)
    2165                 :             {
    2166               1 :                 char* pszMDItemName = CPLStrdup(
    2167               1 :                             CPLSPrintf("%s%s", pszMDPrefix, "NUMOPG"));
    2168               1 :                 int NUMOPG = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
    2169               1 :                 CPLFree(pszMDItemName);
    2170               1 :                 if (NUMOPG < 0)
    2171                 :                 {
    2172               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2173                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2174                 :                             "invalid 'counter' %s",
    2175                 :                             pszTREName, "NUMOPG" );
    2176               0 :                     *pbError = TRUE;
    2177               0 :                     break;
    2178                 :                 }
    2179               1 :                 nIterations = NUMOPG * (NUMOPG + 1) / 2;
    2180                 :             }
    2181               3 :             else if (pszFormula != NULL &&
    2182               1 :                      strcmp(pszFormula, "NPAR*NPARO") == 0)
    2183                 :             {
    2184               1 :                 char* pszMDNPARName = CPLStrdup(
    2185               1 :                             CPLSPrintf("%s%s", pszMDPrefix, "NPAR"));
    2186               1 :                 int NPAR = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
    2187               1 :                 char* pszMDNPAROName = CPLStrdup(
    2188               1 :                             CPLSPrintf("%s%s", pszMDPrefix, "NPARO"));
    2189               1 :                 int NPARO= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
    2190               1 :                 CPLFree(pszMDNPARName);
    2191               1 :                 CPLFree(pszMDNPAROName);
    2192               1 :                 if (NPAR < 0)
    2193                 :                 {
    2194               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2195                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2196                 :                             "invalid 'counter' %s",
    2197                 :                             pszTREName, "NPAR" );
    2198               0 :                     *pbError = TRUE;
    2199               0 :                     break;
    2200                 :                 }
    2201               1 :                 if (NPARO < 0)
    2202                 :                 {
    2203               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2204                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2205                 :                             "invalid 'counter' %s",
    2206                 :                             pszTREName, "NPAR0" );
    2207               0 :                     *pbError = TRUE;
    2208               0 :                     break;
    2209                 :                 }
    2210               1 :                 nIterations = NPAR*NPARO;
    2211                 :             }
    2212               0 :             else if (pszFormula != NULL &&
    2213               0 :                      strcmp(pszFormula, "NPLN-1") == 0)
    2214                 :             {
    2215               0 :                 char* pszMDItemName = CPLStrdup(
    2216               0 :                             CPLSPrintf("%s%s", pszMDPrefix, "NPLN"));
    2217               0 :                 int NPLN = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
    2218               0 :                 CPLFree(pszMDItemName);
    2219               0 :                 if (NPLN < 0)
    2220                 :                 {
    2221               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2222                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2223                 :                             "invalid 'counter' %s",
    2224                 :                             pszTREName, "NPLN" );
    2225               0 :                     *pbError = TRUE;
    2226               0 :                     break;
    2227                 :                 }
    2228               0 :                 nIterations = NPLN-1;
    2229                 :             }
    2230               0 :             else if (pszFormula != NULL &&
    2231               0 :                      strcmp(pszFormula, "NXPTS*NYPTS") == 0)
    2232                 :             {
    2233               0 :                 char* pszMDNPARName = CPLStrdup(
    2234               0 :                             CPLSPrintf("%s%s", pszMDPrefix, "NXPTS"));
    2235               0 :                 int NXPTS = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
    2236               0 :                 char* pszMDNPAROName = CPLStrdup(
    2237               0 :                             CPLSPrintf("%s%s", pszMDPrefix, "NYPTS"));
    2238               0 :                 int NYPTS= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
    2239               0 :                 CPLFree(pszMDNPARName);
    2240               0 :                 CPLFree(pszMDNPAROName);
    2241               0 :                 if (NXPTS < 0)
    2242                 :                 {
    2243               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2244                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2245                 :                             "invalid 'counter' %s",
    2246                 :                             pszTREName, "NXPTS" );
    2247               0 :                     *pbError = TRUE;
    2248               0 :                     break;
    2249                 :                 }
    2250               0 :                 if (NYPTS < 0)
    2251                 :                 {
    2252               0 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2253                 :                             "Invalid loop construct in %s TRE in XML ressource : "
    2254                 :                             "invalid 'counter' %s",
    2255                 :                             pszTREName, "NYPTS" );
    2256               0 :                     *pbError = TRUE;
    2257               0 :                     break;
    2258                 :                 }
    2259               0 :                 nIterations = NXPTS*NYPTS;
    2260                 :             }
    2261                 :             else
    2262                 :             {
    2263               0 :                 CPLError( CE_Warning, CPLE_AppDefined,
    2264                 :                           "Invalid loop construct in %s TRE in XML ressource : "
    2265                 :                           "missing or invalid 'counter' or 'iterations' or 'formula'",
    2266                 :                           pszTREName );
    2267               0 :                 *pbError = TRUE;
    2268               0 :                 break;
    2269                 :             }
    2270                 : 
    2271              43 :             if (nIterations > 0)
    2272                 :             {
    2273                 :                 int iIter;
    2274                 :                 const char* pszPercent;
    2275              33 :                 int bHasValidPercentD = FALSE;
    2276              33 :                 CPLXMLNode* psRepeatedNode = NULL;
    2277              33 :                 CPLXMLNode* psLastChild = NULL;
    2278                 : 
    2279                 :                 /* Check that md_prefix has one and only %XXXXd pattern */
    2280              66 :                 if (pszMDSubPrefix != NULL &&
    2281                 :                     (pszPercent = strchr(pszMDSubPrefix, '%')) != NULL &&
    2282              33 :                     strchr(pszPercent+1,'%') == NULL)
    2283                 :                 {
    2284              33 :                     const char* pszIter = pszPercent + 1;
    2285             124 :                     while(*pszIter != '\0')
    2286                 :                     {
    2287             149 :                         if (*pszIter >= '0' && *pszIter <= '9')
    2288              58 :                             pszIter ++;
    2289              33 :                         else if (*pszIter == 'd')
    2290                 :                         {
    2291              33 :                             bHasValidPercentD = atoi(pszPercent + 1) <= 10;
    2292              33 :                             break;
    2293                 :                         }
    2294                 :                         else
    2295               0 :                             break;
    2296                 :                     }
    2297                 :                 }
    2298                 : 
    2299              33 :                 if (psOutXMLNode != NULL)
    2300                 :                 {
    2301                 :                     CPLXMLNode* psNumberNode;
    2302                 :                     CPLXMLNode* psNameNode;
    2303              33 :                     const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
    2304              33 :                     psRepeatedNode = CPLCreateXMLNode(psOutXMLNode, CXT_Element, "repeated");
    2305              33 :                     if (pszName)
    2306                 :                     {
    2307              33 :                         psNameNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "name");
    2308              33 :                         CPLCreateXMLNode(psNameNode, CXT_Text, pszName);
    2309                 :                     }
    2310              33 :                     psNumberNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "number");
    2311              33 :                     CPLCreateXMLNode(psNumberNode, CXT_Text, CPLSPrintf("%d", nIterations));
    2312                 : 
    2313              33 :                     psLastChild = psRepeatedNode->psChild;
    2314              99 :                     while(psLastChild->psNext != NULL)
    2315              33 :                         psLastChild = psLastChild->psNext;
    2316                 :                 }
    2317                 : 
    2318             247 :                 for(iIter = 0; iIter < nIterations && *pbError == FALSE; iIter++)
    2319                 :                 {
    2320             214 :                     char* pszMDNewPrefix = NULL;
    2321             214 :                     CPLXMLNode* psGroupNode = NULL;
    2322             214 :                     if (pszMDSubPrefix != NULL)
    2323                 :                     {
    2324             214 :                         if (bHasValidPercentD)
    2325                 :                         {
    2326             214 :                             char* szTmp = (char*)CPLMalloc(
    2327             214 :                                             strlen(pszMDSubPrefix) + 10 + 1);
    2328             214 :                             sprintf(szTmp, pszMDSubPrefix, iIter + 1);
    2329             214 :                             pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s",
    2330                 :                                                        pszMDPrefix, szTmp));
    2331             214 :                             CPLFree(szTmp);
    2332                 :                         }
    2333                 :                         else
    2334               0 :                             pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s%04d_",
    2335                 :                                       pszMDPrefix, pszMDSubPrefix, iIter + 1));
    2336                 :                     }
    2337                 :                     else
    2338               0 :                         pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%04d_",
    2339                 :                                                    pszMDPrefix, iIter + 1));
    2340                 : 
    2341             214 :                     if (psRepeatedNode != NULL)
    2342                 :                     {
    2343                 :                         CPLXMLNode* psIndexNode;
    2344             214 :                         psGroupNode = CPLCreateXMLNode(NULL, CXT_Element, "group");
    2345             214 :                         CPLAssert(psLastChild->psNext == NULL);
    2346             214 :                         psLastChild->psNext = psGroupNode;
    2347             214 :                         psLastChild = psGroupNode;
    2348             214 :                         psIndexNode = CPLCreateXMLNode(psGroupNode, CXT_Attribute, "index");
    2349             214 :                         CPLCreateXMLNode(psIndexNode, CXT_Text, CPLSPrintf("%d", iIter));
    2350                 :                     }
    2351                 : 
    2352             214 :                     papszMD = NITFGenericMetadataReadTREInternal(papszMD,
    2353                 :                                                                  pnMDSize,
    2354                 :                                                                  pnMDAlloc,
    2355                 :                                                                  psGroupNode,
    2356                 :                                                                  pszTREName,
    2357                 :                                                                  pachTRE,
    2358                 :                                                                  nTRESize,
    2359                 :                                                                  psIter,
    2360                 :                                                                  pnTreOffset,
    2361                 :                                                                  pszMDNewPrefix,
    2362                 :                                                                  pbError);
    2363             214 :                     CPLFree(pszMDNewPrefix);
    2364                 :                 }
    2365                 :             }
    2366                 :         }
    2367            1002 :         else if (psIter->eType == CXT_Element &&
    2368              45 :                  psIter->pszValue != NULL &&
    2369              45 :                  strcmp(psIter->pszValue, "if") == 0)
    2370                 :         {
    2371              44 :             const char* pszCond = CPLGetXMLValue(psIter, "cond", NULL);
    2372              44 :             const char* pszEqual = NULL;
    2373              47 :             if (pszCond != NULL && strcmp(pszCond, "QSS!=U AND QOD!=Y") == 0)
    2374                 :             {
    2375               3 :                 char* pszQSSName = CPLStrdup(
    2376               3 :                             CPLSPrintf("%s%s", pszMDPrefix, "QSS"));
    2377               3 :                 char* pszQODName = CPLStrdup(
    2378               3 :                             CPLSPrintf("%s%s", pszMDPrefix, "QOD"));
    2379               3 :                 const char* pszQSSVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQSSName, NULL);
    2380               3 :                 const char* pszQODVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQODName, NULL);
    2381               3 :                 if (pszQSSVal == NULL)
    2382                 :                 {
    2383               0 :                     CPLDebug("NITF", "Cannot find if cond variable %s", "QSS");
    2384                 :                 }
    2385               3 :                 else if (pszQODVal == NULL)
    2386                 :                 {
    2387               0 :                     CPLDebug("NITF", "Cannot find if cond variable %s", "QOD");
    2388                 :                 }
    2389               3 :                 else if (strcmp(pszQSSVal, "U") != 0 && strcmp(pszQODVal, "Y") != 0)
    2390                 :                 {
    2391               0 :                     papszMD = NITFGenericMetadataReadTREInternal(papszMD,
    2392                 :                                                                  pnMDSize,
    2393                 :                                                                  pnMDAlloc,
    2394                 :                                                                  psOutXMLNode,
    2395                 :                                                                  pszTREName,
    2396                 :                                                                  pachTRE,
    2397                 :                                                                  nTRESize,
    2398                 :                                                                  psIter,
    2399                 :                                                                  pnTreOffset,
    2400                 :                                                                  pszMDPrefix,
    2401                 :                                                                  pbError);
    2402                 :                 }
    2403               3 :                 CPLFree(pszQSSName);
    2404               3 :                 CPLFree(pszQODName);
    2405                 :             }
    2406              82 :             else if (pszCond != NULL && (pszEqual = strchr(pszCond, '=')) != NULL)
    2407                 :             {
    2408              41 :                 char* pszCondVar = (char*)CPLMalloc(pszEqual - pszCond + 1);
    2409              41 :                 const char* pszCondExpectedVal = pszEqual + 1;
    2410                 :                 char* pszMDItemName;
    2411                 :                 const char* pszCondVal;
    2412              41 :                 int bTestEqual = TRUE;
    2413              41 :                 memcpy(pszCondVar, pszCond, pszEqual - pszCond);
    2414              41 :                 if (pszEqual - pszCond > 1 && pszCondVar[pszEqual - pszCond - 1] == '!')
    2415                 :                 {
    2416              39 :                     bTestEqual = FALSE;
    2417              39 :                     pszCondVar[pszEqual - pszCond - 1] = '\0';
    2418                 :                 }
    2419              41 :                 pszCondVar[pszEqual - pszCond] = '\0';
    2420              41 :                 pszMDItemName = CPLStrdup(
    2421                 :                             CPLSPrintf("%s%s", pszMDPrefix, pszCondVar));
    2422              41 :                 pszCondVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, NULL);
    2423              41 :                 if (pszCondVal == NULL)
    2424                 :                 {
    2425               0 :                     CPLDebug("NITF", "Cannot find if cond variable %s",
    2426                 :                              pszMDItemName);
    2427                 :                 }
    2428              80 :                 else if ((bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) == 0) ||
    2429              39 :                          (!bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) != 0))
    2430                 :                 {
    2431               7 :                     papszMD = NITFGenericMetadataReadTREInternal(papszMD,
    2432                 :                                                                  pnMDSize,
    2433                 :                                                                  pnMDAlloc,
    2434                 :                                                                  psOutXMLNode,
    2435                 :                                                                  pszTREName,
    2436                 :                                                                  pachTRE,
    2437                 :                                                                  nTRESize,
    2438                 :                                                                  psIter,
    2439                 :                                                                  pnTreOffset,
    2440                 :                                                                  pszMDPrefix,
    2441                 :                                                                  pbError);
    2442                 :                 }
    2443              41 :                 CPLFree(pszMDItemName);
    2444              41 :                 CPLFree(pszCondVar);
    2445                 :             }
    2446                 :             else
    2447                 :             {
    2448               0 :                 CPLError( CE_Warning, CPLE_AppDefined,
    2449                 :                           "Invalid if construct in %s TRE in XML ressource : "
    2450                 :                           "missing or invalid 'cond' attribute",
    2451                 :                           pszTREName );
    2452               0 :                 *pbError = TRUE;
    2453               0 :                 break;
    2454                 :             }
    2455                 :         }
    2456             826 :         else if (psIter->eType == CXT_Element &&
    2457               1 :                  psIter->pszValue != NULL &&
    2458               1 :                  strcmp(psIter->pszValue, "if_remaining_bytes") == 0)
    2459                 :         {
    2460               1 :             if (*pnTreOffset < nTRESize)
    2461                 :             {
    2462               0 :                 papszMD = NITFGenericMetadataReadTREInternal(papszMD,
    2463                 :                                                              pnMDSize,
    2464                 :                                                              pnMDAlloc,
    2465                 :                                                              psOutXMLNode,
    2466                 :                                                              pszTREName,
    2467                 :                                                              pachTRE,
    2468                 :                                                              nTRESize,
    2469                 :                                                              psIter,
    2470                 :                                                              pnTreOffset,
    2471                 :                                                              pszMDPrefix,
    2472                 :                                                              pbError);
    2473                 :         }
    2474                 :         }
    2475                 :         else
    2476                 :         {
    2477                 :             //CPLDebug("NITF", "Unknown element : %s", psIter->pszValue ? psIter->pszValue : "null");
    2478                 :         }
    2479                 :     }
    2480             244 :     return papszMD;
    2481                 : }
    2482                 : 
    2483                 : /************************************************************************/
    2484                 : /*                      NITFGenericMetadataReadTRE()                    */
    2485                 : /************************************************************************/
    2486                 : 
    2487                 : static
    2488               8 : char **NITFGenericMetadataReadTRE(char **papszMD,
    2489                 :                                   const char* pszTREName,
    2490                 :                                   const char *pachTRE,
    2491                 :                                   int nTRESize,
    2492                 :                                   CPLXMLNode* psTreNode)
    2493                 : {
    2494               8 :     int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
    2495               8 :     int bError = FALSE;
    2496               8 :     int nTreOffset = 0;
    2497                 :     const char* pszMDPrefix;
    2498                 :     int nMDSize, nMDAlloc;
    2499                 : 
    2500               8 :     nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
    2501               8 :     nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
    2502               8 :     nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
    2503                 : 
    2504               8 :     if( (nTreLength > 0 && nTRESize != nTreLength) ||
    2505                 :         (nTreMinLength > 0 && nTRESize < nTreMinLength) )
    2506                 :     {
    2507               0 :         CPLError( CE_Warning, CPLE_AppDefined,
    2508                 :                   "%s TRE wrong size, ignoring.", pszTREName );
    2509               0 :         return papszMD;
    2510                 :     }
    2511                 : 
    2512               8 :     pszMDPrefix = CPLGetXMLValue(psTreNode, "md_prefix", "");
    2513                 : 
    2514               8 :     nMDSize = nMDAlloc = CSLCount(papszMD);
    2515                 : 
    2516               8 :     papszMD = NITFGenericMetadataReadTREInternal(papszMD,
    2517                 :                                                  &nMDSize,
    2518                 :                                                  &nMDAlloc,
    2519                 :                                                  NULL,
    2520                 :                                                  pszTREName,
    2521                 :                                                  pachTRE,
    2522                 :                                                  nTRESize,
    2523                 :                                                  psTreNode,
    2524                 :                                                  &nTreOffset,
    2525                 :                                                  pszMDPrefix,
    2526                 :                                                  &bError);
    2527                 : 
    2528               8 :     if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
    2529                 :     {
    2530               0 :         CPLError( CE_Warning, CPLE_AppDefined,
    2531                 :                   "Inconsistant declaration of %s TRE",
    2532                 :                   pszTREName );
    2533                 :     }
    2534               8 :     if (nTreOffset < nTRESize)
    2535               0 :         CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
    2536                 :                  nTRESize -nTreOffset, pszTREName);
    2537                 : 
    2538               8 :     return papszMD;
    2539                 : }
    2540                 : 
    2541                 : 
    2542                 : /************************************************************************/
    2543                 : /*                           NITFLoadXMLSpec()                          */
    2544                 : /************************************************************************/
    2545                 : 
    2546                 : #define NITF_SPEC_FILE "nitf_spec.xml"
    2547                 : 
    2548             563 : static CPLXMLNode* NITFLoadXMLSpec(NITFFile* psFile)
    2549                 : {
    2550                 : 
    2551             563 :     if (psFile->psNITFSpecNode == NULL)
    2552                 :     {
    2553             546 :         const char* pszXMLDescFilename = CPLFindFile("gdal", NITF_SPEC_FILE);
    2554             546 :         if (pszXMLDescFilename == NULL)
    2555                 :         {
    2556               0 :             CPLDebug("NITF", "Cannot find XML file : %s", NITF_SPEC_FILE);
    2557               0 :             return NULL;
    2558                 :         }
    2559             546 :         psFile->psNITFSpecNode = CPLParseXMLFile(pszXMLDescFilename);
    2560             546 :         if (psFile->psNITFSpecNode == NULL)
    2561                 :         {
    2562               0 :             CPLDebug("NITF", "Invalid XML file : %s", pszXMLDescFilename);
    2563               0 :             return NULL;
    2564                 :         }
    2565                 :     }
    2566                 : 
    2567             563 :     return psFile->psNITFSpecNode;
    2568                 : }
    2569                 : 
    2570                 : /************************************************************************/
    2571                 : /*                      NITFFindTREXMLDescFromName()                    */
    2572                 : /************************************************************************/
    2573                 : 
    2574              17 : static CPLXMLNode* NITFFindTREXMLDescFromName(NITFFile* psFile,
    2575                 :                                               const char* pszTREName)
    2576                 : {
    2577                 :     CPLXMLNode* psTreeNode;
    2578                 :     CPLXMLNode* psTresNode;
    2579                 :     CPLXMLNode* psIter;
    2580                 : 
    2581              17 :     psTreeNode = NITFLoadXMLSpec(psFile);
    2582              17 :     if (psTreeNode == NULL)
    2583               0 :         return NULL;
    2584                 : 
    2585              17 :     psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
    2586              17 :     if (psTresNode == NULL)
    2587                 :     {
    2588               0 :         CPLDebug("NITF", "Cannot find <tres> root element");
    2589               0 :         return NULL;
    2590                 :     }
    2591                 : 
    2592             286 :     for(psIter = psTresNode->psChild;psIter != NULL;psIter = psIter->psNext)
    2593                 :     {
    2594             838 :         if (psIter->eType == CXT_Element &&
    2595             277 :             psIter->pszValue != NULL &&
    2596             277 :             strcmp(psIter->pszValue, "tre") == 0)
    2597                 :         {
    2598             277 :             const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
    2599             277 :             if (pszName != NULL && strcmp(pszName, pszTREName) == 0)
    2600                 :             {
    2601              15 :                 return psIter;
    2602                 :             }
    2603                 :         }
    2604                 :     }
    2605                 : 
    2606               2 :     return NULL;
    2607                 : }
    2608                 : 
    2609                 : /************************************************************************/
    2610                 : /*                         NITFCreateXMLTre()                           */
    2611                 : /************************************************************************/
    2612                 : 
    2613              17 : CPLXMLNode* NITFCreateXMLTre(NITFFile* psFile,
    2614                 :                              const char* pszTREName,
    2615                 :                              const char *pachTRE,
    2616                 :                              int nTRESize)
    2617                 : {
    2618              17 :     int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
    2619              17 :     int bError = FALSE;
    2620              17 :     int nTreOffset = 0;
    2621                 :     CPLXMLNode* psTreNode;
    2622              17 :     CPLXMLNode* psOutXMLNode = NULL;
    2623              17 :     int nMDSize = 0, nMDAlloc = 0;
    2624                 : 
    2625              17 :     psTreNode = NITFFindTREXMLDescFromName(psFile, pszTREName);
    2626              17 :     if (psTreNode == NULL)
    2627                 :     {
    2628               2 :         if (!(EQUALN(pszTREName, "RPF", 3) || strcmp(pszTREName, "XXXXXX") == 0))
    2629                 :         {
    2630               2 :             CPLDebug("NITF", "Cannot find definition of TRE %s in %s",
    2631                 :                     pszTREName, NITF_SPEC_FILE);
    2632                 :         }
    2633               2 :         return NULL;
    2634                 :     }
    2635                 : 
    2636              15 :     nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
    2637              15 :     nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
    2638              15 :     nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
    2639                 : 
    2640              15 :     if( (nTreLength > 0 && nTRESize != nTreLength) ||
    2641                 :         (nTreMinLength > 0 && nTRESize < nTreMinLength) )
    2642                 :     {
    2643               0 :         CPLError( CE_Warning, CPLE_AppDefined,
    2644                 :                   "%s TRE wrong size, ignoring.", pszTREName );
    2645               0 :         return NULL;
    2646                 :     }
    2647                 : 
    2648              15 :     psOutXMLNode = CPLCreateXMLNode(NULL, CXT_Element, "tre");
    2649              15 :     CPLCreateXMLNode(CPLCreateXMLNode(psOutXMLNode, CXT_Attribute, "name"),
    2650                 :                      CXT_Text, pszTREName);
    2651                 : 
    2652              15 :     CSLDestroy(NITFGenericMetadataReadTREInternal(NULL,
    2653                 :                                                   &nMDSize,
    2654                 :                                                   &nMDAlloc,
    2655                 :                                                   psOutXMLNode,
    2656                 :                                                   pszTREName,
    2657                 :                                                   pachTRE,
    2658                 :                                                   nTRESize,
    2659                 :                                                   psTreNode,
    2660                 :                                                   &nTreOffset,
    2661                 :                                                   "",
    2662                 :                                                   &bError));
    2663                 : 
    2664              15 :     if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
    2665                 :     {
    2666               0 :         CPLError( CE_Warning, CPLE_AppDefined,
    2667                 :                   "Inconsistant declaration of %s TRE",
    2668                 :                   pszTREName );
    2669                 :     }
    2670              15 :     if (nTreOffset < nTRESize)
    2671               0 :         CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
    2672                 :                  nTRESize -nTreOffset, pszTREName);
    2673                 : 
    2674              15 :     return psOutXMLNode;
    2675                 : }
    2676                 : 
    2677                 : /************************************************************************/
    2678                 : /*                        NITFGenericMetadataRead()                     */
    2679                 : /*                                                                      */
    2680                 : /* Add metadata from TREs of file and image objects in the papszMD list */
    2681                 : /* pszSpecificTRE can be NULL, in which case all TREs listed in         */
    2682                 : /* data/nitf_resources.xml that have md_prefix defined will be looked   */
    2683                 : /* for. If not NULL, only the specified one will be looked for.         */
    2684                 : /************************************************************************/
    2685                 : 
    2686             546 : char **NITFGenericMetadataRead( char **papszMD,
    2687                 :                                 NITFFile* psFile,
    2688                 :                                 NITFImage *psImage,
    2689                 :                                 const char* pszSpecificTREName)
    2690                 : {
    2691             546 :     CPLXMLNode* psTreeNode = NULL;
    2692             546 :     CPLXMLNode* psTresNode = NULL;
    2693             546 :     CPLXMLNode* psIter = NULL;
    2694                 : 
    2695             546 :     if (psFile == NULL && psImage == NULL)
    2696               0 :         return papszMD;
    2697                 : 
    2698             546 :     psTreeNode = NITFLoadXMLSpec(psFile ? psFile : psImage->psFile);
    2699             546 :     if (psTreeNode == NULL)
    2700               0 :         return papszMD;
    2701                 : 
    2702             546 :     psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
    2703             546 :     if (psTresNode == NULL)
    2704                 :     {
    2705               0 :         CPLDebug("NITF", "Cannot find <tres> root element");
    2706               0 :         return papszMD;
    2707                 :     }
    2708                 : 
    2709           19656 :     for(psIter = psTresNode->psChild;psIter!=NULL;psIter = psIter->psNext)
    2710                 :     {
    2711           56238 :         if (psIter->eType == CXT_Element &&
    2712           18564 :             psIter->pszValue != NULL &&
    2713           18564 :             strcmp(psIter->pszValue, "tre") == 0)
    2714                 :         {
    2715           18564 :             const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
    2716           18564 :             const char* pszMDPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
    2717           18564 :             if (pszName != NULL && ((pszSpecificTREName == NULL && pszMDPrefix != NULL) ||
    2718               0 :                                     (pszSpecificTREName != NULL && strcmp(pszName, pszSpecificTREName) == 0)))
    2719                 :             {
    2720            3276 :                 if (psFile != NULL)
    2721                 :                 {
    2722            3276 :                     const char *pachTRE = NULL;
    2723            3276 :                     int  nTRESize = 0;
    2724                 : 
    2725            3276 :                     pachTRE = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,
    2726                 :                                            pszName, &nTRESize);
    2727            3276 :                     if( pachTRE != NULL )
    2728               0 :                         papszMD = NITFGenericMetadataReadTRE(
    2729                 :                                   papszMD, pszName, pachTRE, nTRESize, psIter);
    2730                 :                 }
    2731            3276 :                 if (psImage != NULL)
    2732                 :                 {
    2733            3276 :                     const char *pachTRE = NULL;
    2734            3276 :                     int  nTRESize = 0;
    2735                 : 
    2736            3276 :                     pachTRE = NITFFindTRE( psImage->pachTRE, psImage->nTREBytes,
    2737                 :                                            pszName, &nTRESize);
    2738            3276 :                     if( pachTRE != NULL )
    2739               8 :                        papszMD = NITFGenericMetadataReadTRE(
    2740                 :                                   papszMD, pszName, pachTRE, nTRESize, psIter);
    2741                 :                 }
    2742            3276 :                 if (pszSpecificTREName)
    2743               0 :                     break;
    2744                 :             }
    2745                 :         }
    2746                 :     }
    2747                 : 
    2748             546 :     return papszMD;
    2749                 : }

Generated by: LCOV version 1.7