LTP GCOV extension - code coverage report
Current view: directory - frmts/nitf - nitffile.c
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 729
Code covered: 93.3 % Executed lines: 680

       1                 : /******************************************************************************
       2                 :  * $Id: nitffile.c 19365 2010-04-10 19:23:30Z 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 19365 2010-04-10 19:23:30Z rouault $");
      37                 : 
      38                 : static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL, 
      39                 :                             vsi_l_offset nOffsetTRE, 
      40                 :                             int *pnOffset,
      41                 :                             char **papszOptions );
      42                 : static int NITFWriteTREsFromOptions(
      43                 :     FILE* fp,
      44                 :     vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
      45                 :     int *pnOffset,
      46                 :     char **papszOptions,
      47                 :     const char* pszTREPrefix);
      48                 : 
      49                 : static int 
      50                 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLenSize, int nOffset,
      51                 :                         const char szType[3],
      52                 :                         int nHeaderLenSize, int nDataLenSize, 
      53                 :                         GUIntBig *pnNextData );
      54                 : 
      55                 : /************************************************************************/
      56                 : /*                              NITFOpen()                              */
      57                 : /************************************************************************/
      58                 : 
      59                 : NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
      60                 : 
      61             546 : {
      62                 :     FILE  *fp;
      63                 :     char        *pachHeader;
      64                 :     NITFFile    *psFile;
      65                 :     int         nHeaderLen, nOffset, nHeaderLenOffset;
      66                 :     GUIntBig    nNextData;
      67                 :     char        szTemp[128], achFSDWNG[6];
      68                 :     GIntBig     currentPos;
      69             546 :     int         bTriedStreamingFileHeader = FALSE;
      70                 : 
      71                 : /* -------------------------------------------------------------------- */
      72                 : /*      Open the file.                                                  */
      73                 : /* -------------------------------------------------------------------- */
      74             546 :     if( bUpdatable )
      75             196 :         fp = VSIFOpenL( pszFilename, "r+b" );
      76                 :     else
      77             350 :         fp = VSIFOpenL( pszFilename, "rb" );
      78                 : 
      79             546 :     if( fp == NULL )
      80                 :     {
      81               0 :         CPLError( CE_Failure, CPLE_OpenFailed, 
      82                 :                   "Failed to open file %s.", 
      83                 :                   pszFilename );
      84               0 :         return NULL;
      85                 :     }
      86                 : 
      87                 : /* -------------------------------------------------------------------- */
      88                 : /*      Check file type.                                                */
      89                 : /* -------------------------------------------------------------------- */
      90             546 :     VSIFReadL( szTemp, 1, 9, fp );
      91                 : 
      92             546 :     if( !EQUALN(szTemp,"NITF",4) && !EQUALN(szTemp,"NSIF",4) )
      93                 :     {
      94               0 :         CPLError( CE_Failure, CPLE_AppDefined, 
      95                 :                   "The file %s is not an NITF file.", 
      96                 :                   pszFilename );
      97               0 :         VSIFCloseL(fp);
      98               0 :         return NULL;
      99                 :     }
     100                 : 
     101                 : /* -------------------------------------------------------------------- */
     102                 : /*      Read the FSDWNG field.                                          */
     103                 : /* -------------------------------------------------------------------- */
     104             546 :     if( VSIFSeekL( fp, 280, SEEK_SET ) != 0 
     105                 :         || VSIFReadL( achFSDWNG, 1, 6, fp ) != 6 )
     106                 :     {
     107               1 :         CPLError( CE_Failure, CPLE_NotSupported, 
     108                 :                   "Unable to read FSDWNG field from NITF file.  File is either corrupt\n"
     109                 :                   "or empty." );
     110               1 :         VSIFCloseL(fp);
     111               1 :         return NULL;
     112                 :     }
     113                 : 
     114                 : /* -------------------------------------------------------------------- */
     115                 : /*      Get header length.                                              */
     116                 : /* -------------------------------------------------------------------- */
     117             554 :     if( EQUALN(szTemp,"NITF01.",7) || EQUALN(achFSDWNG,"999998",6) )
     118               9 :         nHeaderLenOffset = 394;
     119                 :     else
     120             536 :         nHeaderLenOffset = 354;
     121                 : 
     122             545 :     if( VSIFSeekL( fp, nHeaderLenOffset, SEEK_SET ) != 0 
     123                 :         || VSIFReadL( szTemp, 1, 6, fp ) != 6 )
     124                 :     {
     125               2 :         CPLError( CE_Failure, CPLE_NotSupported, 
     126                 :                   "Unable to read header length from NITF file.  File is either corrupt\n"
     127                 :                   "or empty." );
     128               2 :         VSIFCloseL(fp);
     129               2 :         return NULL;
     130                 :     }
     131                 : 
     132             543 :     szTemp[6] = '\0';
     133             543 :     nHeaderLen = atoi(szTemp);
     134                 : 
     135             543 :     VSIFSeekL( fp, nHeaderLen, SEEK_SET );
     136             543 :     currentPos = VSIFTellL( fp ) ;
     137             543 :     if( nHeaderLen < nHeaderLenOffset || nHeaderLen > currentPos )
     138                 :     {
     139               1 :         CPLError( CE_Failure, CPLE_NotSupported, 
     140                 :                   "NITF Header Length (%d) seems to be corrupt.",
     141                 :                   nHeaderLen );
     142               1 :         VSIFCloseL(fp);
     143               1 :         return NULL;
     144                 :     }
     145                 : 
     146                 : /* -------------------------------------------------------------------- */
     147                 : /*      Read the whole file header.                                     */
     148                 : /* -------------------------------------------------------------------- */
     149             542 :     pachHeader = (char *) VSIMalloc(nHeaderLen);
     150             542 :     if (pachHeader == NULL)
     151                 :     {
     152               0 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     153                 :                   "Cannot allocate memory for NITF header");
     154               0 :         VSIFCloseL(fp);
     155               0 :         return NULL;
     156                 :     }
     157             542 :     VSIFSeekL( fp, 0, SEEK_SET );
     158             542 :     if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
     159                 :     {
     160               1 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     161                 :                   "Cannot read %d bytes for NITF header", (nHeaderLen));
     162               1 :         VSIFCloseL(fp);
     163               1 :         CPLFree(pachHeader);
     164               1 :         return NULL;
     165                 :     }
     166                 : 
     167                 : /* -------------------------------------------------------------------- */
     168                 : /*      Create and initialize info structure about file.                */
     169                 : /* -------------------------------------------------------------------- */
     170             541 :     psFile = (NITFFile *) CPLCalloc(sizeof(NITFFile),1);
     171             541 :     psFile->fp = fp;
     172             541 :     psFile->pachHeader = pachHeader;
     173                 : 
     174             542 : retry_read_header:
     175                 : /* -------------------------------------------------------------------- */
     176                 : /*      Get version.                                                    */
     177                 : /* -------------------------------------------------------------------- */
     178             542 :     NITFGetField( psFile->szVersion, pachHeader, 0, 9 );
     179                 : 
     180                 : /* -------------------------------------------------------------------- */
     181                 : /*      Collect a variety of information as metadata.                   */
     182                 : /* -------------------------------------------------------------------- */
     183                 : #define GetMD( target, hdr, start, length, name )              \
     184                 :     NITFExtractMetadata( &(target->papszMetadata), hdr,       \
     185                 :                          start, length,                        \
     186                 :                          "NITF_" #name );
     187                 :        
     188            1045 :     if( EQUAL(psFile->szVersion,"NITF02.10") 
     189                 :         || EQUAL(psFile->szVersion,"NSIF01.00") )
     190                 :     {
     191                 :         char szWork[100];
     192                 : 
     193             503 :         GetMD( psFile, pachHeader,   0,   9, FHDR   );
     194             503 :         GetMD( psFile, pachHeader,   9,   2, CLEVEL );
     195             503 :         GetMD( psFile, pachHeader,  11,   4, STYPE  );
     196             503 :         GetMD( psFile, pachHeader,  15,  10, OSTAID );
     197             503 :         GetMD( psFile, pachHeader,  25,  14, FDT    );
     198             503 :         GetMD( psFile, pachHeader,  39,  80, FTITLE );
     199             503 :         GetMD( psFile, pachHeader, 119,   1, FSCLAS );
     200             503 :         GetMD( psFile, pachHeader, 120,   2, FSCLSY );
     201             503 :         GetMD( psFile, pachHeader, 122,  11, FSCODE );
     202             503 :         GetMD( psFile, pachHeader, 133,   2, FSCTLH );
     203             503 :         GetMD( psFile, pachHeader, 135,  20, FSREL  );
     204             503 :         GetMD( psFile, pachHeader, 155,   2, FSDCTP );
     205             503 :         GetMD( psFile, pachHeader, 157,   8, FSDCDT );
     206             503 :         GetMD( psFile, pachHeader, 165,   4, FSDCXM );
     207             503 :         GetMD( psFile, pachHeader, 169,   1, FSDG   );
     208             503 :         GetMD( psFile, pachHeader, 170,   8, FSDGDT );
     209             503 :         GetMD( psFile, pachHeader, 178,  43, FSCLTX );
     210             503 :         GetMD( psFile, pachHeader, 221,   1, FSCATP );
     211             503 :         GetMD( psFile, pachHeader, 222,  40, FSCAUT );
     212             503 :         GetMD( psFile, pachHeader, 262,   1, FSCRSN );
     213             503 :         GetMD( psFile, pachHeader, 263,   8, FSSRDT );
     214             503 :         GetMD( psFile, pachHeader, 271,  15, FSCTLN );
     215             503 :         GetMD( psFile, pachHeader, 286,   5, FSCOP  );
     216             503 :         GetMD( psFile, pachHeader, 291,   5, FSCPYS );
     217             503 :         GetMD( psFile, pachHeader, 296,   1, ENCRYP );
     218             503 :         sprintf( szWork, "%3d,%3d,%3d", 
     219                 :                  ((GByte *)pachHeader)[297], 
     220                 :                  ((GByte *)pachHeader)[298], 
     221                 :                  ((GByte *)pachHeader)[299] );
     222             503 :         GetMD( psFile, szWork, 0, 11, FBKGC );
     223             503 :         GetMD( psFile, pachHeader, 300,  24, ONAME  );
     224             503 :         GetMD( psFile, pachHeader, 324,  18, OPHONE );
     225             503 :         NITFGetField(szTemp, pachHeader, 342, 12);
     226                 :     }
     227              39 :     else if( EQUAL(psFile->szVersion,"NITF02.00") )
     228                 :     {
     229              33 :         int nCOff = 0;
     230                 : 
     231              33 :         GetMD( psFile, pachHeader,   0,   9, FHDR   );
     232              33 :         GetMD( psFile, pachHeader,   9,   2, CLEVEL );
     233              33 :         GetMD( psFile, pachHeader,  11,   4, STYPE  );
     234              33 :         GetMD( psFile, pachHeader,  15,  10, OSTAID );
     235              33 :         GetMD( psFile, pachHeader,  25,  14, FDT    );
     236              33 :         GetMD( psFile, pachHeader,  39,  80, FTITLE );
     237              33 :         GetMD( psFile, pachHeader, 119,   1, FSCLAS );
     238              33 :         GetMD( psFile, pachHeader, 120,  40, FSCODE );
     239              33 :         GetMD( psFile, pachHeader, 160,  40, FSCTLH );
     240              33 :         GetMD( psFile, pachHeader, 200,  40, FSREL  );
     241              33 :         GetMD( psFile, pachHeader, 240,  20, FSCAUT );
     242              33 :         GetMD( psFile, pachHeader, 260,  20, FSCTLN );
     243              33 :         GetMD( psFile, pachHeader, 280,   6, FSDWNG );
     244              33 :         if( EQUALN(pachHeader+280,"999998",6) )
     245                 :         {
     246               2 :             GetMD( psFile, pachHeader, 286,  40, FSDEVT );
     247               2 :             nCOff += 40;
     248                 :         }
     249              33 :         GetMD( psFile, pachHeader, 286+nCOff,   5, FSCOP  );
     250              33 :         GetMD( psFile, pachHeader, 291+nCOff,   5, FSCPYS );
     251              33 :         GetMD( psFile, pachHeader, 296+nCOff,   1, ENCRYP );
     252              33 :         GetMD( psFile, pachHeader, 297+nCOff,  27, ONAME  );
     253              33 :         GetMD( psFile, pachHeader, 324+nCOff,  18, OPHONE );
     254              33 :         NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
     255                 :     }
     256                 : 
     257             542 :     if (!bTriedStreamingFileHeader &&
     258                 :          EQUAL(szTemp, "999999999999"))
     259                 :     {
     260                 :         GUIntBig nFileSize;
     261                 :         GByte abyDELIM2_L2[12];
     262                 :         GByte abyL1_DELIM1[11];
     263                 : 
     264               1 :         bTriedStreamingFileHeader = TRUE;
     265               1 :         CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
     266                 : 
     267               1 :         VSIFSeekL( fp, 0, SEEK_END );
     268               1 :         nFileSize = VSIFTellL(fp);
     269                 : 
     270               1 :         VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
     271               1 :         abyDELIM2_L2[11] = '\0';
     272                 : 
     273               1 :         if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
     274                 :             abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
     275                 :             abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
     276                 :         {
     277               1 :             int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
     278               1 :             if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
     279                 :             {
     280               1 :                 VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
     281                 : 
     282               1 :                 if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
     283                 :                      abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
     284                 :                      abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
     285                 :                      memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
     286                 :                 {
     287               1 :                     if (SFHL2 == nHeaderLen)
     288                 :                     {
     289               1 :                         CSLDestroy(psFile->papszMetadata);
     290               1 :                         psFile->papszMetadata = NULL;
     291                 : 
     292               1 :                         if ( (int)VSIFReadL( pachHeader, 1, SFHL2, fp ) != SFHL2 )
     293                 :                         {
     294               0 :                             VSIFCloseL(fp);
     295               0 :                             CPLFree(pachHeader);
     296               0 :                             CPLFree(psFile);
     297               0 :                             return NULL;
     298                 :                         }
     299                 : 
     300               1 :                         goto retry_read_header;
     301                 :                     }
     302                 :                 }
     303                 :             }
     304                 :         }
     305                 :     }
     306                 : 
     307                 : /* -------------------------------------------------------------------- */
     308                 : /*      Collect segment info for the types we care about.               */
     309                 : /* -------------------------------------------------------------------- */
     310             541 :     nNextData = nHeaderLen;
     311                 : 
     312             541 :     nOffset = nHeaderLenOffset + 6;
     313                 : 
     314             541 :     nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
     315                 : 
     316             541 :     if (nOffset != -1)
     317             537 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
     318                 : 
     319                 :     /* LA Called NUMX in NITF 2.1 */
     320             541 :     if (nOffset != -1)
     321             537 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
     322                 : 
     323             541 :     if (nOffset != -1)
     324             537 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
     325                 : 
     326             541 :     if (nOffset != -1)
     327             537 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
     328                 : 
     329             541 :     if (nOffset != -1)
     330             537 :         nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
     331                 :     else
     332                 :     {
     333               4 :         NITFClose(psFile);
     334               4 :         return NULL;
     335                 :     }
     336                 : 
     337                 : /* -------------------------------------------------------------------- */
     338                 : /*      Is there User Define Header Data? (TREs)                        */
     339                 : /* -------------------------------------------------------------------- */
     340             537 :     if (nHeaderLen < nOffset + 5)
     341                 :     {
     342               1 :         CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     343               1 :         NITFClose(psFile);
     344               1 :         return NULL;
     345                 :     }
     346                 : 
     347             536 :     psFile->nTREBytes = 
     348                 :         atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
     349             536 :     if (psFile->nTREBytes < 0)
     350                 :     {
     351               1 :         CPLError(CE_Failure, CPLE_AppDefined,
     352                 :                  "Invalid TRE size : %d", psFile->nTREBytes);
     353               1 :         NITFClose(psFile);
     354               1 :         return NULL;
     355                 :     }
     356             535 :     nOffset += 5;
     357                 : 
     358             535 :     if( psFile->nTREBytes > 3 )
     359                 :     {
     360              27 :         nOffset += 3; /* UDHOFL */
     361              27 :         psFile->nTREBytes -= 3;
     362                 : 
     363              27 :         if (nHeaderLen < nOffset + psFile->nTREBytes)
     364                 :         {
     365               0 :             CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     366               0 :             NITFClose(psFile);
     367               0 :             return NULL;
     368                 :         }
     369                 : 
     370              27 :         psFile->pachTRE = (char *) VSIMalloc(psFile->nTREBytes);
     371              27 :         if (psFile->pachTRE == NULL)
     372                 :         {
     373               0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     374                 :                      "Cannot allocate %d bytes", psFile->nTREBytes);
     375               0 :             NITFClose(psFile);
     376               0 :             return NULL;
     377                 :         }
     378              27 :         memcpy( psFile->pachTRE, pachHeader + nOffset, 
     379                 :                 psFile->nTREBytes );
     380                 :     }
     381                 : 
     382                 : /* -------------------------------------------------------------------- */
     383                 : /*      Is there Extended Header Data?  (More TREs)                     */
     384                 : /* -------------------------------------------------------------------- */
     385             535 :     if( nHeaderLen > nOffset + 8 )
     386                 :     {
     387                 :         int nXHDL = 
     388              37 :             atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
     389              37 :         if (nXHDL < 0)
     390                 :         {
     391               1 :             CPLError(CE_Failure, CPLE_AppDefined,
     392                 :                     "Invalid XHDL value : %d", nXHDL);
     393               1 :             NITFClose(psFile);
     394               1 :             return NULL;
     395                 :         }
     396                 : 
     397              36 :         nOffset += 5; /* XHDL */
     398                 : 
     399              36 :         if( nXHDL > 3 )
     400                 :         {
     401                 :             char* pachNewTRE;
     402                 : 
     403               9 :             nOffset += 3; /* XHDLOFL */
     404               9 :             nXHDL -= 3;
     405                 : 
     406               9 :             if (nHeaderLen < nOffset + nXHDL)
     407                 :             {
     408               1 :                 CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
     409               1 :                 NITFClose(psFile);
     410               1 :                 return NULL;
     411                 :             }
     412                 : 
     413               8 :             pachNewTRE = (char *) 
     414                 :                 VSIRealloc( psFile->pachTRE, 
     415                 :                             psFile->nTREBytes + nXHDL );
     416               8 :             if (pachNewTRE == NULL)
     417                 :             {
     418               0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
     419                 :                      "Cannot allocate %d bytes", psFile->nTREBytes + nXHDL);
     420               0 :                 NITFClose(psFile);
     421               0 :                 return NULL;
     422                 :             }
     423               8 :             psFile->pachTRE = pachNewTRE;
     424               8 :             memcpy( psFile->pachTRE, pachHeader + nOffset, nXHDL );
     425               8 :             psFile->nTREBytes += nXHDL;
     426                 :         }
     427                 :     }
     428                 : 
     429             533 :     return psFile;
     430                 : }
     431                 : 
     432                 : /************************************************************************/
     433                 : /*                             NITFClose()                              */
     434                 : /************************************************************************/
     435                 : 
     436                 : void NITFClose( NITFFile *psFile )
     437                 : 
     438             541 : {
     439                 :     int  iSegment;
     440                 : 
     441            6822 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
     442                 :     {
     443            6281 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
     444                 : 
     445            6281 :         if( psSegInfo->hAccess == NULL )
     446            1747 :             continue;
     447                 : 
     448            4534 :         if( EQUAL(psSegInfo->szSegmentType,"IM"))
     449            4534 :             NITFImageDeaccess( (NITFImage *) psSegInfo->hAccess );
     450               0 :         else if( EQUAL(psSegInfo->szSegmentType,"DE"))
     451               0 :             NITFDESDeaccess( (NITFDES *) psSegInfo->hAccess );
     452                 :         else
     453                 :         {
     454               0 :             CPLAssert( FALSE );
     455                 :         }
     456                 :     }
     457                 : 
     458             541 :     CPLFree( psFile->pasSegmentInfo );
     459             541 :     if( psFile->fp != NULL )
     460             541 :         VSIFCloseL( psFile->fp );
     461             541 :     CPLFree( psFile->pachHeader );
     462             541 :     CSLDestroy( psFile->papszMetadata );
     463             541 :     CPLFree( psFile->pachTRE );
     464             541 :     CPLFree( psFile );
     465             541 : }
     466                 : 
     467                 : static void NITFGotoOffset(FILE* fp, GUIntBig nLocation)
     468          284350 : {
     469          284350 :     GUIntBig nCurrentLocation = VSIFTellL(fp);
     470          284350 :     if (nLocation > nCurrentLocation)
     471                 :     {
     472                 :         GUIntBig nFileSize;
     473                 :         int iFill;
     474          173227 :         char cSpace = ' ';
     475                 : 
     476          173227 :         VSIFSeekL(fp, 0, SEEK_END);
     477          173227 :         nFileSize = VSIFTellL(fp);
     478          173227 :         if (nLocation > nFileSize)
     479                 :         {
     480         1309863 :             for(iFill = 0; iFill < nLocation - nFileSize; iFill++)
     481         1138862 :                 VSIFWriteL(&cSpace, 1, 1, fp);
     482                 :         }
     483                 :         else
     484            2226 :             VSIFSeekL(fp, nLocation, SEEK_SET);
     485                 :     }
     486          111123 :     else if (nLocation < nCurrentLocation)
     487                 :     {
     488            2593 :         VSIFSeekL(fp, nLocation, SEEK_SET);
     489                 :     }
     490                 : 
     491          284350 : }
     492                 : 
     493                 : /************************************************************************/
     494                 : /*                             NITFCreate()                             */
     495                 : /*                                                                      */
     496                 : /*      Create a new uncompressed NITF file.                            */
     497                 : /************************************************************************/
     498                 : 
     499                 : int NITFCreate( const char *pszFilename, 
     500                 :                       int nPixels, int nLines, int nBands, 
     501                 :                       int nBitsPerSample, const char *pszPVType,
     502                 :                       char **papszOptions )
     503                 : 
     504             196 : {
     505                 :     FILE  *fp;
     506             196 :     GUIntBig    nCur = 0;
     507             196 :     int         nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
     508                 :     GIntBig     nImageSize;
     509                 :     int         nNBPR, nNBPC;
     510                 :     const char *pszIREP;
     511             196 :     const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
     512                 :     int nCLevel;
     513                 :     const char *pszNUMT;
     514             196 :     int nHL, nNUMT = 0;
     515                 :     int nUDIDLOffset;
     516                 :     const char *pszVersion;
     517             196 :     int iIM, nIM = 1;
     518                 :     const char *pszNUMI;
     519             196 :     int iGS, nGS = 0; // number of graphic segment
     520                 :     const char *pszNUMS; // graphic segment option string
     521                 : 
     522             196 :     if (nBands <= 0 || nBands > 99999)
     523                 :     {
     524               2 :         CPLError(CE_Failure, CPLE_NotSupported,
     525                 :                  "Invalid band number : %d", nBands);
     526               2 :         return FALSE;
     527                 :     }
     528                 : 
     529             194 :     if( pszIC == NULL )
     530             187 :         pszIC = "NC";
     531                 : 
     532                 : /* -------------------------------------------------------------------- */
     533                 : /*      Fetch some parameter overrides.                                 */
     534                 : /* -------------------------------------------------------------------- */
     535             194 :     pszIREP = CSLFetchNameValue( papszOptions, "IREP" );
     536             194 :     if( pszIREP == NULL )
     537             155 :         pszIREP = "MONO";
     538                 : 
     539             194 :     pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
     540             194 :     if( pszNUMT != NULL )
     541                 :     {
     542               5 :         nNUMT = atoi(pszNUMT);
     543               5 :         if (nNUMT < 0 || nNUMT > 999)
     544                 :         {
     545               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     546                 :                     "Invalid NUMT value : %s", pszNUMT);
     547               1 :             return FALSE;
     548                 :         }
     549                 :     }
     550                 : 
     551             193 :     pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
     552             193 :     if (pszNUMI != NULL)
     553                 :     {
     554               4 :         nIM = atoi(pszNUMI);
     555               4 :         if (nIM < 1 || nIM > 999)
     556                 :         {
     557               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     558                 :                     "Invalid NUMI value : %s", pszNUMI);
     559               1 :             return FALSE;
     560                 :         }
     561               3 :         if (nIM != 1 && !EQUAL(pszIC, "NC"))
     562                 :         {
     563               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     564                 :                     "Unable to create file with multiple images and compression at the same time");
     565               1 :             return FALSE;
     566                 :         }
     567                 :     }
     568                 :     
     569                 :     // Reads and validates graphics segment number option
     570             191 :     pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
     571             191 :     if (pszNUMS != NULL)
     572                 :     {
     573               9 :         nGS = atoi(pszNUMS);
     574               9 :         if (nGS < 0 || nGS > 999)
     575                 :         {
     576               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
     577                 :                             pszNUMS);
     578               1 :             return FALSE;
     579                 :         }
     580                 :     }
     581                 : 
     582                 : 
     583                 : 
     584                 : /* -------------------------------------------------------------------- */
     585                 : /*      Compute raw image size, blocking factors and so forth.          */
     586                 : /* -------------------------------------------------------------------- */
     587             190 :     nNPPBH = nPixels;
     588             190 :     nNPPBV = nLines;
     589                 : 
     590             190 :     if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
     591               4 :         nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
     592                 : 
     593             190 :     if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
     594               3 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
     595                 : 
     596             190 :     if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
     597               2 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
     598                 :     
     599             190 :     if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
     600               0 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
     601                 :     
     602             190 :     if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
     603               0 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
     604                 :         
     605                 :         
     606             193 :     if (EQUAL(pszIC, "NC") &&
     607                 :         (nPixels > 8192 || nLines > 8192) && 
     608                 :         nNPPBH == nPixels && nNPPBV == nLines)
     609                 :     {
     610                 :         /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
     611               3 :         nNBPR = 1;
     612               3 :         nNBPC = 1;
     613               3 :         nNPPBH = 0;
     614               3 :         nNPPBV = 0;
     615                 :         
     616               3 :         nImageSize = 
     617                 :             ((nBitsPerSample)/8) 
     618                 :             * ((GIntBig) nPixels *nLines)
     619                 :             * nBands;
     620                 :     }
     621                 :     else
     622                 :     {
     623             187 :         if( nNPPBH <= 0 || nNPPBV <= 0 ||
     624                 :             nNPPBH > 9999 || nNPPBV > 9999  )
     625               0 :             nNPPBH = nNPPBV = 256;
     626                 : 
     627             187 :         nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
     628             187 :         nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
     629             187 :         if ( nNBPR > 9999 || nNBPC > 9999 )
     630                 :         {
     631               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     632                 :                       "Unable to create file %s,\n"
     633                 :                       "Too many blocks : %d x %d",
     634                 :                      pszFilename, nNBPR, nNBPC);
     635               1 :             return FALSE;
     636                 :         }
     637                 : 
     638             186 :         nImageSize = 
     639                 :             ((nBitsPerSample)/8) 
     640                 :             * ((GIntBig) nNBPR * nNBPC)
     641                 :             * nNPPBH * nNPPBV * nBands;
     642                 :     }
     643                 : 
     644             189 :     if (EQUAL(pszIC, "NC"))
     645                 :     {
     646             184 :         if ((double)nImageSize >= 1e10 - 1)
     647                 :         {
     648               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     649                 :                     "Unable to create file %s,\n"
     650                 :                     "Too big image size : " CPL_FRMT_GUIB,
     651                 :                     pszFilename, nImageSize );
     652               1 :             return FALSE;
     653                 :         }
     654             183 :         if ((double)(nImageSize * nIM) >= 1e12 - 1)
     655                 :         {
     656               1 :             CPLError( CE_Failure, CPLE_AppDefined, 
     657                 :                     "Unable to create file %s,\n"
     658                 :                     "Too big file size : " CPL_FRMT_GUIB,
     659                 :                     pszFilename, nImageSize * nIM );
     660               1 :             return FALSE;
     661                 :         }
     662                 :     }
     663                 : 
     664                 : /* -------------------------------------------------------------------- */
     665                 : /*      Open new file.                                                  */
     666                 : /* -------------------------------------------------------------------- */
     667             187 :     fp = VSIFOpenL( pszFilename, "wb+" );
     668             187 :     if( fp == NULL )
     669                 :     {
     670               1 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     671                 :                   "Unable to create file %s,\n"
     672                 :                   "check path and permissions.",
     673                 :                   pszFilename );
     674               1 :         return FALSE;
     675                 :     }
     676                 : 
     677                 : 
     678                 : /* -------------------------------------------------------------------- */
     679                 : /*      Work out the version we are producing.  For now we really       */
     680                 : /*      only support creating NITF02.10 or the nato analog              */
     681                 : /*      NSIF01.00.                                                      */
     682                 : /* -------------------------------------------------------------------- */
     683             186 :     pszVersion = CSLFetchNameValue( papszOptions, "FHDR" );
     684             186 :     if( pszVersion == NULL )
     685             180 :         pszVersion = "NITF02.10";
     686               6 :     else if( !EQUAL(pszVersion,"NITF02.10") 
     687                 :              && !EQUAL(pszVersion,"NSIF01.00") )
     688                 :     {
     689               1 :         CPLError( CE_Warning, CPLE_AppDefined, 
     690                 :                   "FHDR=%s not supported, switching to NITF02.10.",
     691                 :                   pszVersion );
     692               1 :         pszVersion = "NITF02.10";
     693                 :     }
     694                 : 
     695                 : /* -------------------------------------------------------------------- */
     696                 : /*      Prepare the file header.                                        */
     697                 : /* -------------------------------------------------------------------- */
     698                 : 
     699                 : #define PLACE(location,name,text)  { \
     700                 :     const char* _text = text; \
     701                 :     NITFGotoOffset(fp, location); \
     702                 :     VSIFWriteL(_text, 1, strlen(_text), fp); }
     703                 : 
     704                 : #define OVR(width,location,name,text) {         \
     705                 :     const char* _text = text; \
     706                 :     const char *pszParmValue;             \
     707                 :     pszParmValue = CSLFetchNameValue( papszOptions, #name );    \
     708                 :     if( pszParmValue == NULL )            \
     709                 :         pszParmValue = _text;           \
     710                 :     NITFGotoOffset(fp, location); \
     711                 :     VSIFWriteL(pszParmValue, 1, MIN(width,strlen(pszParmValue)), fp); }
     712                 : 
     713                 : #define WRITE_BYTE(location, val) { \
     714                 :     char cVal = val; \
     715                 :     NITFGotoOffset(fp, location); \
     716                 :     VSIFWriteL(&cVal, 1, 1, fp); }
     717                 : 
     718             186 :     VSIFSeekL(fp, 0, SEEK_SET);
     719                 : 
     720             186 :     PLACE (  0, FDHR_FVER,    pszVersion                      );
     721             186 :     OVR( 2,  9, CLEVEL,       "03"                            );  /* Patched at the end */
     722             186 :     PLACE ( 11, STYPE        ,"BF01"                          );
     723             186 :     OVR(10, 15, OSTAID       ,"GDAL"                          );
     724             186 :     OVR(14, 25, FDT          ,"20021216151629"                );
     725             186 :     OVR(80, 39, FTITLE       ,""                              );
     726             186 :     OVR( 1,119, FSCLAS       ,"U"                             );
     727             186 :     OVR( 2,120, FSCLSY       ,""                              );
     728             186 :     OVR(11,122, FSCODE       ,""                              );
     729             186 :     OVR( 2,133, FSCTLH       ,""                              );
     730             186 :     OVR(20,135, FSREL        ,""                              );
     731             186 :     OVR( 2,155, FSDCTP       ,""                              );
     732             186 :     OVR( 8,157, FSDCDT       ,""                              );
     733             186 :     OVR( 4,165, FSDCXM       ,""                              );
     734             186 :     OVR( 1,169, FSDG         ,""                              );
     735             186 :     OVR( 8,170, FSDGDT       ,""                              );
     736             186 :     OVR(43,178, FSCLTX       ,""                              );
     737             186 :     OVR( 1,221, FSCATP       ,""                              );
     738             186 :     OVR(40,222, FSCAUT       ,""                              );
     739             186 :     OVR( 1,262, FSCRSN       ,""                              );
     740             186 :     OVR( 8,263, FSSRDT       ,""                              );
     741             186 :     OVR(15,271, FSCTLN       ,""                              );
     742             186 :     OVR( 5,286, FSCOP        ,"00000"                         );
     743             186 :     OVR( 5,291, FSCPYS       ,"00000"                         );
     744             186 :     PLACE (296, ENCRYP       ,"0"                             );
     745             186 :     WRITE_BYTE(297, 0x00); /* FBKGC */
     746             186 :     WRITE_BYTE(298, 0x00);
     747             186 :     WRITE_BYTE(299, 0x00);
     748             186 :     OVR(24,300, ONAME        ,""                              );
     749             186 :     OVR(18,324, OPHONE       ,""                              );
     750             186 :     PLACE (342, FL           ,"????????????"                  );
     751             186 :     PLACE (354, HL           ,"??????"                        );
     752             186 :     PLACE (360, NUMI         ,CPLSPrintf("%03d", nIM)         );
     753                 : 
     754             186 :     nHL = 363;
     755            1370 :     for(iIM=0;iIM<nIM;iIM++)
     756                 :     {
     757            1184 :         PLACE (nHL,     LISHi    ,"??????"                        );
     758            1184 :         PLACE (nHL + 6, LIi      ,CPLSPrintf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "d", nImageSize)  );
     759            1184 :         nHL += 6 + 10;
     760                 :     }
     761                 : 
     762                 :     // Creates Header entries for graphic segment
     763                 :     //    NUMS: number of segment
     764                 :     // For each segment:
     765                 :     //    LSSH[i]: subheader length (4 byte), set to be 258, the size for
     766                 :     //        minimal amount of information.
     767                 :     //    LS[i] data length (6 byte)
     768             186 :     PLACE (nHL,     NUMS         ,CPLSPrintf("%03d",nGS)        );
     769             186 :     nHL += 3; // Move three characters
     770             190 :     for (iGS = 0; iGS < nGS; iGS++)
     771                 :     {
     772               4 :         PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
     773               4 :         PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
     774               4 :         nHL += 4 + 6;
     775                 :     }
     776                 : 
     777             186 :     PLACE (nHL, NUMX         ,"000"                           );
     778             186 :     PLACE (nHL + 3, NUMT         ,CPLSPrintf("%03d",nNUMT)        );
     779                 : 
     780             186 :     PLACE (nHL + 6, LTSHnLTn     ,""                              );
     781                 : 
     782             186 :     nHL += 6 + (4+5) * nNUMT;
     783                 : 
     784             186 :     PLACE (nHL, NUMDES       ,"000"                           );
     785             186 :     nHL += 3;
     786             186 :     PLACE (nHL, NUMRES       ,"000"                           );
     787             186 :     nHL += 3;
     788             186 :     PLACE (nHL, UDHDL        ,"00000"                         );
     789             186 :     nHL += 5;
     790             186 :     PLACE (nHL, XHDL         ,"00000"                         );
     791             186 :     nHL += 5;
     792                 : 
     793             186 :     if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
     794                 :     {
     795               3 :         NITFWriteTREsFromOptions(
     796                 :             fp,
     797                 :             nHL - 10,
     798                 :             nHL,
     799                 :             &nHL,
     800                 :             papszOptions, "FILE_TRE=" );
     801                 :     }
     802                 : 
     803             186 :     if (nHL > 999999)
     804                 :     {
     805               0 :         CPLError(CE_Failure, CPLE_AppDefined,
     806                 :                  "Too big file header length : %d", nHL);
     807               0 :         VSIFCloseL( fp );
     808               0 :         return FALSE;
     809                 :     }
     810                 : 
     811                 :     // update header length
     812             186 :     PLACE (354, HL           ,CPLSPrintf("%06d",nHL)          );
     813                 : 
     814             186 :     nCur = nHL;
     815                 : 
     816                 : /* -------------------------------------------------------------------- */
     817                 : /*      Prepare the image header.                                       */
     818                 : /* -------------------------------------------------------------------- */
     819            1370 :   for(iIM=0;iIM<nIM;iIM++)
     820                 :   {
     821            1184 :     VSIFSeekL(fp, nCur, SEEK_SET);
     822                 : 
     823            1184 :     PLACE (nCur+  0, IM           , "IM"                           );
     824            1184 :     OVR(10,nCur+  2, IID1         , "Missing"                      );
     825            1184 :     OVR(14,nCur+ 12, IDATIM       , "20021216151629"               );
     826            1184 :     OVR(17,nCur+ 26, TGTID        , ""                             );
     827            1184 :     OVR(80,nCur+ 43, IID2         , ""                             );
     828            1184 :     OVR( 1,nCur+123, ISCLAS       , "U"                            );
     829            1184 :     OVR( 2,nCur+124, ISCLSY       , ""                             );
     830            1184 :     OVR(11,nCur+126, ISCODE       , ""                             );
     831            1184 :     OVR( 2,nCur+137, ISCTLH       , ""                             );
     832            1184 :     OVR(20,nCur+139, ISREL        , ""                             );
     833            1184 :     OVR( 2,nCur+159, ISDCTP       , ""                             );
     834            1184 :     OVR( 8,nCur+161, ISDCDT       , ""                             );
     835            1184 :     OVR( 4,nCur+169, ISDCXM       , ""                             );
     836            1184 :     OVR( 1,nCur+173, ISDG         , ""                             );
     837            1184 :     OVR( 8,nCur+174, ISDGDT       , ""                             );
     838            1184 :     OVR(43,nCur+182, ISCLTX       , ""                             );
     839            1184 :     OVR( 1,nCur+225, ISCATP       , ""                             );
     840            1184 :     OVR(40,nCur+226, ISCAUT       , ""                             );
     841            1184 :     OVR( 1,nCur+266, ISCRSN       , ""                             );
     842            1184 :     OVR( 8,nCur+267, ISSRDT       , ""                             );
     843            1184 :     OVR(15,nCur+275, ISCTLN       , ""                             );
     844            1184 :     PLACE (nCur+290, ENCRYP       , "0"                            );
     845            1184 :     OVR(42,nCur+291, ISORCE       , "Unknown"                      );
     846            1184 :     PLACE (nCur+333, NROWS        , CPLSPrintf("%08d", nLines)     );
     847            1184 :     PLACE (nCur+341, NCOLS        , CPLSPrintf("%08d", nPixels)    );
     848            1184 :     PLACE (nCur+349, PVTYPE       , pszPVType                      );
     849            1184 :     PLACE (nCur+352, IREP         , pszIREP                        );
     850            1184 :     OVR( 8,nCur+360, ICAT         , "VIS"                          );
     851            1184 :     OVR( 2,nCur+368, ABPP         , CPLSPrintf("%02d",nBitsPerSample) );
     852            1184 :     OVR( 1,nCur+370, PJUST        , "R"                            );
     853            1184 :     OVR( 1,nCur+371, ICORDS       , " "                            );
     854                 : 
     855            1184 :     nOffset = 372;
     856                 : 
     857                 :     {
     858                 :         const char *pszParmValue;
     859            1184 :         pszParmValue = CSLFetchNameValue( papszOptions, "ICORDS" );
     860            1184 :         if( pszParmValue == NULL )
     861            1145 :             pszParmValue = " ";
     862            1184 :         if( *pszParmValue != ' ' )
     863                 :         {
     864              39 :             OVR(60,nCur+nOffset, IGEOLO, ""                            );
     865              39 :             nOffset += 60;
     866                 :         }
     867                 :     }
     868                 : 
     869                 :     {
     870            1184 :         const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
     871            1184 :         if (pszICOM != NULL)
     872                 :         {
     873               1 :             int nLenICOM = strlen(pszICOM);
     874               1 :             int nICOM = (79 + nLenICOM) / 80;
     875               1 :             if (nICOM > 9)
     876                 :             {
     877               0 :                 CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
     878               0 :                 nICOM = 9;
     879                 :             }
     880               1 :             PLACE (nCur+nOffset, NICOM    , CPLSPrintf("%01d",nICOM) );
     881               1 :             VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
     882               1 :             nOffset += nICOM * 80;
     883                 :         }
     884                 :         else
     885                 :         {
     886            1183 :             PLACE (nCur+nOffset, NICOM    , "0"                            );
     887                 :         }
     888                 :     }
     889                 : 
     890            1184 :     OVR( 2,nCur+nOffset+1, IC     , "NC"                           );
     891                 : 
     892            1184 :     if( pszIC[0] != 'N' )
     893                 :     {
     894               5 :         OVR( 4,nCur+nOffset+3, COMRAT , "    "                     );
     895               5 :         nOffset += 4;
     896                 :     }
     897                 : 
     898            1184 :     if (nBands <= 9)
     899                 :     {
     900            1181 :         PLACE (nCur+nOffset+3, NBANDS , CPLSPrintf("%d",nBands)        );
     901                 :     }
     902                 :     else
     903                 :     {
     904               3 :         PLACE (nCur+nOffset+3, NBANDS , "0"        );
     905               3 :         PLACE (nCur+nOffset+4, XBANDS , CPLSPrintf("%05d",nBands)        );
     906               3 :         nOffset += 5;
     907                 :     }
     908                 : 
     909            1184 :     nOffset += 4;
     910                 : 
     911                 : /* -------------------------------------------------------------------- */
     912                 : /*      Per band info                                                   */
     913                 : /* -------------------------------------------------------------------- */
     914           72450 :     for( iBand = 0; iBand < nBands; iBand++ )
     915                 :     {
     916           71266 :         const char *pszIREPBAND = "M";
     917                 : 
     918           71266 :         if( EQUAL(pszIREP,"RGB/LUT") )
     919               5 :             pszIREPBAND = "LU";
     920           71261 :         else if( EQUAL(pszIREP,"RGB") )
     921                 :         {
     922              13 :             if( iBand == 0 )
     923               4 :                 pszIREPBAND = "R";
     924               9 :             else if( iBand == 1 )
     925               4 :                 pszIREPBAND = "G";
     926               5 :             else if( iBand == 2 )
     927               4 :                 pszIREPBAND = "B";
     928                 :         }
     929           71248 :         else if( EQUALN(pszIREP,"YCbCr",5) )
     930                 :         {
     931               9 :             if( iBand == 0 )
     932               3 :                 pszIREPBAND = "Y";
     933               6 :             else if( iBand == 1 )
     934               3 :                 pszIREPBAND = "Cb";
     935               3 :             else if( iBand == 2 )
     936               3 :                 pszIREPBAND = "Cr";
     937                 :         }
     938                 : 
     939           71266 :         PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND                 );
     940                 : //      PLACE(nCur+nOffset+ 2, ISUBCATn, ""                           );
     941           71266 :         PLACE(nCur+nOffset+ 8, IFCn  , "N"                            );
     942                 : //      PLACE(nCur+nOffset+ 9, IMFLTn, ""                             );
     943                 : 
     944           71266 :         if( !EQUAL(pszIREP,"RGB/LUT") )
     945                 :         {
     946           71261 :             PLACE(nCur+nOffset+12, NLUTSn, "0"                        );
     947           71261 :             nOffset += 13;
     948                 :         }
     949                 :         else
     950                 :         {
     951               5 :             int iC, nCount=256;
     952                 : 
     953               5 :             if( CSLFetchNameValue(papszOptions,"LUT_SIZE") != NULL )
     954               5 :                 nCount = atoi(CSLFetchNameValue(papszOptions,"LUT_SIZE"));
     955                 : 
     956               5 :             if (!(nCount >= 0 && nCount <= 99999))
     957                 :             {
     958               1 :                 CPLError(CE_Warning, CPLE_AppDefined,
     959                 :                          "Invalid LUT value : %d. Defaulting to 256", nCount);
     960               1 :                 nCount = 256;
     961                 :             }
     962               5 :             PLACE(nCur+nOffset+12, NLUTSn, "3"                        );
     963               5 :             PLACE(nCur+nOffset+13, NELUTn, CPLSPrintf("%05d",nCount)  );
     964                 : 
     965            1030 :             for( iC = 0; iC < nCount; iC++ )
     966                 :             {
     967            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+       0, (char) iC);
     968            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+nCount*1, (char) iC);
     969            1025 :                 WRITE_BYTE(nCur+nOffset+18+iC+nCount*2, (char) iC);
     970                 :             }
     971               5 :             nOffset += 18 + nCount*3;
     972                 :         }
     973                 :     }
     974                 : 
     975                 : /* -------------------------------------------------------------------- */
     976                 : /*      Remainder of image header info.                                 */
     977                 : /* -------------------------------------------------------------------- */
     978            1184 :     PLACE(nCur+nOffset+  0, ISYNC , "0"                            );
     979                 : 
     980                 :     /* RGB JPEG compressed NITF requires IMODE=P (see #3345) */
     981            1187 :     if (nBands >= 3 && (EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3")))
     982                 :     {
     983               3 :         PLACE(nCur+nOffset+  1, IMODE , "P"                            );
     984                 :     }
     985                 :     else
     986                 :     {
     987            1181 :         PLACE(nCur+nOffset+  1, IMODE , "B"                            );
     988                 :     }
     989            1184 :     PLACE(nCur+nOffset+  2, NBPR  , CPLSPrintf("%04d",nNBPR)       );
     990            1184 :     PLACE(nCur+nOffset+  6, NBPC  , CPLSPrintf("%04d",nNBPC)       );
     991            1184 :     PLACE(nCur+nOffset+ 10, NPPBH , CPLSPrintf("%04d",nNPPBH)      );
     992            1184 :     PLACE(nCur+nOffset+ 14, NPPBV , CPLSPrintf("%04d",nNPPBV)      );
     993            1184 :     PLACE(nCur+nOffset+ 18, NBPP  , CPLSPrintf("%02d",nBitsPerSample) );
     994            1184 :     PLACE(nCur+nOffset+ 20, IDLVL , "001"                          );
     995            1184 :     PLACE(nCur+nOffset+ 23, IALVL , "000"                          );
     996            1184 :     PLACE(nCur+nOffset+ 26, ILOC  , "0000000000"                   );
     997            1184 :     PLACE(nCur+nOffset+ 36, IMAG  , "1.0 "                         );
     998            1184 :     PLACE(nCur+nOffset+ 40, UDIDL , "00000"                        );
     999            1184 :     PLACE(nCur+nOffset+ 45, IXSHDL, "00000"                        );
    1000                 : 
    1001            1184 :     nUDIDLOffset = nOffset + 40;
    1002            1184 :     nOffset += 50;
    1003                 : 
    1004                 : /* -------------------------------------------------------------------- */
    1005                 : /*      Add BLOCKA TRE if requested.                                    */
    1006                 : /* -------------------------------------------------------------------- */
    1007            1184 :     if( CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL )
    1008                 :     {
    1009               3 :         NITFWriteBLOCKA( fp,
    1010                 :                          nCur + (GUIntBig)nUDIDLOffset, 
    1011                 :                          nCur + (GUIntBig)nOffset, 
    1012                 :                          &nOffset, 
    1013                 :                          papszOptions );
    1014                 :     }
    1015                 : 
    1016            1184 :     if( CSLFetchNameValue(papszOptions,"TRE") != NULL )
    1017                 :     {
    1018              13 :         NITFWriteTREsFromOptions(
    1019                 :             fp,
    1020                 :             nCur + (GUIntBig)nUDIDLOffset, 
    1021                 :             nCur + (GUIntBig)nOffset, 
    1022                 :             &nOffset, 
    1023                 :             papszOptions, "TRE=" );
    1024                 :     }
    1025                 : 
    1026                 : /* -------------------------------------------------------------------- */
    1027                 : /*      Update the image header length in the file header.              */
    1028                 : /* -------------------------------------------------------------------- */
    1029            1184 :     nIHSize = nOffset;
    1030                 : 
    1031            1184 :     if (nIHSize > 999999)
    1032                 :     {
    1033               0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1034                 :                  "Too big image header length : %d", nIHSize);
    1035               0 :         VSIFCloseL( fp );
    1036               0 :         return FALSE;
    1037                 :     }
    1038                 : 
    1039            1184 :     PLACE( 363 + iIM * 16, LISH1, CPLSPrintf("%06d",nIHSize)      );
    1040                 : 
    1041            1184 :     nCur += nIHSize + nImageSize;
    1042                 :   }
    1043                 : 
    1044                 : /* -------------------------------------------------------------------- */
    1045                 : /*      Compute and update CLEVEL ("complexity" level).                 */
    1046                 : /*      See: http://164.214.2.51/ntb/baseline/docs/2500b/2500b_not2.pdf */
    1047                 : /*            page 96u                                                  */
    1048                 : /* -------------------------------------------------------------------- */
    1049             186 :     nCLevel = 3;
    1050             186 :     if (nBands > 9 || nIM > 20 || nPixels > 2048 || nLines > 2048 ||
    1051                 :         nNPPBH > 2048 || nNPPBV > 2048 || nCur > 52428799 )
    1052                 :     {
    1053               6 :         nCLevel = 5;
    1054                 :     }
    1055             186 :     if (nPixels > 8192 || nLines > 8192 ||
    1056                 :         nNPPBH > 8192 || nNPPBV > 8192 || nCur > 1073741833)
    1057                 :     {
    1058               2 :         nCLevel = 6;
    1059                 :     }
    1060             186 :     if (nBands > 256 || nPixels > 65536 || nLines > 65536 ||
    1061                 :         nCur > 2147483647)
    1062                 :     {
    1063               2 :         nCLevel = 7;
    1064                 :     }
    1065             186 :     OVR( 2,  9, CLEVEL,       CPLSPrintf("%02d", nCLevel)     );
    1066                 : 
    1067                 : /* -------------------------------------------------------------------- */
    1068                 : /*      Update total file length                                        */
    1069                 : /* -------------------------------------------------------------------- */
    1070                 : 
    1071                 :     /* According to the spec, CLEVEL 7 supports up to 10,737,418,330 bytes */
    1072                 :     /* but we can support technically much more */
    1073             186 :     if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12 - 1)
    1074                 :     {
    1075               0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1076                 :                  "Too big file : " CPL_FRMT_GUIB, nCur);
    1077               0 :         VSIFCloseL( fp );
    1078               0 :         return FALSE;
    1079                 :     }
    1080                 : 
    1081             186 :     PLACE( 342, FL,
    1082                 :           CPLSPrintf( "%012" CPL_FRMT_GB_WITHOUT_PREFIX "d", nCur) );
    1083                 : 
    1084                 : /* -------------------------------------------------------------------- */
    1085                 : /*      Grow file to full required size by writing one byte at the end. */
    1086                 : /* -------------------------------------------------------------------- */
    1087             186 :     if( EQUAL(pszIC,"NC") )
    1088                 :     {
    1089             181 :         char cNul = 0;
    1090             181 :         VSIFSeekL( fp, nCur-1, SEEK_SET );
    1091             181 :         VSIFWriteL( &cNul, 1, 1, fp );
    1092                 :     }
    1093                 : 
    1094             186 :     VSIFCloseL( fp );
    1095                 : 
    1096             186 :     return TRUE;
    1097                 : }
    1098                 : 
    1099                 : /************************************************************************/
    1100                 : /*                            NITFWriteTRE()                            */
    1101                 : /************************************************************************/
    1102                 : 
    1103                 : static int NITFWriteTRE( FILE* fp,
    1104                 :                          vsi_l_offset nOffsetUDIDL, 
    1105                 :                          vsi_l_offset nOffsetTREInHeader, 
    1106                 :                          int  *pnOffset,
    1107                 :                          const char *pszTREName, char *pabyTREData, int nTREDataSize )
    1108                 : 
    1109              19 : {
    1110                 :     char szTemp[12];
    1111                 :     int  nOldOffset;
    1112                 : 
    1113                 : /* -------------------------------------------------------------------- */
    1114                 : /*      Update IXSHDL.                                                  */
    1115                 : /* -------------------------------------------------------------------- */
    1116              19 :     VSIFSeekL(fp, nOffsetUDIDL + 5, SEEK_SET);
    1117              19 :     VSIFReadL(szTemp, 1, 5, fp);
    1118              19 :     szTemp[5] = 0;
    1119              19 :     nOldOffset = atoi(szTemp);
    1120                 : 
    1121              19 :     if( nOldOffset == 0 )
    1122                 :     {
    1123              16 :         nOldOffset = 3;
    1124              16 :         PLACE(nOffsetUDIDL+10, IXSOFL, "000" );
    1125              16 :         *pnOffset += 3;
    1126                 :     }
    1127                 : 
    1128              19 :     if (nOldOffset + 11 + nTREDataSize > 99999 || nTREDataSize > 99999)
    1129                 :     {
    1130               2 :         CPLError(CE_Failure, CPLE_AppDefined, "Too big TRE to be written");
    1131               2 :         return FALSE;
    1132                 :     }
    1133                 : 
    1134              17 :     sprintf( szTemp, "%05d", nOldOffset + 11 + nTREDataSize );
    1135              17 :     PLACE( nOffsetUDIDL + 5, IXSHDL, szTemp );
    1136                 : 
    1137                 : /* -------------------------------------------------------------------- */
    1138                 : /*      Create TRE prefix.                                              */
    1139                 : /* -------------------------------------------------------------------- */
    1140              17 :     sprintf( szTemp, "%-6s%05d", 
    1141                 :              pszTREName, nTREDataSize );
    1142              17 :     VSIFSeekL(fp, nOffsetTREInHeader + nOldOffset, SEEK_SET);
    1143              17 :     VSIFWriteL(szTemp, 11, 1, fp);
    1144              17 :     VSIFWriteL(pabyTREData, nTREDataSize, 1, fp);
    1145                 : 
    1146                 : /* -------------------------------------------------------------------- */
    1147                 : /*      Increment values.                                               */
    1148                 : /* -------------------------------------------------------------------- */
    1149              17 :     *pnOffset += nTREDataSize + 11;
    1150                 : 
    1151              17 :     return TRUE;
    1152                 : }
    1153                 : 
    1154                 : /************************************************************************/
    1155                 : /*                   NITFWriteTREsFromOptions()                         */
    1156                 : /************************************************************************/
    1157                 : 
    1158                 : static int NITFWriteTREsFromOptions(
    1159                 :     FILE* fp,
    1160                 :     vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
    1161                 :     int *pnOffset,
    1162                 :     char **papszOptions, const char* pszTREPrefix )    
    1163                 : 
    1164              16 : {
    1165                 :     int bIgnoreBLOCKA = 
    1166              16 :         CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
    1167                 :     int iOption;
    1168              16 :     int nTREPrefixLen = strlen(pszTREPrefix);
    1169                 : 
    1170              16 :     if( papszOptions == NULL )
    1171               0 :         return TRUE;
    1172                 : 
    1173              50 :     for( iOption = 0; papszOptions[iOption] != NULL; iOption++ )
    1174                 :     {
    1175                 :         const char *pszEscapedContents;
    1176                 :         char *pszUnescapedContents;
    1177                 :         char *pszTREName;
    1178                 :         int  nContentLength;
    1179                 :         const char* pszSpace;
    1180                 : 
    1181              37 :         if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
    1182              18 :             continue;
    1183                 : 
    1184              19 :         if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
    1185                 :             && bIgnoreBLOCKA )
    1186               1 :             continue;
    1187                 :         
    1188                 :         /* We do no longer use CPLParseNameValue() as it removes leading spaces */
    1189                 :         /* from the value (see #3088) */
    1190              18 :         pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
    1191              18 :         if (pszSpace == NULL)
    1192                 :         {
    1193               1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1194                 :                      "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
    1195               1 :             return FALSE;
    1196                 :         }
    1197                 :         
    1198              17 :         pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
    1199              17 :         pszTREName[pszSpace - (papszOptions[iOption]+nTREPrefixLen)] = '\0';
    1200              17 :         pszEscapedContents = pszSpace + 1;
    1201                 : 
    1202              17 :         pszUnescapedContents = 
    1203                 :             CPLUnescapeString( pszEscapedContents, &nContentLength,
    1204                 :                                CPLES_BackslashQuotable );
    1205                 : 
    1206              17 :         if( !NITFWriteTRE( fp,
    1207                 :                            nOffsetUDIDL, nOffsetTRE,
    1208                 :                            pnOffset,
    1209                 :                            pszTREName, pszUnescapedContents, 
    1210                 :                            nContentLength ) )
    1211                 :         {
    1212               2 :             CPLFree( pszTREName );
    1213               2 :             CPLFree( pszUnescapedContents );
    1214               2 :             return FALSE;
    1215                 :         }
    1216                 :         
    1217              15 :         CPLFree( pszTREName );
    1218              15 :         CPLFree( pszUnescapedContents );
    1219                 : 
    1220                 :     }
    1221                 : 
    1222              13 :     return TRUE;
    1223                 : }
    1224                 : 
    1225                 : /************************************************************************/
    1226                 : /*                          NITFWriteBLOCKA()                           */
    1227                 : /************************************************************************/
    1228                 : 
    1229                 : static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL, 
    1230                 :                             vsi_l_offset nOffsetTRE, 
    1231                 :                             int *pnOffset,
    1232                 :                             char **papszOptions )
    1233                 : 
    1234               3 : {
    1235                 :     static const char *apszFields[] = { 
    1236                 :         "BLOCK_INSTANCE", "0", "2",
    1237                 :         "N_GRAY",         "2", "5",
    1238                 :         "L_LINES",        "7", "5",
    1239                 :         "LAYOVER_ANGLE",  "12", "3",
    1240                 :         "SHADOW_ANGLE",   "15", "3",
    1241                 :         "BLANKS",         "18", "16",
    1242                 :         "FRLC_LOC",       "34", "21",
    1243                 :         "LRLC_LOC",       "55", "21",
    1244                 :         "LRFC_LOC",       "76", "21",
    1245                 :         "FRFC_LOC",       "97", "21",
    1246                 :         NULL,             NULL, NULL };
    1247                 :     int nBlockCount = 
    1248               3 :         atoi(CSLFetchNameValue( papszOptions, "BLOCKA_BLOCK_COUNT" ));
    1249                 :     int iBlock;
    1250                 : 
    1251                 : /* ==================================================================== */
    1252                 : /*      Loop over all the blocks we have metadata for.                  */
    1253                 : /* ==================================================================== */
    1254               5 :     for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
    1255                 :     {
    1256                 :         char szBLOCKA[123];
    1257                 :         int iField;
    1258                 : 
    1259                 : /* -------------------------------------------------------------------- */
    1260                 : /*      Write all fields.                                               */
    1261                 : /* -------------------------------------------------------------------- */
    1262              32 :         for( iField = 0; apszFields[iField*3] != NULL; iField++ )
    1263                 :         {
    1264                 :             char szFullFieldName[64];
    1265              30 :             int  iStart = atoi(apszFields[iField*3+1]);
    1266              30 :             int  iSize = atoi(apszFields[iField*3+2]);
    1267                 :             const char *pszValue;
    1268                 : 
    1269              30 :             sprintf( szFullFieldName, "BLOCKA_%s_%02d", 
    1270                 :                      apszFields[iField*3 + 0], iBlock );
    1271                 : 
    1272              30 :             pszValue = CSLFetchNameValue( papszOptions, szFullFieldName );
    1273              30 :             if( pszValue == NULL )
    1274              14 :                 pszValue = "";
    1275                 : 
    1276              30 :             if (strlen(pszValue) > (size_t)iSize)
    1277                 :             {
    1278               1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1279                 :                          "Too much data for %s. Got %d bytes, max allowed is %d",
    1280                 :                          szFullFieldName, (int)strlen(pszValue), iSize);
    1281               1 :                 return FALSE;
    1282                 :             }
    1283                 : 
    1284                 :             /* Right align value and left pad with spaces */
    1285              29 :             memset( szBLOCKA + iStart, ' ', iSize );
    1286              29 :             memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
    1287                 :                     pszValue, strlen(pszValue) );
    1288                 :         }
    1289                 : 
    1290                 :         // required field - semantics unknown. 
    1291               2 :         memcpy( szBLOCKA + 118, "010.0", 5);
    1292                 : 
    1293               2 :         if( !NITFWriteTRE( fp,
    1294                 :                            nOffsetUDIDL, nOffsetTRE, 
    1295                 :                            pnOffset,
    1296                 :                            "BLOCKA", szBLOCKA, 123 ) )
    1297               0 :             return FALSE;
    1298                 :     }
    1299                 :     
    1300               2 :     return TRUE;
    1301                 : }
    1302                 :                       
    1303                 : /************************************************************************/
    1304                 : /*                       NITFCollectSegmentInfo()                       */
    1305                 : /*                                                                      */
    1306                 : /*      Collect the information about a set of segments of a            */
    1307                 : /*      particular type from the NITF file header, and add them to      */
    1308                 : /*      the segment list in the NITFFile object.                        */
    1309                 : /************************************************************************/
    1310                 : 
    1311                 : static int 
    1312                 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLen, int nOffset, const char szType[3],
    1313                 :                         int nHeaderLenSize, int nDataLenSize, GUIntBig *pnNextData )
    1314                 : 
    1315            3226 : {
    1316                 :     char szTemp[12];
    1317                 :     int  nCount, nSegDefSize, iSegment;
    1318                 : 
    1319                 : /* -------------------------------------------------------------------- */
    1320                 : /*      Get the segment count, and grow the segmentinfo array           */
    1321                 : /*      accordingly.                                                    */
    1322                 : /* -------------------------------------------------------------------- */
    1323            3226 :     if ( nFileHeaderLen < nOffset + 3 )
    1324                 :     {
    1325               1 :         CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
    1326               1 :         return -1;
    1327                 :     }
    1328                 : 
    1329            3225 :     NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
    1330            3225 :     nCount = atoi(szTemp);
    1331                 : 
    1332            3225 :     if( nCount <= 0 )
    1333            2635 :         return nOffset + 3;
    1334                 : 
    1335             590 :     nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
    1336             590 :     if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
    1337                 :     {
    1338               1 :         CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
    1339               1 :         return -1;
    1340                 :     }
    1341                 : 
    1342             589 :     if( psFile->pasSegmentInfo == NULL )
    1343             539 :         psFile->pasSegmentInfo = (NITFSegmentInfo *)
    1344                 :             CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
    1345                 :     else
    1346              50 :         psFile->pasSegmentInfo = (NITFSegmentInfo *)
    1347                 :             CPLRealloc( psFile->pasSegmentInfo, 
    1348                 :                         sizeof(NITFSegmentInfo)
    1349                 :                         * (psFile->nSegmentCount+nCount) );
    1350                 : 
    1351                 : /* -------------------------------------------------------------------- */
    1352                 : /*      Collect detailed about segment.                                 */
    1353                 : /* -------------------------------------------------------------------- */
    1354            6870 :     for( iSegment = 0; iSegment < nCount; iSegment++ )
    1355                 :     {
    1356            6283 :         NITFSegmentInfo *psInfo = psFile->pasSegmentInfo+psFile->nSegmentCount;
    1357                 :         
    1358            6283 :         psInfo->nDLVL = -1;
    1359            6283 :         psInfo->nALVL = -1;
    1360            6283 :         psInfo->nLOC_R = -1;
    1361            6283 :         psInfo->nLOC_C = -1;
    1362            6283 :         psInfo->nCCS_R = -1;
    1363            6283 :         psInfo->nCCS_C = -1;
    1364                 : 
    1365            6283 :         psInfo->hAccess = NULL;
    1366            6283 :         strcpy( psInfo->szSegmentType, szType );
    1367                 :         
    1368            6283 :         psInfo->nSegmentHeaderSize = 
    1369                 :             atoi(NITFGetField(szTemp, psFile->pachHeader, 
    1370                 :                               nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize), 
    1371                 :                               nHeaderLenSize));
    1372            6283 :         if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
    1373                 :         {
    1374               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
    1375               1 :             return -1;
    1376                 :         }
    1377                 : 
    1378            6282 :         if (strcmp(szType, "DE") == 0 && psInfo->nSegmentHeaderSize == 207)
    1379                 :         {
    1380                 :             /* DMAAC A.TOC files have a wrong header size. It says 207 but it is 209 really */
    1381               0 :             psInfo->nSegmentHeaderSize = 209;
    1382                 :         }
    1383                 : 
    1384            6282 :         psInfo->nSegmentSize = 
    1385                 :             CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader, 
    1386                 :                               nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize) 
    1387                 :                               + nHeaderLenSize,
    1388                 :                               nDataLenSize), nDataLenSize);
    1389            6282 :         if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
    1390                 :         {
    1391               1 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
    1392               1 :             return -1;
    1393                 :         }
    1394                 : 
    1395            6281 :         psInfo->nSegmentHeaderStart = *pnNextData;
    1396            6281 :         psInfo->nSegmentStart = *pnNextData + psInfo->nSegmentHeaderSize;
    1397                 : 
    1398            6281 :         *pnNextData += (psInfo->nSegmentHeaderSize+psInfo->nSegmentSize);
    1399            6281 :         psFile->nSegmentCount++;
    1400                 :     }
    1401                 : 
    1402             587 :     return nOffset + nSegDefSize + 3;
    1403                 : }
    1404                 : 
    1405                 : /************************************************************************/
    1406                 : /*                            NITFGetField()                            */
    1407                 : /*                                                                      */
    1408                 : /*      Copy a field from a passed in header buffer into a temporary    */
    1409                 : /*      buffer and zero terminate it.                                   */
    1410                 : /************************************************************************/
    1411                 : 
    1412                 : char *NITFGetField( char *pszTarget, const char *pszSource, 
    1413                 :                     int nStart, int nLength )
    1414                 : 
    1415          798825 : {
    1416          798825 :     memcpy( pszTarget, pszSource + nStart, nLength );
    1417          798825 :     pszTarget[nLength] = '\0';
    1418                 : 
    1419          798825 :     return pszTarget;
    1420                 : }
    1421                 : 
    1422                 : /************************************************************************/
    1423                 : /*                            NITFFindTRE()                             */
    1424                 : /************************************************************************/
    1425                 : 
    1426                 : const char *NITFFindTRE( const char *pszTREData, int nTREBytes,
    1427                 :                          const char *pszTag, int *pnFoundTRESize )
    1428                 : 
    1429           18150 : {
    1430                 :     char szTemp[100];
    1431                 : 
    1432           73487 :     while( nTREBytes >= 11 )
    1433                 :     {
    1434           37292 :         int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
    1435           37292 :         if (nThisTRESize < 0)
    1436                 :         {
    1437              20 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1438              20 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
    1439                 :                      nThisTRESize, szTemp);
    1440              20 :             return NULL;
    1441                 :         }
    1442           37272 :         if (nTREBytes - 11 < nThisTRESize)
    1443                 :         {
    1444              20 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1445              20 :             CPLError(CE_Failure, CPLE_AppDefined,
    1446                 :                     "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
    1447                 :                     szTemp, nTREBytes - 11, nThisTRESize);
    1448              20 :             return NULL;
    1449                 :         }
    1450                 : 
    1451           37252 :         if( EQUALN(pszTREData,pszTag,6) )
    1452                 :         {
    1453              65 :             if( pnFoundTRESize != NULL )
    1454              65 :                 *pnFoundTRESize = nThisTRESize;
    1455                 : 
    1456              65 :             return pszTREData + 11;
    1457                 :         }
    1458                 : 
    1459           37187 :         nTREBytes -= (nThisTRESize + 11);
    1460           37187 :         pszTREData += (nThisTRESize + 11);
    1461                 :     }
    1462                 : 
    1463           18045 :     return NULL;
    1464                 : }
    1465                 : 
    1466                 : /************************************************************************/
    1467                 : /*                     NITFFindTREByIndex()                             */
    1468                 : /************************************************************************/
    1469                 : 
    1470                 : const char *NITFFindTREByIndex( const char *pszTREData, int nTREBytes,
    1471                 :                                 const char *pszTag, int nTreIndex,
    1472                 :                                 int *pnFoundTRESize )
    1473                 : 
    1474             520 : {
    1475                 :     char szTemp[100];
    1476                 : 
    1477            1123 :     while( nTREBytes >= 11 )
    1478                 :     {
    1479             101 :         int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
    1480             101 :         if (nThisTRESize < 0)
    1481                 :         {
    1482               2 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1483               2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
    1484                 :                      nThisTRESize, szTemp);
    1485               2 :             return NULL;
    1486                 :         }
    1487              99 :         if (nTREBytes - 11 < nThisTRESize)
    1488                 :         {
    1489               2 :             NITFGetField(szTemp, pszTREData, 0, 6 );
    1490               2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1491                 :                     "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
    1492                 :                     szTemp, nTREBytes - 11, nThisTRESize);
    1493               2 :             return NULL;
    1494                 :         }
    1495                 : 
    1496              97 :         if( EQUALN(pszTREData,pszTag,6) )
    1497                 :         {
    1498              28 :             if ( nTreIndex <= 0)
    1499                 :             {
    1500              14 :                 if( pnFoundTRESize != NULL )
    1501              14 :                     *pnFoundTRESize = nThisTRESize;
    1502                 : 
    1503              14 :                 return pszTREData + 11;
    1504                 :             }
    1505                 : 
    1506                 :             /* Found a prevoius one - skip it ... */
    1507              14 :             nTreIndex--;
    1508                 :         }
    1509                 : 
    1510              83 :         nTREBytes -= (nThisTRESize + 11);
    1511              83 :         pszTREData += (nThisTRESize + 11);
    1512                 :     }
    1513                 : 
    1514             502 :     return NULL;
    1515                 : }
    1516                 : 
    1517                 : /************************************************************************/
    1518                 : /*                        NITFExtractMetadata()                         */
    1519                 : /************************************************************************/
    1520                 : 
    1521                 : void NITFExtractMetadata( char ***ppapszMetadata, const char *pachHeader,
    1522                 :                           int nStart, int nLength, const char *pszName )
    1523                 : 
    1524          137256 : {
    1525                 :     char szWork[400];
    1526                 : 
    1527                 :     /* trim white space */
    1528         1840757 :     while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
    1529         1566245 :         nLength--;
    1530                 : 
    1531          137256 :     memcpy( szWork, pachHeader + nStart, nLength );
    1532          137256 :     szWork[nLength] = '\0';
    1533                 : 
    1534          137256 :     *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, szWork );
    1535          137256 : }
    1536                 :                           
    1537                 : /************************************************************************/
    1538                 : /*        NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude()         */
    1539                 : /*                                                                      */
    1540                 : /*      The input is a geocentric latitude in degrees.  The output      */
    1541                 : /*      is a geodetic latitude in degrees.                              */
    1542                 : /************************************************************************/
    1543                 : 
    1544                 : /*
    1545                 :  * "The angle L' is called "geocentric latitude" and is defined as the
    1546                 :  * angle between the equatorial plane and the radius from the geocenter.
    1547                 :  * 
    1548                 :  * The angle L is called "geodetic latitude" and is defined as the angle
    1549                 :  * between the equatorial plane and the normal to the surface of the
    1550                 :  * ellipsoid.  The word "latitude" usually means geodetic latitude.  This
    1551                 :  * is the basis for most of the maps and charts we use.  The normal to the
    1552                 :  * surface is the direction that a plumb bob would hang were it not for
    1553                 :  * local anomalies in the earth's gravitational field."
    1554                 :  */
    1555                 : 
    1556                 : double NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( double dfLat )
    1557                 : 
    1558               0 : {
    1559                 :     /* WGS84 Ellipsoid */
    1560               0 :     double a = 6378137.0;
    1561               0 :     double b = 6356752.3142;
    1562               0 :     double dfPI = 3.14159265358979323;
    1563                 : 
    1564                 :     /* convert to radians */
    1565               0 :     dfLat = dfLat * dfPI / 180.0;
    1566                 : 
    1567                 :     /* convert to geodetic */
    1568               0 :     dfLat = atan( ((a*a)/(b*b)) * tan(dfLat) );
    1569                 : 
    1570                 :     /* convert back to degrees */
    1571               0 :     dfLat = dfLat * 180.0 / dfPI;
    1572                 : 
    1573               0 :     return dfLat;
    1574                 : }
    1575                 : 
    1576                 : 
    1577                 : /************************************************************************/
    1578                 : /*                        NITFGetSeriesInfo()                           */
    1579                 : /************************************************************************/
    1580                 : 
    1581                 : static const NITFSeries nitfSeries[] =
    1582                 : {
    1583                 :     { "GN", "GNC", "1:5M", "Global Navigation Chart", "CADRG"},
    1584                 :     { "JN", "JNC", "1:2M", "Jet Navigation Chart", "CADRG"},
    1585                 :     { "OH", "VHRC", "1:1M", "VFR Helicopter Route Chart", "CADRG"},
    1586                 :     { "ON", "ONC", "1:1M", "Operational Navigation Chart", "CADRG"},
    1587                 :     { "OW", "WAC", "1:1M", "High Flying Chart - Host Nation", "CADRG"},
    1588                 :     { "TP", "TPC", "1:500K", "Tactical Pilotage Chart", "CADRG"},
    1589                 :     { "LF", "LFC-FR (Day)", "1:500K", "Low Flying Chart (Day) - Host Nation", "CADRG"},
    1590                 :     { "L1", "LFC-1", "1:500K", "Low Flying Chart (TED #1)", "CADRG"},
    1591                 :     { "L2", "LFC-2", "1:500K", "Low Flying Chart (TED #2)", "CADRG"},
    1592                 :     { "L3", "LFC-3", "1:500K", "Low Flying Chart (TED #3)", "CADRG"},
    1593                 :     { "L4", "LFC-4", "1:500K", "Low Flying Chart (TED #4)", "CADRG"},
    1594                 :     { "L5", "LFC-5", "1:500K", "Low Flying Chart (TED #5)", "CADRG"},
    1595                 :     { "LN", "LN (Night)", "1:500K", "Low Flying Chart (Night) - Host Nation", "CADRG"},
    1596                 :     { "JG", "JOG", "1:250K", "Joint Operation Graphic", "CADRG"},
    1597                 :     { "JA", "JOG-A", "1:250K", "Joint Operation Graphic - Air", "CADRG"},
    1598                 :     { "JR", "JOG-R", "1:250K", "Joint Operation Graphic - Radar", "CADRG"},
    1599                 :     { "JO", "OPG", "1:250K", "Operational Planning Graphic", "CADRG"},
    1600                 :     { "VT", "VTAC", "1:250K", "VFR Terminal Area Chart", "CADRG"},
    1601                 :     { "F1", "TFC-1", "1:250K", "Transit Flying Chart (TED #1)", "CADRG"},
    1602                 :     { "F2", "TFC-2", "1:250K", "Transit Flying Chart (TED #2)", "CADRG"},
    1603                 :     { "F3", "TFC-3", "1:250K", "Transit Flying Chart (TED #3)", "CADRG"},
    1604                 :     { "F4", "TFC-4", "1:250K", "Transit Flying Chart (TED #4)", "CADRG"},
    1605                 :     { "F5", "TFC-5", "1:250K", "Transit Flying Chart (TED #5)", "CADRG"},
    1606                 :     { "AT", "ATC", "1:200K", "Series 200 Air Target Chart", "CADRG"},
    1607                 :     { "VH", "HRC", "1:125K", "Helicopter Route Chart", "CADRG"},
    1608                 :     { "TN", "TFC (Night)", "1:250K", "Transit Flying Charget (Night) - Host Nation", "CADRG"},
    1609                 :     { "TR", "TLM 200", "1:200K", "Topographic Line Map 1:200,000 scale", "CADRG"},
    1610                 :     { "TC", "TLM 100", "1:100K", "Topographic Line Map 1:100,000 scale", "CADRG"},
    1611                 :     { "RV", "Riverine", "1:50K", "Riverine Map 1:50,000 scale", "CADRG"},
    1612                 :     { "TL", "TLM 50", "1:50K", "Topographic Line Map 1:50,000 scale", "CADRG"},
    1613                 :     { "UL", "TLM 50 - Other", "1:50K", "Topographic Line Map (other 1:50,000 scale)", "CADRG"},
    1614                 :     { "TT", "TLM 25", "1:25K", "Topographic Line Map 1:25,000 scale", "CADRG"},
    1615                 :     { "TQ", "TLM 24", "1:24K", "Topographic Line Map 1:24,000 scale", "CADRG"},
    1616                 :     { "HA", "HA", "Various", "Harbor and Approach Charts", "CADRG"},
    1617                 :     { "CO", "CO", "Various", "Coastal Charts", "CADRG"},
    1618                 :     { "OA", "OPAREA", "Various", "Naval Range Operation Area Chart", "CADRG"},
    1619                 :     { "CG", "CG", "Various", "City Graphics", "CADRG"},
    1620                 :     { "C1", "CG", "1:10000", "City Graphics", "CADRG"},
    1621                 :     { "C2", "CG", "1:10560", "City Graphics", "CADRG"},
    1622                 :     { "C3", "CG", "1:11000", "City Graphics", "CADRG"},
    1623                 :     { "C4", "CG", "1:11800", "City Graphics", "CADRG"},
    1624                 :     { "C5", "CG", "1:12000", "City Graphics", "CADRG"},
    1625                 :     { "C6", "CG", "1:12500", "City Graphics", "CADRG"},
    1626                 :     { "C7", "CG", "1:12800", "City Graphics", "CADRG"},
    1627                 :     { "C8", "CG", "1:14000", "City Graphics", "CADRG"},
    1628                 :     { "C9", "CG", "1:14700", "City Graphics", "CADRG"},
    1629                 :     { "CA", "CG", "1:15000", "City Graphics", "CADRG"},
    1630                 :     { "CB", "CG", "1:15500", "City Graphics", "CADRG"},
    1631                 :     { "CC", "CG", "1:16000", "City Graphics", "CADRG"},
    1632                 :     { "CD", "CG", "1:16666", "City Graphics", "CADRG"},
    1633                 :     { "CE", "CG", "1:17000", "City Graphics", "CADRG"},
    1634                 :     { "CF", "CG", "1:17500", "City Graphics", "CADRG"},
    1635                 :     { "CH", "CG", "1:18000", "City Graphics", "CADRG"},
    1636                 :     { "CJ", "CG", "1:20000", "City Graphics", "CADRG"},
    1637                 :     { "CK", "CG", "1:21000", "City Graphics", "CADRG"},
    1638                 :     { "CL", "CG", "1:21120", "City Graphics", "CADRG"},
    1639                 :     { "CN", "CG", "1:22000", "City Graphics", "CADRG"},
    1640                 :     { "CP", "CG", "1:23000", "City Graphics", "CADRG"},
    1641                 :     { "CQ", "CG", "1:25000", "City Graphics", "CADRG"},
    1642                 :     { "CR", "CG", "1:26000", "City Graphics", "CADRG"},
    1643                 :     { "CS", "CG", "1:35000", "City Graphics", "CADRG"},
    1644                 :     { "CT", "CG", "1:36000", "City Graphics", "CADRG"},
    1645                 :     { "CM", "CM", "Various", "Combat Charts", "CADRG"},
    1646                 :     { "A1", "CM", "1:10K", "Combat Charts (1:10K)", "CADRG"},
    1647                 :     { "A2", "CM", "1:25K", "Combat Charts (1:25K)", "CADRG"},
    1648                 :     { "A3", "CM", "1:50K", "Combat Charts (1:50K)", "CADRG"},
    1649                 :     { "A4", "CM", "1:100K", "Combat Charts (1:100K)", "CADRG"},
    1650                 :     { "MI", "MIM", "1:50K", "Military Installation Maps", "CADRG"},
    1651                 :     { "M1", "MIM", "Various", "Military Installation Maps (TED #1)", "CADRG"},
    1652                 :     { "M2", "MIM", "Various", "Military Installation Maps (TED #2)", "CADRG"},
    1653                 :     { "VN", "VNC", "1:500K", "Visual Navigation Charts", "CADRG"},
    1654                 :     { "MM", "", "Various", "(Miscellaneous Maps & Charts)", "CADRG"},
    1655                 :     
    1656                 :     { "I1", "", "10m", "Imagery, 10 meter resolution", "CIB"},
    1657                 :     { "I2", "", "5m", "Imagery, 5 meter resolution", "CIB"},
    1658                 :     { "I3", "", "2m", "Imagery, 2 meter resolution", "CIB"},
    1659                 :     { "I4", "", "1m", "Imagery, 1 meter resolution", "CIB"},
    1660                 :     { "I5", "", ".5m", "Imagery, .5 (half) meter resolution", "CIB"},
    1661                 :     { "IV", "", "Various > 10m", "Imagery, greater than 10 meter resolution", "CIB"},
    1662                 :     
    1663                 :     { "D1", "", "100m", "Elevation Data from DTED level 1", "CDTED"},
    1664                 :     { "D2", "", "30m", "Elevation Data from DTED level 2", "CDTED"},
    1665                 : };
    1666                 : 
    1667                 : /* See 24111CN1.pdf paragraph 5.1.4 */
    1668                 : const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
    1669             517 : {
    1670                 :     int i;
    1671             517 :     char seriesCode[3] = {0,0,0};
    1672             517 :     if (pszFilename == NULL) return NULL;
    1673            3363 :     for (i=strlen(pszFilename)-1;i>=0;i--)
    1674                 :     {
    1675            3313 :         if (pszFilename[i] == '.')
    1676                 :         {
    1677             472 :             if (i < (int)strlen(pszFilename) - 3)
    1678                 :             {
    1679             467 :                 seriesCode[0] = pszFilename[i+1];
    1680             467 :                 seriesCode[1] = pszFilename[i+2];
    1681           35511 :                 for(i=0;i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
    1682                 :                 {
    1683           35074 :                     if (EQUAL(seriesCode, nitfSeries[i].code))
    1684                 :                     {
    1685              30 :                         return &nitfSeries[i];
    1686                 :                     }
    1687                 :                 }
    1688             437 :                 return NULL;
    1689                 :             }
    1690                 :         }
    1691                 :     }
    1692              50 :     return NULL;
    1693                 : }
    1694                 : 
    1695                 : /************************************************************************/
    1696                 : /*                       NITFCollectAttachments()                       */
    1697                 : /*                                                                      */
    1698                 : /*      Collect attachment, display level and location info into the    */
    1699                 : /*      segmentinfo structures.                                         */
    1700                 : /************************************************************************/
    1701                 : 
    1702                 : int NITFCollectAttachments( NITFFile *psFile )
    1703                 : 
    1704             376 : {
    1705                 :     int iSegment;
    1706                 : 
    1707                 : /* ==================================================================== */
    1708                 : /*      Loop over all segments.                                         */
    1709                 : /* ==================================================================== */
    1710            5476 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    1711                 :     {
    1712            5119 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
    1713                 : 
    1714                 : /* -------------------------------------------------------------------- */
    1715                 : /*      For image segments, we use the normal image access stuff.       */
    1716                 : /* -------------------------------------------------------------------- */
    1717            5119 :         if( EQUAL(psSegInfo->szSegmentType,"IM") )
    1718                 :         {
    1719            4401 :             NITFImage *psImage = NITFImageAccess( psFile, iSegment );
    1720            4401 :             if (psImage == NULL)
    1721              19 :                 return FALSE;
    1722                 :                 
    1723            4382 :             psSegInfo->nDLVL = psImage->nIDLVL;
    1724            4382 :             psSegInfo->nALVL = psImage->nIALVL;
    1725            4382 :             psSegInfo->nLOC_R = psImage->nILOCRow;
    1726            4382 :             psSegInfo->nLOC_C = psImage->nILOCColumn;
    1727                 :         }
    1728                 : /* -------------------------------------------------------------------- */
    1729                 : /*      For graphic file we need to process the header.                 */
    1730                 : /* -------------------------------------------------------------------- */
    1731             718 :         else if( EQUAL(psSegInfo->szSegmentType,"SY")
    1732                 :                  || EQUAL(psSegInfo->szSegmentType,"GR") )
    1733                 :         {
    1734                 :             char achSubheader[298];
    1735                 :             int  nSTYPEOffset;
    1736                 :             char szTemp[100];
    1737                 : 
    1738                 : /* -------------------------------------------------------------------- */
    1739                 : /*      Load the graphic subheader.                                     */
    1740                 : /* -------------------------------------------------------------------- */
    1741             361 :             if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart, 
    1742                 :                            SEEK_SET ) != 0 
    1743                 :                 || VSIFReadL( achSubheader, 1, sizeof(achSubheader), 
    1744                 :                               psFile->fp ) < 258 )
    1745                 :             {
    1746               1 :                 CPLError( CE_Warning, CPLE_FileIO, 
    1747                 :                           "Failed to read graphic subheader at " CPL_FRMT_GUIB ".", 
    1748                 :                           psSegInfo->nSegmentHeaderStart );
    1749               1 :                 continue;
    1750                 :             }
    1751                 : 
    1752                 :             // NITF 2.0. (also works for NITF 2.1)
    1753             360 :             nSTYPEOffset = 200;
    1754             360 :             if( EQUALN(achSubheader+193,"999998",6) )
    1755             318 :                 nSTYPEOffset += 40;
    1756                 : 
    1757                 : /* -------------------------------------------------------------------- */
    1758                 : /*      Report some standard info.                                      */
    1759                 : /* -------------------------------------------------------------------- */
    1760             360 :             psSegInfo->nDLVL = atoi(NITFGetField(szTemp,achSubheader,
    1761                 :                                                  nSTYPEOffset + 14, 3));
    1762             360 :             psSegInfo->nALVL = atoi(NITFGetField(szTemp,achSubheader,
    1763                 :                                                  nSTYPEOffset + 17, 3));
    1764             360 :             psSegInfo->nLOC_R = atoi(NITFGetField(szTemp,achSubheader,
    1765                 :                                                   nSTYPEOffset + 20, 5));
    1766             360 :             psSegInfo->nLOC_C = atoi(NITFGetField(szTemp,achSubheader,
    1767                 :                                                   nSTYPEOffset + 25, 5));
    1768                 :         }
    1769                 :     }
    1770                 :     
    1771             357 :     return TRUE;
    1772                 : }
    1773                 : 
    1774                 : /************************************************************************/
    1775                 : /*                      NITFReconcileAttachments()                      */
    1776                 : /*                                                                      */
    1777                 : /*      Generate the CCS location information for all the segments      */
    1778                 : /*      if possible.                                                    */
    1779                 : /************************************************************************/
    1780                 : 
    1781                 : int NITFReconcileAttachments( NITFFile *psFile )
    1782                 : 
    1783             384 : {
    1784                 :     int iSegment;
    1785             384 :     int bSuccess = TRUE;
    1786             384 :     int bMadeProgress = FALSE;
    1787                 : 
    1788            5615 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    1789                 :     {
    1790            5231 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
    1791                 :         int iOther;
    1792                 : 
    1793                 :         // already processed?
    1794            5231 :         if( psSegInfo->nCCS_R != -1 )
    1795              48 :             continue;
    1796                 : 
    1797                 :         // unattached segments are straight forward.
    1798            5183 :         if( psSegInfo->nALVL < 1 )
    1799                 :         {
    1800            5020 :             psSegInfo->nCCS_R = psSegInfo->nLOC_R;
    1801            5020 :             psSegInfo->nCCS_C = psSegInfo->nLOC_C;
    1802            5020 :             if( psSegInfo->nCCS_R != -1 )
    1803            4603 :                 bMadeProgress = TRUE;
    1804            5020 :             continue;
    1805                 :         }
    1806                 : 
    1807                 :         // Loc for segment to which we are attached.
    1808             610 :         for( iOther = 0; iOther < psFile->nSegmentCount; iOther++ )
    1809                 :         {
    1810             586 :             NITFSegmentInfo *psOtherSegInfo = psFile->pasSegmentInfo + iOther;
    1811                 :             
    1812             586 :             if( psSegInfo->nALVL == psOtherSegInfo->nDLVL )
    1813                 :             {
    1814             139 :                 if( psOtherSegInfo->nCCS_R != -1 )
    1815                 :                 {
    1816             131 :                     psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
    1817             131 :                     psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
    1818             131 :                     if ( psSegInfo->nCCS_R != -1 )
    1819             131 :                         bMadeProgress = TRUE;
    1820                 :                 }
    1821                 :                 else
    1822                 :                 {
    1823               8 :                     bSuccess = FALSE;
    1824                 :                 }
    1825             139 :                 break;
    1826                 :             }
    1827                 :         }
    1828                 : 
    1829             163 :         if( iOther == psFile->nSegmentCount )
    1830              24 :             bSuccess = FALSE;
    1831                 :     }
    1832                 : 
    1833                 : /* -------------------------------------------------------------------- */
    1834                 : /*      If succeeded or made no progress then return our success        */
    1835                 : /*      flag.  Otherwise make another pass, hopefully filling in        */
    1836                 : /*      more values.                                                    */
    1837                 : /* -------------------------------------------------------------------- */
    1838             384 :     if( bSuccess || !bMadeProgress )
    1839             376 :         return bSuccess;
    1840                 :     else
    1841               8 :         return NITFReconcileAttachments( psFile );
    1842                 : }

Generated by: LTP GCOV extension version 1.5