LCOV - code coverage report
Current view: directory - frmts/nitf - nitffile.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 678 581 85.7 %
Date: 2010-01-09 Functions: 16 15 93.8 %

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

Generated by: LCOV version 1.7