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: 2013-03-30 Functions: 23 22 95.7 %

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

Generated by: LCOV version 1.7