LTP GCOV extension - code coverage report
Current view: directory - frmts/nitf - nitfdataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 1987
Code covered: 79.9 % Executed lines: 1587

       1                 : /******************************************************************************
       2                 :  * $Id: nitfdataset.cpp 19905 2010-06-23 20:50:48Z rouault $
       3                 :  *
       4                 :  * Project:  NITF Read/Write Translator
       5                 :  * Purpose:  GDALDataset/GDALRasterBand implementation on top of "nitflib".
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2002, Frank Warmerdam
      10                 :  *
      11                 :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12                 :  * represented by the Minister of National Defence, 2006.
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  *
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  *
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      25                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  ****************************************************************************/
      32                 : 
      33                 : #include "gdal_pam.h"
      34                 : #include "nitflib.h"
      35                 : #include "ogr_spatialref.h"
      36                 : #include "cpl_string.h"
      37                 : #include "cpl_csv.h"
      38                 : #include "gdal_proxy.h"
      39                 : 
      40                 : CPL_CVSID("$Id: nitfdataset.cpp 19905 2010-06-23 20:50:48Z rouault $");
      41                 : 
      42                 : static void NITFPatchImageLength( const char *pszFilename,
      43                 :                                   GUIntBig nImageOffset, 
      44                 :                                   GIntBig nPixelCount, const char *pszIC );
      45                 : static int NITFWriteCGMSegments( const char *pszFilename, char **papszList );
      46                 : static void NITFWriteTextSegments( const char *pszFilename, char **papszList );
      47                 : 
      48                 : static CPLErr NITFSetColorInterpretation( NITFImage *psImage, 
      49                 :                                           int nBand,
      50                 :                                           GDALColorInterp eInterp );
      51                 : #ifdef JPEG_SUPPORTED
      52                 : static int NITFWriteJPEGImage( GDALDataset *, FILE *, vsi_l_offset, char **,
      53                 :                                GDALProgressFunc pfnProgress, 
      54                 :                                void * pProgressData );
      55                 : #endif
      56                 : 
      57                 : /************************************************************************/
      58                 : /* ==================================================================== */
      59                 : /*        NITFDataset       */
      60                 : /* ==================================================================== */
      61                 : /************************************************************************/
      62                 : 
      63                 : class NITFRasterBand;
      64                 : class NITFWrapperRasterBand;
      65                 : 
      66                 : class NITFDataset : public GDALPamDataset
      67                 : {
      68                 :     friend class NITFRasterBand;
      69                 :     friend class NITFWrapperRasterBand;
      70                 : 
      71                 :     NITFFile    *psFile;
      72                 :     NITFImage   *psImage;
      73                 : 
      74                 :     GDALPamDataset *poJ2KDataset;
      75                 :     int         bJP2Writing;
      76                 : 
      77                 :     GDALPamDataset *poJPEGDataset;
      78                 : 
      79                 :     int         bGotGeoTransform;
      80                 :     double      adfGeoTransform[6];
      81                 : 
      82                 :     char        *pszProjection;
      83                 : 
      84                 :     int         nGCPCount;
      85                 :     GDAL_GCP    *pasGCPList;
      86                 :     char        *pszGCPProjection;
      87                 : 
      88                 :     GDALMultiDomainMetadata oSpecialMD;
      89                 : 
      90                 :     void         InitializeCGMMetadata();
      91                 :     void         InitializeTextMetadata();
      92                 :     void         InitializeTREMetadata();
      93                 : 
      94                 :     GIntBig     *panJPEGBlockOffset;
      95                 :     GByte       *pabyJPEGBlock;
      96                 :     int          nQLevel;
      97                 : 
      98                 :     int          ScanJPEGQLevel( GUIntBig *pnDataStart );
      99                 :     CPLErr       ScanJPEGBlocks( void );
     100                 :     CPLErr       ReadJPEGBlock( int, int );
     101                 :     void         CheckGeoSDEInfo();
     102                 : 
     103                 :     int          nIMIndex;
     104                 :     CPLString    osNITFFilename;
     105                 : 
     106                 :     CPLString    osRSetVRT;
     107                 :     int          CheckForRSets( const char *pszFilename );
     108                 : 
     109                 :     char       **papszTextMDToWrite;
     110                 :     char       **papszCgmMDToWrite;
     111                 : 
     112                 :   public:
     113                 :                  NITFDataset();
     114                 :                  ~NITFDataset();
     115                 : 
     116                 :     virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     117                 :                                int nBufXSize, int nBufYSize, 
     118                 :                                GDALDataType eDT, 
     119                 :                                int nBandCount, int *panBandList,
     120                 :                                char **papszOptions );
     121                 : 
     122                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     123                 :                               void *, int, int, GDALDataType,
     124                 :                               int, int *, int, int, int );
     125                 : 
     126                 :     virtual const char *GetProjectionRef(void);
     127                 :     virtual CPLErr SetProjection( const char * );
     128                 :     virtual CPLErr GetGeoTransform( double * );
     129                 :     virtual CPLErr SetGeoTransform( double * );
     130                 : 
     131                 :     virtual int    GetGCPCount();
     132                 :     virtual const char *GetGCPProjection();
     133                 :     virtual const GDAL_GCP *GetGCPs();
     134                 : 
     135                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
     136                 :     virtual const char *GetMetadataItem( const char * pszName,
     137                 :                                          const char * pszDomain = "" );
     138                 :     virtual void   FlushCache();
     139                 :     virtual CPLErr IBuildOverviews( const char *, int, int *,
     140                 :                                     int, int *, GDALProgressFunc, void * );
     141                 : 
     142                 :     static int          Identify( GDALOpenInfo * );
     143                 :     static GDALDataset *Open( GDALOpenInfo *, GDALDataset *poWritableJ2KDataset,
     144                 :                               int bOpenForCreate);
     145                 :     static GDALDataset *Open( GDALOpenInfo * );
     146                 :     static GDALDataset *
     147                 :     NITFCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
     148                 :                     int bStrict, char **papszOptions, 
     149                 :                     GDALProgressFunc pfnProgress, void * pProgressData );
     150                 :     static GDALDataset *
     151                 :              NITFDatasetCreate( const char *pszFilename,
     152                 :                                 int nXSize, int nYSize, int nBands,
     153                 :                                 GDALDataType eType, char **papszOptions );
     154                 : 
     155                 : };
     156                 : 
     157                 : /************************************************************************/
     158                 : /*                       NITFMakeColorTable()                           */
     159                 : /************************************************************************/
     160                 : 
     161          210664 : static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
     162                 : {
     163          210664 :     GDALColorTable* poColorTable = NULL;
     164                 : 
     165          210664 :     if( psBandInfo->nSignificantLUTEntries > 0 )
     166                 :     {
     167                 :         int  iColor;
     168                 : 
     169              39 :         poColorTable = new GDALColorTable();
     170                 : 
     171            7790 :         for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
     172                 :         {
     173                 :             GDALColorEntry sEntry;
     174                 : 
     175            7751 :             sEntry.c1 = psBandInfo->pabyLUT[  0 + iColor];
     176            7751 :             sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
     177            7751 :             sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
     178            7751 :             sEntry.c4 = 255;
     179                 : 
     180            7751 :             poColorTable->SetColorEntry( iColor, &sEntry );
     181                 :         }
     182                 : 
     183              39 :         if (psImage->bNoDataSet)
     184                 :         {
     185                 :             GDALColorEntry sEntry;
     186              30 :             sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
     187              30 :             poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
     188                 :         }
     189                 :     }
     190                 : 
     191                 : /* -------------------------------------------------------------------- */
     192                 : /*      We create a color table for 1 bit data too...                   */
     193                 : /* -------------------------------------------------------------------- */
     194          210664 :     if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
     195                 :     {
     196                 :         GDALColorEntry sEntry;
     197                 : 
     198              18 :         poColorTable = new GDALColorTable();
     199                 : 
     200              18 :         sEntry.c1 = 0;
     201              18 :         sEntry.c2 = 0;
     202              18 :         sEntry.c3 = 0;
     203              18 :         sEntry.c4 = 255;
     204              18 :         poColorTable->SetColorEntry( 0, &sEntry );
     205                 : 
     206              18 :         sEntry.c1 = 255;
     207              18 :         sEntry.c2 = 255;
     208              18 :         sEntry.c3 = 255;
     209              18 :         sEntry.c4 = 255;
     210              18 :         poColorTable->SetColorEntry( 1, &sEntry );
     211                 :     }
     212                 :     
     213          210664 :     return poColorTable;
     214                 : }
     215                 : 
     216                 : /************************************************************************/
     217                 : /* ==================================================================== */
     218                 : /*                            NITFRasterBand                             */
     219                 : /* ==================================================================== */
     220                 : /************************************************************************/
     221                 : 
     222                 : class NITFRasterBand : public GDALPamRasterBand
     223                 : {
     224                 :     friend class NITFDataset;
     225                 : 
     226                 :     NITFImage   *psImage;
     227                 : 
     228                 :     GDALColorTable *poColorTable;
     229                 : 
     230                 :     GByte       *pUnpackData;
     231                 : 
     232                 :   public:
     233                 :                    NITFRasterBand( NITFDataset *, int );
     234                 :                   ~NITFRasterBand();
     235                 : 
     236                 :     virtual CPLErr IReadBlock( int, int, void * );
     237                 :     virtual CPLErr IWriteBlock( int, int, void * );
     238                 : 
     239                 :     virtual GDALColorInterp GetColorInterpretation();
     240                 :     virtual CPLErr SetColorInterpretation( GDALColorInterp );
     241                 :     virtual GDALColorTable *GetColorTable();
     242                 :     virtual CPLErr SetColorTable( GDALColorTable * ); 
     243                 :     virtual double GetNoDataValue( int *pbSuccess = NULL );
     244                 : 
     245                 :     void Unpack(GByte* pData);
     246                 : };
     247                 : 
     248                 : /************************************************************************/
     249                 : /*                           NITFRasterBand()                           */
     250                 : /************************************************************************/
     251                 : 
     252          210661 : NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
     253                 : 
     254                 : {
     255          210661 :     NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
     256                 : 
     257          210661 :     this->poDS = poDS;
     258          210661 :     this->nBand = nBand;
     259                 : 
     260          210661 :     this->eAccess = poDS->eAccess;
     261          210661 :     this->psImage = poDS->psImage;
     262                 : 
     263                 : /* -------------------------------------------------------------------- */
     264                 : /*      Translate data type(s).                                         */
     265                 : /* -------------------------------------------------------------------- */
     266          210661 :     if( psImage->nBitsPerSample <= 8 )
     267          210547 :         eDataType = GDT_Byte;
     268             141 :     else if( psImage->nBitsPerSample == 16 
     269                 :              && EQUAL(psImage->szPVType,"SI") )
     270              27 :         eDataType = GDT_Int16;
     271              87 :     else if( psImage->nBitsPerSample == 16 )
     272              12 :         eDataType = GDT_UInt16;
     273              75 :     else if( psImage->nBitsPerSample == 12 )
     274              18 :         eDataType = GDT_UInt16;
     275              69 :     else if( psImage->nBitsPerSample == 32 
     276                 :              && EQUAL(psImage->szPVType,"SI") )
     277              12 :         eDataType = GDT_Int32;
     278              57 :     else if( psImage->nBitsPerSample == 32 
     279                 :              && EQUAL(psImage->szPVType,"R") )
     280              12 :         eDataType = GDT_Float32;
     281              33 :     else if( psImage->nBitsPerSample == 32 )
     282              12 :         eDataType = GDT_UInt32;
     283              33 :     else if( psImage->nBitsPerSample == 64 
     284                 :              && EQUAL(psImage->szPVType,"R") )
     285              12 :         eDataType = GDT_Float64;
     286              18 :     else if( psImage->nBitsPerSample == 64
     287                 :               && EQUAL(psImage->szPVType,"C") )
     288               9 :         eDataType = GDT_CFloat32;
     289                 :     /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2 characters */
     290                 :     else
     291                 :     {
     292               0 :         eDataType = GDT_Unknown;
     293                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     294                 :                   "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
     295               0 :                   psImage->szPVType, psImage->nBitsPerSample );
     296                 :     }
     297                 : 
     298                 : /* -------------------------------------------------------------------- */
     299                 : /*      Work out block size. If the image is all one big block we       */
     300                 : /*      handle via the scanline access API.                             */
     301                 : /* -------------------------------------------------------------------- */
     302          421119 :     if( psImage->nBlocksPerRow == 1 
     303                 :         && psImage->nBlocksPerColumn == 1
     304                 :         && psImage->nBitsPerSample >= 8
     305                 :         && EQUAL(psImage->szIC,"NC") )
     306                 :     {
     307          210458 :         nBlockXSize = psImage->nBlockWidth;
     308          210458 :         nBlockYSize = 1;
     309                 :     }
     310                 :     else
     311                 :     {
     312             203 :         nBlockXSize = psImage->nBlockWidth;
     313             203 :         nBlockYSize = psImage->nBlockHeight;
     314                 :     }
     315                 : 
     316                 : /* -------------------------------------------------------------------- */
     317                 : /*      Do we have a color table?                                       */
     318                 : /* -------------------------------------------------------------------- */
     319                 :     poColorTable = NITFMakeColorTable(psImage,
     320          210661 :                                       psBandInfo);
     321                 : 
     322          210661 :     if( psImage->nBitsPerSample == 1 
     323                 :     ||  psImage->nBitsPerSample == 3
     324                 :     ||  psImage->nBitsPerSample == 5
     325                 :     ||  psImage->nBitsPerSample == 6
     326                 :     ||  psImage->nBitsPerSample == 7
     327                 :     ||  psImage->nBitsPerSample == 12 )
     328             102 :         SetMetadataItem( "NBITS", CPLString().Printf("%d", psImage->nBitsPerSample), "IMAGE_STRUCTURE" );
     329                 : 
     330          210661 :     pUnpackData = 0;
     331          210661 :     if (psImage->nBitsPerSample == 3
     332                 :     ||  psImage->nBitsPerSample == 5
     333                 :     ||  psImage->nBitsPerSample == 6
     334                 :     ||  psImage->nBitsPerSample == 7)
     335              64 :       pUnpackData = new GByte[((nBlockXSize*nBlockYSize+7)/8)*8];
     336          210661 : }
     337                 : 
     338                 : /************************************************************************/
     339                 : /*                          ~NITFRasterBand()                           */
     340                 : /************************************************************************/
     341                 : 
     342          210661 : NITFRasterBand::~NITFRasterBand()
     343                 : 
     344                 : {
     345          210661 :     if( poColorTable != NULL )
     346              54 :         delete poColorTable;
     347                 : 
     348          210661 :     delete[] pUnpackData;
     349          210661 : }
     350                 : 
     351                 : /************************************************************************/
     352                 : /*                             IReadBlock()                             */
     353                 : /************************************************************************/
     354                 : 
     355                 : CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     356            4160 :                                    void * pImage )
     357                 : 
     358                 : {
     359                 :     int  nBlockResult;
     360            4160 :     NITFDataset *poGDS = (NITFDataset *) poDS;
     361                 : 
     362                 : /* -------------------------------------------------------------------- */
     363                 : /*      Special case for JPEG blocks.                                   */
     364                 : /* -------------------------------------------------------------------- */
     365            4160 :     if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
     366                 :     {
     367              55 :         CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
     368                 :         int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
     369              55 :                              (GDALGetDataTypeSize(eDataType)/8);
     370                 : 
     371              55 :         if( eErr != CE_None )
     372               0 :             return eErr;
     373                 : 
     374                 :         memcpy( pImage, 
     375                 :                 poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize, 
     376              55 :                 nBlockBandSize );
     377                 : 
     378              55 :         return eErr;
     379                 :     }
     380                 : 
     381                 : /* -------------------------------------------------------------------- */
     382                 : /*      Read the line/block                                             */
     383                 : /* -------------------------------------------------------------------- */
     384            4105 :     if( nBlockYSize == 1 )
     385                 :     {
     386                 :         nBlockResult = 
     387            2214 :             NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
     388                 :     }
     389                 :     else
     390                 :     {
     391                 :         nBlockResult = 
     392            1891 :             NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
     393                 :     }
     394                 : 
     395            4105 :     if( nBlockResult == BLKREAD_OK )
     396                 :     {
     397            3909 :         if( psImage->nBitsPerSample % 8 )
     398              72 :             Unpack((GByte*)pImage);
     399                 : 
     400            3909 :         return CE_None;
     401                 :     }
     402                 : 
     403             196 :     if( nBlockResult == BLKREAD_FAIL )
     404               1 :         return CE_Failure;
     405                 : 
     406                 : /* -------------------------------------------------------------------- */
     407                 : /*      If we got a null/missing block, try to fill it in with the      */
     408                 : /*      nodata value.  It seems this only really works properly for     */
     409                 : /*      8bit.                                                           */
     410                 : /* -------------------------------------------------------------------- */
     411             195 :     if( psImage->bNoDataSet )
     412                 :         memset( pImage, psImage->nNoDataValue, 
     413             195 :                 psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
     414                 :     else
     415                 :         memset( pImage, 0, 
     416               0 :                 psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
     417                 : 
     418             195 :     return CE_None;
     419                 : }
     420                 : 
     421                 : /************************************************************************/
     422                 : /*                            IWriteBlock()                             */
     423                 : /************************************************************************/
     424                 : 
     425                 : CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     426            3222 :                                     void * pImage )
     427                 :     
     428                 : {
     429                 :     int  nBlockResult;
     430                 : 
     431                 : /* -------------------------------------------------------------------- */
     432                 : /*      Write the line/block                                            */
     433                 : /* -------------------------------------------------------------------- */
     434            3222 :     if( nBlockYSize == 1 )
     435                 :     {
     436                 :         nBlockResult = 
     437            2617 :             NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
     438                 :     }
     439                 :     else
     440                 :     {
     441                 :         nBlockResult = 
     442             605 :             NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
     443                 :     }
     444                 : 
     445            3222 :     if( nBlockResult == BLKREAD_OK )
     446            3222 :         return CE_None;
     447                 :     else
     448               0 :         return CE_Failure;
     449                 : }
     450                 : 
     451                 : /************************************************************************/
     452                 : /*                           GetNoDataValue()                           */
     453                 : /************************************************************************/
     454                 : 
     455              75 : double NITFRasterBand::GetNoDataValue( int *pbSuccess )
     456                 : 
     457                 : {
     458              75 :     if( pbSuccess != NULL )
     459              74 :         *pbSuccess = psImage->bNoDataSet;
     460                 : 
     461              75 :     if( psImage->bNoDataSet )
     462              19 :         return psImage->nNoDataValue;
     463                 :     else
     464              56 :         return GDALPamRasterBand::GetNoDataValue( pbSuccess );
     465                 : }
     466                 : 
     467                 : /************************************************************************/
     468                 : /*                       GetColorInterpretation()                       */
     469                 : /************************************************************************/
     470                 : 
     471             116 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
     472                 : 
     473                 : {
     474             116 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     475                 : 
     476             116 :     if( poColorTable != NULL )
     477              17 :         return GCI_PaletteIndex;
     478                 :     
     479              99 :     if( EQUAL(psBandInfo->szIREPBAND,"R") )
     480              15 :         return GCI_RedBand;
     481              84 :     if( EQUAL(psBandInfo->szIREPBAND,"G") )
     482              15 :         return GCI_GreenBand;
     483              69 :     if( EQUAL(psBandInfo->szIREPBAND,"B") )
     484              15 :         return GCI_BlueBand;
     485              54 :     if( EQUAL(psBandInfo->szIREPBAND,"M") )
     486              36 :         return GCI_GrayIndex;
     487              18 :     if( EQUAL(psBandInfo->szIREPBAND,"Y") )
     488               2 :         return GCI_YCbCr_YBand;
     489              16 :     if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
     490               2 :         return GCI_YCbCr_CbBand;
     491              14 :     if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
     492               2 :         return GCI_YCbCr_CrBand;
     493                 : 
     494              12 :     return GCI_Undefined;
     495                 : }
     496                 : 
     497                 : /************************************************************************/
     498                 : /*                     NITFSetColorInterpretation()                     */
     499                 : /************************************************************************/
     500                 : 
     501                 : static CPLErr NITFSetColorInterpretation( NITFImage *psImage, 
     502                 :                                           int nBand,
     503              18 :                                           GDALColorInterp eInterp )
     504                 : 
     505                 : {
     506              18 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     507              18 :     const char *pszREP = NULL;
     508                 :     GUIntBig nOffset;
     509                 : 
     510              18 :     if( eInterp == GCI_RedBand )
     511               6 :         pszREP = "R";
     512              12 :     else if( eInterp == GCI_GreenBand )
     513               6 :         pszREP = "G";
     514               6 :     else if( eInterp == GCI_BlueBand )
     515               6 :         pszREP = "B";
     516               0 :     else if( eInterp == GCI_GrayIndex )
     517               0 :         pszREP = "M";
     518               0 :     else if( eInterp == GCI_YCbCr_YBand )
     519               0 :         pszREP = "Y";
     520               0 :     else if( eInterp == GCI_YCbCr_CbBand )
     521               0 :         pszREP = "Cb";
     522               0 :     else if( eInterp == GCI_YCbCr_CrBand )
     523               0 :         pszREP = "Cr";
     524               0 :     else if( eInterp == GCI_Undefined )
     525               0 :         return CE_None;
     526                 : 
     527              18 :     if( pszREP == NULL )
     528                 :     {
     529                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     530                 :                   "Requested color interpretation (%s) not supported in NITF.",
     531               0 :                   GDALGetColorInterpretationName( eInterp ) );
     532               0 :         return CE_Failure;
     533                 :     }
     534                 : 
     535                 : /* -------------------------------------------------------------------- */
     536                 : /*      Where does this go in the file?                                 */
     537                 : /* -------------------------------------------------------------------- */
     538              18 :     strcpy( psBandInfo->szIREPBAND, pszREP );
     539              18 :     nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
     540                 : 
     541              18 :     if( nOffset != 0 )
     542              18 :         nOffset += (nBand - 1) * 13;
     543                 :     
     544                 : /* -------------------------------------------------------------------- */
     545                 : /*      write it (space padded).                                        */
     546                 : /* -------------------------------------------------------------------- */
     547                 :     char szPadded[4];
     548              18 :     strcpy( szPadded, pszREP );
     549              18 :     strcat( szPadded, " " );
     550                 :     
     551              18 :     if( nOffset != 0 )
     552                 :     {
     553              18 :         if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0 
     554                 :             || VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
     555                 :         {
     556                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     557               0 :                       "IO failure writing new IREPBAND value to NITF file." );
     558               0 :             return CE_Failure;
     559                 :         }
     560                 :     }
     561                 :     
     562              18 :     return CE_None;
     563                 : }
     564                 : 
     565                 : /************************************************************************/
     566                 : /*                       SetColorInterpretation()                       */
     567                 : /************************************************************************/
     568                 : 
     569              18 : CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
     570                 : 
     571                 : {
     572              18 :     return NITFSetColorInterpretation( psImage, nBand, eInterp );
     573                 : }
     574                 : 
     575                 : /************************************************************************/
     576                 : /*                           GetColorTable()                            */
     577                 : /************************************************************************/
     578                 : 
     579              36 : GDALColorTable *NITFRasterBand::GetColorTable()
     580                 : 
     581                 : {
     582              36 :     return poColorTable;
     583                 : }
     584                 : 
     585                 : /************************************************************************/
     586                 : /*                           SetColorTable()                            */
     587                 : /************************************************************************/
     588                 : 
     589               2 : CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
     590                 : 
     591                 : {
     592               2 :     if( poNewCT == NULL )
     593               0 :         return CE_Failure;
     594                 : 
     595                 :     GByte abyNITFLUT[768];
     596                 :     int   i;
     597               2 :     int   nCount = MIN(256,poNewCT->GetColorEntryCount());
     598                 : 
     599               2 :     memset( abyNITFLUT, 0, 768 );
     600             135 :     for( i = 0; i < nCount; i++ )
     601                 :     {
     602                 :         GDALColorEntry sEntry;
     603                 : 
     604             133 :         poNewCT->GetColorEntryAsRGB( i, &sEntry );
     605             133 :         abyNITFLUT[i    ] = (GByte) sEntry.c1;
     606             133 :         abyNITFLUT[i+256] = (GByte) sEntry.c2;
     607             133 :         abyNITFLUT[i+512] = (GByte) sEntry.c3;
     608                 :     }
     609                 : 
     610               2 :     if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
     611               2 :         return CE_None;
     612                 :     else
     613               0 :         return CE_Failure;
     614                 : }
     615                 : 
     616                 : /************************************************************************/
     617                 : /*                           Unpack()                                   */
     618                 : /************************************************************************/
     619                 : 
     620              72 : void NITFRasterBand::Unpack( GByte* pData )
     621                 : {
     622              72 :   long n = nBlockXSize*nBlockYSize;
     623                 :   long i;
     624                 :   long k;
     625                 : 
     626              72 :   GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
     627              72 :   const GByte* pDataSrc = pData;
     628              72 :   if (n < psImage->nBitsPerSample &&
     629                 :       psImage->nBitsPerSample < 8)
     630                 :   {
     631              21 :       memcpy(abyTempData, pData, n);
     632              21 :       pDataSrc = abyTempData;
     633                 :   }
     634                 : 
     635              72 :   switch (psImage->nBitsPerSample)
     636                 :   {
     637                 :     case 1:
     638                 :     {
     639                 :       // unpack 1-bit in-place in reverse
     640         1050526 :       for (i = n; --i >= 0; )
     641         1050502 :         pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
     642                 :        
     643              12 :       break;
     644                 :     }
     645                 :     case 2:
     646                 :     {
     647                 :       static const int s_Shift2[] = {6, 4, 2, 0};
     648                 :       // unpack 2-bit in-place in reverse
     649              52 :       for (i = n; --i >= 0; )
     650              36 :         pData[i] = (pData[i>>2] >> (GByte)s_Shift2[i&3]) & 0x03;
     651                 :        
     652               8 :       break;
     653                 :     }
     654                 :     case 4:
     655                 :     {
     656                 :       static const int s_Shift4[] = {4, 0};
     657                 :       // unpack 4-bit in-place in reverse
     658              52 :       for (i = n; --i >= 0; )
     659              36 :         pData[i] = (pData[i>>1] >> (GByte)s_Shift4[i&1]) & 0x0f;
     660                 :        
     661               8 :       break;
     662                 :     }
     663                 :     case 3:
     664                 :     {
     665                 :       // unpacks 8 pixels (3 bytes) at time
     666              16 :       for (i = 0, k = 0; i < n; i += 8, k += 3)
     667                 :       {
     668               8 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 5));
     669               8 :         pUnpackData[i+1] = ((pDataSrc[k+0] >> 2) & 0x07);
     670               8 :         pUnpackData[i+2] = ((pDataSrc[k+0] << 1) & 0x07) | (pDataSrc[k+1] >> 7);
     671               8 :         pUnpackData[i+3] = ((pDataSrc[k+1] >> 4) & 0x07);
     672               8 :         pUnpackData[i+4] = ((pDataSrc[k+1] >> 1) & 0x07);
     673               8 :         pUnpackData[i+5] = ((pDataSrc[k+1] << 2) & 0x07) | (pDataSrc[k+2] >> 6);
     674               8 :         pUnpackData[i+6] = ((pDataSrc[k+2] >> 3) & 0x07);
     675               8 :         pUnpackData[i+7] = ((pDataSrc[k+2]) & 0x7);
     676                 :       }
     677                 : 
     678               8 :       memcpy(pData, pUnpackData, n);
     679               8 :       break;
     680                 :     }
     681                 :     case 5:
     682                 :     {
     683                 :       // unpacks 8 pixels (5 bytes) at time
     684              16 :       for (i = 0, k = 0; i < n; i += 8, k += 5)
     685                 :       {
     686               8 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 3));
     687               8 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 2) & 0x1f) | (pDataSrc[k+1] >> 6);
     688               8 :         pUnpackData[i+2] = ((pDataSrc[k+1] >> 1) & 0x1f);
     689               8 :         pUnpackData[i+3] = ((pDataSrc[k+1] << 4) & 0x1f) | (pDataSrc[k+2] >> 4);
     690               8 :         pUnpackData[i+4] = ((pDataSrc[k+2] << 1) & 0x1f) | (pDataSrc[k+3] >> 7);
     691               8 :         pUnpackData[i+5] = ((pDataSrc[k+3] >> 2) & 0x1f);
     692               8 :         pUnpackData[i+6] = ((pDataSrc[k+3] << 3) & 0x1f) | (pDataSrc[k+4] >> 5);
     693               8 :         pUnpackData[i+7] = ((pDataSrc[k+4]) & 0x1f);
     694                 :       }
     695                 : 
     696               8 :       memcpy(pData, pUnpackData, n);
     697               8 :       break;
     698                 :     }
     699                 :     case 6:
     700                 :     {
     701                 :       // unpacks 4 pixels (3 bytes) at time
     702              20 :       for (i = 0, k = 0; i < n; i += 4, k += 3)
     703                 :       {
     704              12 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 2));
     705              12 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 4) & 0x3f) | (pDataSrc[k+1] >> 4);
     706              12 :         pUnpackData[i+2] = ((pDataSrc[k+1] << 2) & 0x3f) | (pDataSrc[k+2] >> 6);
     707              12 :         pUnpackData[i+3] = ((pDataSrc[k+2]) & 0x3f);
     708                 :       }
     709                 : 
     710               8 :       memcpy(pData, pUnpackData, n);
     711               8 :       break;
     712                 :     }
     713                 :     case 7:
     714                 :     {
     715                 :       // unpacks 8 pixels (7 bytes) at time
     716              16 :       for (i = 0, k = 0; i < n; i += 8, k += 7)
     717                 :       {
     718               8 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 1));
     719               8 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 6) & 0x7f) | (pDataSrc[k+1] >> 2);
     720               8 :         pUnpackData[i+2] = ((pDataSrc[k+1] << 5) & 0x7f) | (pDataSrc[k+2] >> 3) ;
     721               8 :         pUnpackData[i+3] = ((pDataSrc[k+2] << 4) & 0x7f) | (pDataSrc[k+3] >> 4);
     722               8 :         pUnpackData[i+4] = ((pDataSrc[k+3] << 3) & 0x7f) | (pDataSrc[k+4] >> 5);
     723               8 :         pUnpackData[i+5] = ((pDataSrc[k+4] << 2) & 0x7f) | (pDataSrc[k+5] >> 6);
     724               8 :         pUnpackData[i+6] = ((pDataSrc[k+5] << 1) & 0x7f) | (pDataSrc[k+6] >> 7);
     725               8 :         pUnpackData[i+7] = ((pDataSrc[k+6]) & 0x7f);
     726                 :       }
     727                 : 
     728               8 :       memcpy(pData, pUnpackData, n);
     729               8 :       break;
     730                 :     }
     731                 :     case 12:
     732                 :     {
     733              12 :       GByte*   pabyImage = (GByte  *)pData;
     734              12 :       GUInt16* panImage  = (GUInt16*)pData;
     735         1048636 :       for (i = n; --i >= 0; )
     736                 :       {
     737         1048612 :         long iOffset = i*3 / 2;
     738         1048612 :         if (i % 2 == 0)
     739          524308 :           panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
     740                 :         else
     741                 :           panImage[i] = (pabyImage[iOffset]   & 0x0f) * 16
     742                 :                       + (pabyImage[iOffset+1] & 0xf0) / 16
     743          524304 :                       + (pabyImage[iOffset+1] & 0x0f) * 256;
     744                 :       }
     745                 : 
     746                 :       break;
     747                 :     }
     748                 :   }
     749              72 : }
     750                 : 
     751                 : /************************************************************************/
     752                 : /* ==================================================================== */
     753                 : /*                       NITFWrapperRasterBand                          */
     754                 : /* ==================================================================== */
     755                 : /************************************************************************/
     756                 : 
     757                 : /* This class is used to wrap bands from JPEG or JPEG2000 datasets in */
     758                 : /* bands of the NITF dataset. Previously a trick was applied in the */
     759                 : /* relevant drivers to define a SetColorInterpretation() method and */
     760                 : /* to make sure they keep the proper pointer to their "natural" dataset */
     761                 : /* This trick is no longer necessary with the NITFWrapperRasterBand */
     762                 : /* We just override the few specific methods where we want that */
     763                 : /* the NITFWrapperRasterBand behaviour differs from the JPEG/JPEG2000 one */
     764                 : 
     765                 : class NITFWrapperRasterBand : public GDALProxyRasterBand
     766                 : {
     767                 :   GDALRasterBand* poBaseBand;
     768                 :   GDALColorTable* poColorTable;
     769                 :   GDALColorInterp eInterp;
     770                 : 
     771                 :   protected:
     772                 :     /* Pure virtual method of the GDALProxyRasterBand */
     773                 :     virtual GDALRasterBand* RefUnderlyingRasterBand();
     774                 : 
     775                 :   public:
     776                 :                    NITFWrapperRasterBand( NITFDataset * poDS,
     777                 :                                           GDALRasterBand* poBaseBand,
     778                 :                                           int nBand);
     779                 :                   ~NITFWrapperRasterBand();
     780                 :     
     781                 :     /* Methods from GDALRasterBand we want to override */
     782                 :     virtual GDALColorInterp GetColorInterpretation();
     783                 :     virtual CPLErr          SetColorInterpretation( GDALColorInterp );
     784                 :     
     785                 :     virtual GDALColorTable *GetColorTable();
     786                 : 
     787                 :     /* Specific method */
     788                 :     void                    SetColorTableFromNITFBandInfo(); 
     789                 : };
     790                 : 
     791                 : /************************************************************************/
     792                 : /*                      NITFWrapperRasterBand()                         */
     793                 : /************************************************************************/
     794                 : 
     795                 : NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
     796                 :                                               GDALRasterBand* poBaseBand,
     797              35 :                                               int nBand)
     798                 : {
     799              35 :     this->poDS = poDS;
     800              35 :     this->nBand = nBand;
     801              35 :     this->poBaseBand = poBaseBand;
     802              35 :     eDataType = poBaseBand->GetRasterDataType();
     803              35 :     poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     804              35 :     poColorTable = NULL;
     805              35 :     eInterp = poBaseBand->GetColorInterpretation();
     806              35 : }
     807                 : 
     808                 : /************************************************************************/
     809                 : /*                      ~NITFWrapperRasterBand()                        */
     810                 : /************************************************************************/
     811                 : 
     812              35 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
     813                 : {
     814              35 :     if( poColorTable != NULL )
     815               3 :         delete poColorTable;
     816              35 : }
     817                 : 
     818                 : /************************************************************************/
     819                 : /*                     RefUnderlyingRasterBand()                        */
     820                 : /************************************************************************/
     821                 : 
     822                 : /* We don't need ref-counting. Just return the base band */
     823            7847 : GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
     824                 : {
     825            7847 :   return poBaseBand;
     826                 : }
     827                 : 
     828                 : /************************************************************************/
     829                 : /*                            GetColorTable()                           */
     830                 : /************************************************************************/
     831                 : 
     832              11 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
     833                 : {
     834              11 :     return poColorTable;
     835                 : }
     836                 : 
     837                 : /************************************************************************/
     838                 : /*                 SetColorTableFromNITFBandInfo()                      */
     839                 : /************************************************************************/
     840                 : 
     841               3 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
     842                 : {
     843               3 :     NITFDataset* poGDS = (NITFDataset* )poDS;
     844                 :     poColorTable = NITFMakeColorTable(poGDS->psImage,
     845               3 :                                       poGDS->psImage->pasBandInfo + nBand - 1);
     846               3 : }
     847                 : 
     848                 : /************************************************************************/
     849                 : /*                        GetColorInterpretation()                      */
     850                 : /************************************************************************/
     851                 : 
     852              10 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
     853                 : {
     854              10 :     return eInterp;
     855                 : }
     856                 : 
     857                 : /************************************************************************/
     858                 : /*                        SetColorInterpretation()                      */
     859                 : /************************************************************************/
     860                 : 
     861              29 : CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
     862                 : {
     863              29 :     this->eInterp = eInterp;
     864              29 :     return CE_None;
     865                 : }
     866                 : 
     867                 : /************************************************************************/
     868                 : /* ==================================================================== */
     869                 : /*                             NITFDataset                              */
     870                 : /* ==================================================================== */
     871                 : /************************************************************************/
     872                 : 
     873                 : /************************************************************************/
     874                 : /*                            NITFDataset()                             */
     875                 : /************************************************************************/
     876                 : 
     877             509 : NITFDataset::NITFDataset()
     878                 : 
     879                 : {
     880             509 :     psFile = NULL;
     881             509 :     psImage = NULL;
     882             509 :     bGotGeoTransform = FALSE;
     883             509 :     pszProjection = CPLStrdup("");
     884             509 :     poJ2KDataset = NULL;
     885             509 :     bJP2Writing = FALSE;
     886             509 :     poJPEGDataset = NULL;
     887                 : 
     888             509 :     panJPEGBlockOffset = NULL;
     889             509 :     pabyJPEGBlock = NULL;
     890             509 :     nQLevel = 0;
     891                 : 
     892             509 :     nGCPCount = 0;
     893             509 :     pasGCPList = NULL;
     894             509 :     pszGCPProjection = NULL;
     895                 : 
     896             509 :     adfGeoTransform[0] = 0.0;
     897             509 :     adfGeoTransform[1] = 1.0;
     898             509 :     adfGeoTransform[2] = 0.0;
     899             509 :     adfGeoTransform[3] = 0.0;
     900             509 :     adfGeoTransform[4] = 0.0;
     901             509 :     adfGeoTransform[5] = 1.0;
     902                 :     
     903             509 :     poDriver = (GDALDriver*) GDALGetDriverByName("NITF");
     904                 : 
     905             509 :     papszTextMDToWrite = NULL;
     906             509 :     papszCgmMDToWrite = NULL;
     907             509 : }
     908                 : 
     909                 : /************************************************************************/
     910                 : /*                            ~NITFDataset()                            */
     911                 : /************************************************************************/
     912                 : 
     913             509 : NITFDataset::~NITFDataset()
     914                 : 
     915                 : {
     916             509 :     FlushCache();
     917                 : 
     918                 : /* -------------------------------------------------------------------- */
     919                 : /*      If we have been writing to a JPEG2000 file, check if the        */
     920                 : /*      color interpretations were set.  If so, apply the settings      */
     921                 : /*      to the NITF file.                                               */
     922                 : /* -------------------------------------------------------------------- */
     923             509 :     if( poJ2KDataset != NULL && bJP2Writing )
     924                 :     {
     925                 :         int i;
     926                 : 
     927               0 :         for( i = 0; i < nBands && papoBands != NULL; i++ )
     928                 :         {
     929               0 :             if( papoBands[i]->GetColorInterpretation() != GCI_Undefined )
     930                 :                 NITFSetColorInterpretation( psImage, i+1, 
     931               0 :                                 papoBands[i]->GetColorInterpretation() );
     932                 :         }
     933                 :     }
     934                 : 
     935                 : /* -------------------------------------------------------------------- */
     936                 : /*      Close the underlying NITF file.                                 */
     937                 : /* -------------------------------------------------------------------- */
     938             509 :     GUIntBig nImageStart = 0;
     939             509 :     if( psFile != NULL )
     940                 :     {
     941             509 :         if (psFile->nSegmentCount > 0)
     942             509 :             nImageStart = psFile->pasSegmentInfo[0].nSegmentStart;
     943                 : 
     944             509 :         NITFClose( psFile );
     945             509 :         psFile = NULL;
     946                 :     }
     947                 : 
     948                 : /* -------------------------------------------------------------------- */
     949                 : /*      Free datastructures.                                            */
     950                 : /* -------------------------------------------------------------------- */
     951             509 :     CPLFree( pszProjection );
     952                 : 
     953             509 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
     954             509 :     CPLFree( pasGCPList );
     955             509 :     CPLFree( pszGCPProjection );
     956                 : 
     957                 : /* -------------------------------------------------------------------- */
     958                 : /*      If we have a jpeg2000 output file, make sure it gets closed     */
     959                 : /*      and flushed out.                                                */
     960                 : /* -------------------------------------------------------------------- */
     961             509 :     if( poJ2KDataset != NULL )
     962                 :     {
     963              12 :         GDALClose( (GDALDatasetH) poJ2KDataset );
     964                 :     }
     965                 : 
     966                 : /* -------------------------------------------------------------------- */
     967                 : /*      Update file length, and COMRAT for JPEG2000 files we are        */
     968                 : /*      writing to.                                                     */
     969                 : /* -------------------------------------------------------------------- */
     970             509 :     if( bJP2Writing )
     971                 :     {
     972                 :         GIntBig nPixelCount = nRasterXSize * ((GIntBig) nRasterYSize) * 
     973               0 :             nBands;
     974                 : 
     975                 :         NITFPatchImageLength( GetDescription(), nImageStart, nPixelCount, 
     976               0 :                               "C8" );
     977                 :     }
     978                 : 
     979                 : /* -------------------------------------------------------------------- */
     980                 : /*      If we have a jpeg output file, make sure it gets closed         */
     981                 : /*      and flushed out.                                                */
     982                 : /* -------------------------------------------------------------------- */
     983             509 :     if( poJPEGDataset != NULL )
     984                 :     {
     985              13 :         GDALClose( (GDALDatasetH) poJPEGDataset );
     986                 :     }
     987                 : 
     988             509 :     CPLFree( panJPEGBlockOffset );
     989             509 :     CPLFree( pabyJPEGBlock );
     990                 : 
     991                 : /* -------------------------------------------------------------------- */
     992                 : /*      If the dataset was opened by Create(), we may need to write     */
     993                 : /*      the CGM and TEXT segments                                       */
     994                 : /* -------------------------------------------------------------------- */
     995             509 :     NITFWriteCGMSegments( GetDescription(), papszCgmMDToWrite );
     996             509 :     NITFWriteTextSegments( GetDescription(), papszTextMDToWrite );
     997                 : 
     998             509 :     CSLDestroy(papszTextMDToWrite);
     999             509 :     CSLDestroy(papszCgmMDToWrite);
    1000             509 : }
    1001                 : 
    1002                 : /************************************************************************/
    1003                 : /*                             FlushCache()                             */
    1004                 : /************************************************************************/
    1005                 : 
    1006             509 : void NITFDataset::FlushCache()
    1007                 : 
    1008                 : {
    1009                 :     // If the JPEG/JP2K dataset has dirty pam info, then we should consider 
    1010                 :     // ourselves to as well.
    1011             509 :     if( poJPEGDataset != NULL 
    1012                 :         && (poJPEGDataset->GetPamFlags() & GPF_DIRTY) )
    1013               3 :         MarkPamDirty();
    1014             509 :     if( poJ2KDataset != NULL 
    1015                 :         && (poJ2KDataset->GetPamFlags() & GPF_DIRTY) )
    1016               1 :         MarkPamDirty();
    1017                 : 
    1018             509 :     if( poJ2KDataset != NULL && bJP2Writing)
    1019               0 :         poJ2KDataset->FlushCache();
    1020                 : 
    1021             509 :     GDALPamDataset::FlushCache();
    1022             509 : }
    1023                 : 
    1024                 : /************************************************************************/
    1025                 : /*                              Identify()                              */
    1026                 : /************************************************************************/
    1027                 : 
    1028           12301 : int NITFDataset::Identify( GDALOpenInfo * poOpenInfo )
    1029                 : 
    1030                 : {
    1031           12301 :     const char *pszFilename = poOpenInfo->pszFilename;
    1032                 : 
    1033                 : /* -------------------------------------------------------------------- */
    1034                 : /*      Is this a dataset selector? If so, it is obviously NITF.        */
    1035                 : /* -------------------------------------------------------------------- */
    1036           12301 :     if( EQUALN(pszFilename, "NITF_IM:",8) )
    1037              13 :         return TRUE;
    1038                 : 
    1039                 : /* -------------------------------------------------------------------- */
    1040                 : /*  First we check to see if the file has the expected header */
    1041                 : /*  bytes.                */    
    1042                 : /* -------------------------------------------------------------------- */
    1043           12288 :     if( poOpenInfo->nHeaderBytes < 4 )
    1044            9837 :         return FALSE;
    1045                 :     
    1046            2451 :     if( !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) 
    1047                 :         && !EQUALN((char *) poOpenInfo->pabyHeader,"NSIF",4)
    1048                 :         && !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) )
    1049            1860 :         return FALSE;
    1050                 : 
    1051                 :     int i;
    1052                 :     /* Check that it's not in fact a NITF A.TOC file, which is handled by the RPFTOC driver */
    1053          538659 :     for(i=0;i<(int)poOpenInfo->nHeaderBytes-(int)strlen("A.TOC");i++)
    1054                 :     {
    1055          538068 :         if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "A.TOC", strlen("A.TOC")))
    1056               0 :             return FALSE;
    1057                 :     }
    1058                 : 
    1059             591 :     return TRUE;
    1060                 : }
    1061                 :         
    1062                 : /************************************************************************/
    1063                 : /*                                Open()                                */
    1064                 : /************************************************************************/
    1065                 : 
    1066            3819 : GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo )
    1067                 : {
    1068            3819 :     return Open(poOpenInfo, NULL, FALSE);
    1069                 : }
    1070                 : 
    1071                 : GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo,
    1072                 :                                 GDALDataset *poWritableJ2KDataset,
    1073            3971 :                                 int bOpenForCreate)
    1074                 : 
    1075                 : {
    1076            3971 :     int nIMIndex = -1;
    1077            3971 :     const char *pszFilename = poOpenInfo->pszFilename;
    1078                 : 
    1079            3971 :     if( !Identify( poOpenInfo ) )
    1080            3430 :         return NULL;
    1081                 :         
    1082                 : /* -------------------------------------------------------------------- */
    1083                 : /*      Select a specific subdataset.                                   */
    1084                 : /* -------------------------------------------------------------------- */
    1085             541 :     if( EQUALN(pszFilename, "NITF_IM:",8) )
    1086                 :     {
    1087              13 :         pszFilename += 8;
    1088              13 :         nIMIndex = atoi(pszFilename);
    1089                 :         
    1090              43 :         while( *pszFilename != '\0' && *pszFilename != ':' )
    1091              17 :             pszFilename++;
    1092                 : 
    1093              13 :         if( *pszFilename == ':' )
    1094              13 :             pszFilename++;
    1095                 :     }
    1096                 : 
    1097                 : /* -------------------------------------------------------------------- */
    1098                 : /*      Open the file with library.                                     */
    1099                 : /* -------------------------------------------------------------------- */
    1100                 :     NITFFile *psFile;
    1101                 : 
    1102             541 :     psFile = NITFOpen( pszFilename, poOpenInfo->eAccess == GA_Update );
    1103             541 :     if( psFile == NULL )
    1104                 :     {
    1105              13 :         return NULL;
    1106                 :     }
    1107                 : 
    1108             528 :     if (!bOpenForCreate)
    1109                 :     {
    1110             376 :         NITFCollectAttachments( psFile );
    1111             376 :         NITFReconcileAttachments( psFile );
    1112                 :     }
    1113                 : 
    1114                 : /* -------------------------------------------------------------------- */
    1115                 : /*      Is there an image to operate on?                                */
    1116                 : /* -------------------------------------------------------------------- */
    1117             528 :     int iSegment, nThisIM = 0;
    1118             528 :     NITFImage *psImage = NULL;
    1119                 : 
    1120            2553 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    1121                 :     {
    1122            2550 :         if( EQUAL(psFile->pasSegmentInfo[iSegment].szSegmentType,"IM") 
    1123                 :             && (nThisIM++ == nIMIndex || nIMIndex == -1) )
    1124                 :         {
    1125             525 :             psImage = NITFImageAccess( psFile, iSegment );
    1126             525 :             if( psImage == NULL )
    1127                 :             {
    1128              19 :                 NITFClose( psFile );
    1129              19 :                 return NULL;
    1130                 :             }
    1131             506 :             break;
    1132                 :         }
    1133                 :     }
    1134                 : 
    1135                 : /* -------------------------------------------------------------------- */
    1136                 : /*      If no image segments found report this to the user.             */
    1137                 : /* -------------------------------------------------------------------- */
    1138             509 :     if( psImage == NULL )
    1139                 :     {
    1140                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    1141                 :                   "The file %s appears to be an NITF file, but no image\n"
    1142                 :                   "blocks were found on it.", 
    1143               3 :                   poOpenInfo->pszFilename );
    1144                 :     }
    1145                 :     
    1146                 : /* -------------------------------------------------------------------- */
    1147                 : /*      Create a corresponding GDALDataset.                             */
    1148                 : /* -------------------------------------------------------------------- */
    1149                 :     NITFDataset   *poDS;
    1150                 : 
    1151             509 :     poDS = new NITFDataset();
    1152                 : 
    1153             509 :     poDS->psFile = psFile;
    1154             509 :     poDS->psImage = psImage;
    1155             509 :     poDS->eAccess = poOpenInfo->eAccess;
    1156            1018 :     poDS->osNITFFilename = pszFilename;
    1157             509 :     poDS->nIMIndex = nIMIndex;
    1158                 : 
    1159             509 :     if( psImage )
    1160                 :     {
    1161             506 :         if (psImage->nCols <= 0 || psImage->nRows <= 0 || 
    1162                 :             psImage->nBlockWidth <= 0 || psImage->nBlockHeight <= 0) 
    1163                 :         { 
    1164                 :             CPLError( CE_Failure, CPLE_AppDefined,  
    1165                 :                       "Bad values in NITF image : nCols=%d, nRows=%d, nBlockWidth=%d, nBlockHeight=%d", 
    1166               0 :                       psImage->nCols, psImage->nRows, psImage->nBlockWidth, psImage->nBlockHeight); 
    1167               0 :             delete poDS; 
    1168               0 :             return NULL; 
    1169                 :         } 
    1170                 : 
    1171             506 :         poDS->nRasterXSize = psImage->nCols;
    1172             506 :         poDS->nRasterYSize = psImage->nRows;
    1173                 :     }
    1174                 :     else
    1175                 :     {
    1176               3 :         poDS->nRasterXSize = 1;
    1177               3 :         poDS->nRasterYSize = 1;
    1178                 :     }
    1179                 : 
    1180                 : /* -------------------------------------------------------------------- */
    1181                 : /*      If the image is JPEG2000 (C8) compressed, we will need to       */
    1182                 : /*      open the image data as a JPEG2000 dataset.                      */
    1183                 : /* -------------------------------------------------------------------- */
    1184             509 :     int nUsableBands = 0;
    1185                 :     int iBand;
    1186             509 :     int bSetColorInterpretation = TRUE;
    1187             509 :     int bSetColorTable = FALSE;
    1188                 : 
    1189             509 :     if( psImage )
    1190             506 :         nUsableBands = psImage->nBands;
    1191                 : 
    1192             521 :     if( psImage != NULL && EQUAL(psImage->szIC,"C8") )
    1193                 :     {
    1194              12 :         CPLString osDSName;
    1195                 : 
    1196                 :         osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_" CPL_FRMT_GUIB ",%s", 
    1197                 :                          psFile->pasSegmentInfo[iSegment].nSegmentStart,
    1198                 :                          psFile->pasSegmentInfo[iSegment].nSegmentSize,
    1199              12 :                          pszFilename );
    1200                 :     
    1201              12 :         if( poWritableJ2KDataset != NULL )
    1202                 :         {
    1203               0 :             poDS->poJ2KDataset = (GDALPamDataset *) poWritableJ2KDataset; 
    1204               0 :             poDS->bJP2Writing = TRUE;
    1205               0 :             poWritableJ2KDataset = NULL;
    1206                 :         }
    1207                 :         else
    1208                 :         {
    1209                 :             poDS->poJ2KDataset = (GDALPamDataset *) 
    1210              12 :                 GDALOpen( osDSName, GA_ReadOnly );
    1211                 :                 
    1212              12 :             if( poDS->poJ2KDataset == NULL )
    1213                 :             {
    1214                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
    1215                 :                           "Unable to open JPEG2000 image within NITF file.\n"
    1216               0 :                           "Is the JP2KAK driver available?" );
    1217               0 :                 delete poDS;
    1218               0 :                 return NULL;
    1219                 :             }
    1220                 :             
    1221                 :             poDS->poJ2KDataset->SetPamFlags( 
    1222              12 :                 poDS->poJ2KDataset->GetPamFlags() | GPF_NOSAVE );
    1223                 :         }
    1224                 : 
    1225              12 :         if( poDS->GetRasterXSize() != poDS->poJ2KDataset->GetRasterXSize()
    1226                 :             || poDS->GetRasterYSize() != poDS->poJ2KDataset->GetRasterYSize())
    1227                 :         {
    1228                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1229               0 :                       "JPEG2000 data stream has not the same dimensions as the NITF file.");
    1230               0 :             delete poDS;
    1231               0 :             return NULL;
    1232                 :         }
    1233                 :         
    1234              12 :         if ( nUsableBands == 1)
    1235                 :         {
    1236              12 :             const char* pszIREP = CSLFetchNameValue(psImage->papszMetadata, "NITF_IREP");
    1237              12 :             if (pszIREP != NULL && EQUAL(pszIREP, "RGB/LUT"))
    1238                 :             {
    1239               4 :                 if (poDS->poJ2KDataset->GetRasterCount() == 3)
    1240                 :                 {
    1241                 : /* Test case : http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9_jp2_2places.ntf */
    1242                 : /* 256-entry palette/LUT in both JP2 Header and image Subheader */
    1243                 : /* In this case, the JPEG2000 driver will probably do the RGB expension */
    1244               1 :                     nUsableBands = 3;
    1245               1 :                     bSetColorInterpretation = FALSE;
    1246                 :                 }
    1247               3 :                 else if (poDS->poJ2KDataset->GetRasterCount() == 1 &&
    1248                 :                          psImage->pasBandInfo[0].nSignificantLUTEntries > 0 &&
    1249                 :                          poDS->poJ2KDataset->GetRasterBand(1)->GetColorTable() == NULL)
    1250                 :                 {
    1251                 : /* Test case : http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9_j2c.ntf */
    1252                 : /* 256-entry/LUT in Image Subheader, JP2 header completely removed */
    1253                 : /* The JPEG2000 driver will decode it as a grey band */
    1254                 : /* So we must set the color table on the wrapper band */
    1255               3 :                     bSetColorTable = TRUE;
    1256                 :                 }
    1257                 :             }
    1258                 :         }
    1259                 : 
    1260              12 :         if( poDS->poJ2KDataset->GetRasterCount() < nUsableBands )
    1261                 :         {
    1262                 :             CPLError( CE_Warning, CPLE_AppDefined, 
    1263                 :                       "JPEG2000 data stream has less useful bands than expected, likely\n"
    1264               0 :                       "because some channels have differing resolutions." );
    1265                 :             
    1266               0 :             nUsableBands = poDS->poJ2KDataset->GetRasterCount();
    1267               0 :         }
    1268                 :     }
    1269                 : 
    1270                 : /* -------------------------------------------------------------------- */
    1271                 : /*      If the image is JPEG (C3) compressed, we will need to open      */
    1272                 : /*      the image data as a JPEG dataset.                               */
    1273                 : /* -------------------------------------------------------------------- */
    1274             497 :     else if( psImage != NULL
    1275                 :              && EQUAL(psImage->szIC,"C3") 
    1276                 :              && psImage->nBlocksPerRow == 1
    1277                 :              && psImage->nBlocksPerColumn == 1 )
    1278                 :     {
    1279              13 :         GUIntBig nJPEGStart = psFile->pasSegmentInfo[iSegment].nSegmentStart;
    1280                 : 
    1281              13 :         poDS->nQLevel = poDS->ScanJPEGQLevel( &nJPEGStart );
    1282                 : 
    1283              13 :         CPLString osDSName;
    1284                 : 
    1285                 :         osDSName.Printf( "JPEG_SUBFILE:Q%d," CPL_FRMT_GUIB "," CPL_FRMT_GUIB ",%s", 
    1286                 :                          poDS->nQLevel, nJPEGStart,
    1287                 :                          psFile->pasSegmentInfo[iSegment].nSegmentSize
    1288                 :                          - (nJPEGStart - psFile->pasSegmentInfo[iSegment].nSegmentStart),
    1289              13 :                          pszFilename );
    1290                 : 
    1291                 :         CPLDebug( "GDAL", 
    1292              13 :                   "NITFDataset::Open() as IC=C3 (JPEG compressed)\n");
    1293                 : 
    1294              13 :         poDS->poJPEGDataset = (GDALPamDataset*) GDALOpen(osDSName,GA_ReadOnly);
    1295              13 :         if( poDS->poJPEGDataset == NULL )
    1296                 :         {
    1297                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1298                 :                       "Unable to open JPEG image within NITF file.\n"
    1299               0 :                       "Is the JPEG driver available?" );
    1300               0 :             delete poDS;
    1301               0 :             return NULL;
    1302                 :         }
    1303                 :         
    1304              13 :         if( poDS->GetRasterXSize() != poDS->poJPEGDataset->GetRasterXSize()
    1305                 :             || poDS->GetRasterYSize() != poDS->poJPEGDataset->GetRasterYSize())
    1306                 :         {
    1307                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1308               0 :                       "JPEG data stream has not the same dimensions as the NITF file.");
    1309               0 :             delete poDS;
    1310               0 :             return NULL;
    1311                 :         }
    1312                 :         
    1313                 :         poDS->poJPEGDataset->SetPamFlags( 
    1314              13 :             poDS->poJPEGDataset->GetPamFlags() | GPF_NOSAVE );
    1315                 : 
    1316              13 :         if( poDS->poJPEGDataset->GetRasterCount() < nUsableBands )
    1317                 :         {
    1318                 :             CPLError( CE_Warning, CPLE_AppDefined, 
    1319                 :                       "JPEG data stream has less useful bands than expected, likely\n"
    1320               0 :                       "because some channels have differing resolutions." );
    1321                 :             
    1322               0 :             nUsableBands = poDS->poJPEGDataset->GetRasterCount();
    1323               0 :         }
    1324                 :     }
    1325                 : 
    1326                 : /* -------------------------------------------------------------------- */
    1327                 : /*      Create band information objects.                                */
    1328                 : /* -------------------------------------------------------------------- */
    1329                 : 
    1330             509 :     GDALDataset*    poBaseDS = NULL;
    1331             509 :     if (poDS->poJ2KDataset != NULL)
    1332              12 :         poBaseDS = poDS->poJ2KDataset;
    1333             497 :     else if (poDS->poJPEGDataset != NULL)
    1334              13 :         poBaseDS = poDS->poJPEGDataset;
    1335                 : 
    1336          211205 :     for( iBand = 0; iBand < nUsableBands; iBand++ )
    1337                 :     {
    1338          210696 :         if( poBaseDS != NULL)
    1339                 :         {
    1340                 :             GDALRasterBand* poBaseBand =
    1341              35 :                 poBaseDS->GetRasterBand(iBand+1);
    1342                 :             NITFWrapperRasterBand* poBand =
    1343              35 :                 new NITFWrapperRasterBand(poDS, poBaseBand, iBand+1 );
    1344                 :                 
    1345              35 :             NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;
    1346              35 :             if (bSetColorInterpretation)
    1347                 :             {
    1348                 :                 /* FIXME? Does it make sense if the JPEG/JPEG2000 driver decodes */
    1349                 :                 /* YCbCr data as RGB. We probably don't want to set */
    1350                 :                 /* the color interpretation as Y, Cb, Cr */
    1351              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"R") )
    1352               0 :                     poBand->SetColorInterpretation( GCI_RedBand );
    1353              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"G") )
    1354               0 :                     poBand->SetColorInterpretation( GCI_GreenBand );
    1355              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"B") )
    1356               0 :                     poBand->SetColorInterpretation( GCI_BlueBand );
    1357              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"M") )
    1358              14 :                     poBand->SetColorInterpretation( GCI_GrayIndex );
    1359              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"Y") )
    1360               4 :                     poBand->SetColorInterpretation( GCI_YCbCr_YBand );
    1361              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
    1362               4 :                     poBand->SetColorInterpretation( GCI_YCbCr_CbBand );
    1363              32 :                 if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
    1364               4 :                     poBand->SetColorInterpretation( GCI_YCbCr_CrBand );
    1365                 :             }
    1366              35 :             if (bSetColorTable)
    1367                 :             {
    1368               3 :                 poBand->SetColorTableFromNITFBandInfo();
    1369               3 :                 poBand->SetColorInterpretation( GCI_PaletteIndex );
    1370                 :             }
    1371                 :             
    1372              35 :             poDS->SetBand( iBand+1, poBand );
    1373                 :         }
    1374                 :         else
    1375                 :         {
    1376          210661 :             GDALRasterBand* poBand = new NITFRasterBand( poDS, iBand+1 );
    1377          210661 :             if (poBand->GetRasterDataType() == GDT_Unknown)
    1378                 :             {
    1379               0 :                 delete poBand;
    1380               0 :                 delete poDS;
    1381               0 :                 return NULL;
    1382                 :             }
    1383          210661 :             poDS->SetBand( iBand+1, poBand );
    1384                 :         }
    1385                 :     }
    1386                 : 
    1387                 : /* -------------------------------------------------------------------- */
    1388                 : /*      Report problems with odd bit sizes.                             */
    1389                 : /* -------------------------------------------------------------------- */
    1390             509 :     if( poOpenInfo->eAccess == GA_Update &&
    1391                 :         psImage != NULL 
    1392                 :         && (psImage->nBitsPerSample % 8 != 0) 
    1393                 :         && poDS->poJPEGDataset == NULL
    1394                 :         && poDS->poJ2KDataset == NULL )
    1395                 :     {
    1396                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    1397                 :                   "Image with %d bits per sample cannot be opened in update mode.", 
    1398               0 :                   psImage->nBitsPerSample );
    1399               0 :         delete poDS;
    1400               0 :         return NULL;
    1401                 :     }
    1402                 : 
    1403                 : /* -------------------------------------------------------------------- */
    1404                 : /*      Process the projection from the ICORDS.                         */
    1405                 : /* -------------------------------------------------------------------- */
    1406             509 :     OGRSpatialReference oSRSWork;
    1407                 : 
    1408             509 :     if( psImage == NULL )
    1409                 :     {
    1410                 :         /* nothing */
    1411                 :     }
    1412             595 :     else if( psImage->chICORDS == 'G' || psImage->chICORDS == 'D' )
    1413                 :     {
    1414              89 :         CPLFree( poDS->pszProjection );
    1415              89 :         poDS->pszProjection = NULL;
    1416                 :         
    1417              89 :         oSRSWork.SetWellKnownGeogCS( "WGS84" );
    1418              89 :         oSRSWork.exportToWkt( &(poDS->pszProjection) );
    1419                 :     }
    1420             417 :     else if( psImage->chICORDS == 'C' )
    1421                 :     {
    1422               0 :         CPLFree( poDS->pszProjection );
    1423               0 :         poDS->pszProjection = NULL;
    1424                 :         
    1425               0 :         oSRSWork.SetWellKnownGeogCS( "WGS84" );
    1426               0 :         oSRSWork.exportToWkt( &(poDS->pszProjection) );
    1427                 : 
    1428                 :         /* convert latitudes from geocentric to geodetic form. */
    1429                 :         
    1430                 :         psImage->dfULY = 
    1431                 :             NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( 
    1432               0 :                 psImage->dfULY );
    1433                 :         psImage->dfLLY = 
    1434                 :             NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( 
    1435               0 :                 psImage->dfLLY );
    1436                 :         psImage->dfURY = 
    1437                 :             NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( 
    1438               0 :                 psImage->dfURY );
    1439                 :         psImage->dfLRY = 
    1440                 :             NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( 
    1441               0 :                 psImage->dfLRY );
    1442                 :     }
    1443             453 :     else if( psImage->chICORDS == 'S' || psImage->chICORDS == 'N' )
    1444                 :     {
    1445              36 :         CPLFree( poDS->pszProjection );
    1446              36 :         poDS->pszProjection = NULL;
    1447                 : 
    1448              36 :         oSRSWork.SetUTM( psImage->nZone, psImage->chICORDS == 'N' );
    1449              36 :         oSRSWork.SetWellKnownGeogCS( "WGS84" );
    1450              36 :         oSRSWork.exportToWkt( &(poDS->pszProjection) );
    1451                 :     }
    1452             381 :     else if( psImage->chICORDS == 'U' && psImage->nZone != 0 )
    1453                 :     {
    1454               2 :         CPLFree( poDS->pszProjection );
    1455               2 :         poDS->pszProjection = NULL;
    1456                 : 
    1457               2 :         oSRSWork.SetUTM( ABS(psImage->nZone), psImage->nZone > 0 );
    1458               2 :         oSRSWork.SetWellKnownGeogCS( "WGS84" );
    1459               2 :         oSRSWork.exportToWkt( &(poDS->pszProjection) );
    1460                 :     }
    1461                 : 
    1462                 : 
    1463                 : /* -------------------------------------------------------------------- */
    1464                 : /*      Try looking for a .nfw file.                                    */
    1465                 : /* -------------------------------------------------------------------- */
    1466             509 :     if( psImage
    1467                 :         && GDALReadWorldFile( pszFilename, "nfw", 
    1468                 :                               poDS->adfGeoTransform ) )
    1469                 :     {
    1470                 :         const char *pszHDR;
    1471                 :         FILE *fpHDR;
    1472                 :         char **papszLines;
    1473                 :         int isNorth;
    1474                 :         int zone;
    1475                 :         
    1476               3 :         poDS->bGotGeoTransform = TRUE;
    1477                 : 
    1478                 :         /* If nfw found, try looking for a header with projection info */
    1479                 :         /* in space imaging style format                               */
    1480               3 :         pszHDR = CPLResetExtension( pszFilename, "hdr" );
    1481                 :         
    1482               3 :         fpHDR = VSIFOpenL( pszHDR, "rt" );
    1483                 : 
    1484                 : #ifndef WIN32
    1485               3 :         if( fpHDR == NULL )
    1486                 :         {
    1487               1 :             pszHDR = CPLResetExtension( pszFilename, "HDR" );
    1488               1 :             fpHDR = VSIFOpenL( pszHDR, "rt" );
    1489                 :         }
    1490                 : #endif
    1491                 :     
    1492               3 :         if( fpHDR != NULL )
    1493                 :         {
    1494               2 :             VSIFCloseL( fpHDR );
    1495               2 :             papszLines=CSLLoad2(pszHDR, 16, 200, NULL);
    1496               2 :             if (CSLCount(papszLines) == 16)
    1497                 :             {
    1498                 : 
    1499               2 :                 if (psImage->chICORDS == 'N')
    1500               2 :                     isNorth=1;
    1501               0 :                 else if (psImage->chICORDS =='S')
    1502               0 :                     isNorth=0;
    1503                 :                 else
    1504                 :                 {
    1505               0 :                     if (psImage->dfLLY+psImage->dfLRY+psImage->dfULY+psImage->dfURY < 0)
    1506               0 :                         isNorth=0;
    1507                 :                     else
    1508               0 :                         isNorth=1;
    1509                 :                 }
    1510               4 :                 if( (EQUALN(papszLines[7],
    1511                 :                             "Selected Projection: Universal Transverse Mercator",50)) &&
    1512                 :                     (EQUALN(papszLines[8],"Zone: ",6)) &&
    1513                 :                     (strlen(papszLines[8]) >= 7))
    1514                 :                 {
    1515               2 :                     CPLFree( poDS->pszProjection );
    1516               2 :                     poDS->pszProjection = NULL;
    1517               2 :                     zone=atoi(&(papszLines[8][6]));
    1518               2 :                     oSRSWork.Clear();
    1519               2 :                     oSRSWork.SetUTM( zone, isNorth );
    1520               2 :                     oSRSWork.SetWellKnownGeogCS( "WGS84" );
    1521               2 :                     oSRSWork.exportToWkt( &(poDS->pszProjection) );
    1522                 :                 }
    1523                 :                 else
    1524                 :                 {
    1525                 :                     /* Couldn't find associated projection info.
    1526                 :                        Go back to original file for geotransform.
    1527                 :                     */
    1528               0 :                     poDS->bGotGeoTransform = FALSE;
    1529                 :                 }
    1530                 :             }
    1531                 :             else
    1532               0 :                 poDS->bGotGeoTransform = FALSE;
    1533               2 :             CSLDestroy(papszLines);
    1534                 :         }
    1535                 :         else
    1536               1 :             poDS->bGotGeoTransform = FALSE;
    1537                 :     }
    1538                 : 
    1539                 : /* -------------------------------------------------------------------- */
    1540                 : /*      Does this look like a CADRG polar tile ? (#2940)                */
    1541                 : /* -------------------------------------------------------------------- */
    1542             509 :     const char* pszIID1 = (psImage) ? CSLFetchNameValue(psImage->papszMetadata, "NITF_IID1") : NULL;
    1543             509 :     const char* pszITITLE = (psImage) ? CSLFetchNameValue(psImage->papszMetadata, "NITF_ITITLE") : NULL;
    1544             509 :     if( psImage != NULL && !poDS->bGotGeoTransform &&
    1545                 :         (psImage->chICORDS == 'G' || psImage->chICORDS == 'D') &&
    1546                 :         pszIID1 != NULL && EQUAL(pszIID1, "CADRG") &&
    1547                 :         pszITITLE != NULL && strlen(pszITITLE) >= 12 
    1548                 :         && (pszITITLE[strlen(pszITITLE) - 1] == '9' 
    1549                 :             || pszITITLE[strlen(pszITITLE) - 1] == 'J') )
    1550                 :     {
    1551                 :         /* To get a perfect rectangle in Azimuthal Equidistant projection, we must use */
    1552                 :         /* the sphere and not WGS84 ellipsoid. That's a bit strange... */
    1553               2 :         const char* pszNorthPolarProjection = "+proj=aeqd +lat_0=90 +lon_0=0 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +units=m +no_defs";
    1554               2 :         const char* pszSouthPolarProjection = "+proj=aeqd +lat_0=-90 +lon_0=0 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +units=m +no_defs";
    1555                 : 
    1556               2 :         OGRSpatialReference oSRS_AEQD, oSRS_WGS84;
    1557                 : 
    1558               2 :         const char *pszPolarProjection = (psImage->dfULY > 0) ? pszNorthPolarProjection : pszSouthPolarProjection;
    1559               2 :         oSRS_AEQD.importFromProj4(pszPolarProjection);
    1560                 : 
    1561               2 :         oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
    1562                 : 
    1563               2 :         CPLPushErrorHandler( CPLQuietErrorHandler );
    1564                 :         OGRCoordinateTransformationH hCT =
    1565               2 :             (OGRCoordinateTransformationH)OGRCreateCoordinateTransformation(&oSRS_WGS84, &oSRS_AEQD);
    1566               2 :         CPLPopErrorHandler();
    1567               2 :         if (hCT)
    1568                 :         {
    1569               2 :             double dfULX_AEQD = psImage->dfULX;
    1570               2 :             double dfULY_AEQD = psImage->dfULY;
    1571               2 :             double dfURX_AEQD = psImage->dfURX;
    1572               2 :             double dfURY_AEQD = psImage->dfURY;
    1573               2 :             double dfLLX_AEQD = psImage->dfLLX;
    1574               2 :             double dfLLY_AEQD = psImage->dfLLY;
    1575               2 :             double dfLRX_AEQD = psImage->dfLRX;
    1576               2 :             double dfLRY_AEQD = psImage->dfLRY;
    1577               2 :             double z = 0;
    1578               2 :             int bSuccess = TRUE;
    1579               2 :             bSuccess &= OCTTransform(hCT, 1, &dfULX_AEQD, &dfULY_AEQD, &z);
    1580               2 :             bSuccess &= OCTTransform(hCT, 1, &dfURX_AEQD, &dfURY_AEQD, &z);
    1581               2 :             bSuccess &= OCTTransform(hCT, 1, &dfLLX_AEQD, &dfLLY_AEQD, &z);
    1582               2 :             bSuccess &= OCTTransform(hCT, 1, &dfLRX_AEQD, &dfLRY_AEQD, &z);
    1583               2 :             if (bSuccess)
    1584                 :             {
    1585                 :                 /* Check that the coordinates of the 4 corners in Azimuthal Equidistant projection */
    1586                 :                 /* are a rectangle */
    1587               2 :                 if (fabs((dfULX_AEQD - dfLLX_AEQD) / dfLLX_AEQD) < 1e-6 &&
    1588                 :                     fabs((dfURX_AEQD - dfLRX_AEQD) / dfLRX_AEQD) < 1e-6 &&
    1589                 :                     fabs((dfULY_AEQD - dfURY_AEQD) / dfURY_AEQD) < 1e-6 &&
    1590                 :                     fabs((dfLLY_AEQD - dfLRY_AEQD) / dfLRY_AEQD) < 1e-6)
    1591                 :                 {
    1592               2 :                     CPLFree(poDS->pszProjection);
    1593               2 :                     oSRS_AEQD.exportToWkt( &(poDS->pszProjection) );
    1594                 : 
    1595               2 :                     poDS->bGotGeoTransform = TRUE;
    1596               2 :                     poDS->adfGeoTransform[0] = dfULX_AEQD;
    1597               2 :                     poDS->adfGeoTransform[1] = (dfURX_AEQD - dfULX_AEQD) / poDS->nRasterXSize;
    1598               2 :                     poDS->adfGeoTransform[2] = 0;
    1599               2 :                     poDS->adfGeoTransform[3] = dfULY_AEQD;
    1600               2 :                     poDS->adfGeoTransform[4] = 0;
    1601               2 :                     poDS->adfGeoTransform[5] = (dfLLY_AEQD - dfULY_AEQD) / poDS->nRasterYSize;
    1602                 :                 }
    1603                 :             }
    1604               2 :             OCTDestroyCoordinateTransformation(hCT);
    1605                 :         }
    1606                 :         else
    1607                 :         {
    1608                 :             // if we cannot instantiate the transformer, then we
    1609                 :             // will at least attempt to record what we believe the
    1610                 :             // natural coordinate system of the image is.  This is 
    1611                 :             // primarily used by ArcGIS (#3337)
    1612                 : 
    1613               0 :             CPLErrorReset();
    1614                 : 
    1615                 :             CPLError( CE_Warning, CPLE_AppDefined,
    1616               0 :                       "Failed to instantiate coordinate system transformer, likely PROJ.DLL/libproj.so is not available.  Returning image corners as lat/long GCPs as a fallback." );
    1617                 : 
    1618               0 :             char *pszAEQD = NULL;
    1619               0 :             oSRS_AEQD.exportToWkt( &(pszAEQD) );
    1620               0 :             poDS->SetMetadataItem( "GCPPROJECTIONX", pszAEQD, "IMAGE_STRUCTURE" );
    1621               0 :             CPLFree( pszAEQD );
    1622               2 :         }
    1623                 :     }
    1624                 : 
    1625                 : /* -------------------------------------------------------------------- */
    1626                 : /*      Do we have IGEOLO data that can be treated as a                 */
    1627                 : /*      geotransform?  Our approach should support images in an         */
    1628                 : /*      affine rotated frame of reference.                              */
    1629                 : /* -------------------------------------------------------------------- */
    1630             509 :     int nGCPCount = 0;
    1631             509 :     GDAL_GCP    *psGCPs = NULL;
    1632                 : 
    1633             509 :     if( psImage && !poDS->bGotGeoTransform && psImage->chICORDS != ' ' )
    1634                 :     {
    1635             124 :         nGCPCount = 4;
    1636                 : 
    1637             124 :         psGCPs = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nGCPCount);
    1638             124 :         GDALInitGCPs( nGCPCount, psGCPs );
    1639                 : 
    1640             124 :         if( psImage->bIsBoxCenterOfPixel ) 
    1641                 :         {
    1642             100 :             psGCPs[0].dfGCPPixel  = 0.5;
    1643             100 :             psGCPs[0].dfGCPLine   = 0.5;
    1644             100 :             psGCPs[1].dfGCPPixel = poDS->nRasterXSize-0.5;
    1645             100 :             psGCPs[1].dfGCPLine = 0.5;
    1646             100 :             psGCPs[2].dfGCPPixel = poDS->nRasterXSize-0.5;
    1647             100 :             psGCPs[2].dfGCPLine = poDS->nRasterYSize-0.5;
    1648             100 :             psGCPs[3].dfGCPPixel = 0.5;
    1649             100 :             psGCPs[3].dfGCPLine = poDS->nRasterYSize-0.5;
    1650                 :         }
    1651                 :         else
    1652                 :         {
    1653              24 :             psGCPs[0].dfGCPPixel  = 0.0;
    1654              24 :             psGCPs[0].dfGCPLine   = 0.0;
    1655              24 :             psGCPs[1].dfGCPPixel = poDS->nRasterXSize;
    1656              24 :             psGCPs[1].dfGCPLine = 0.0;
    1657              24 :             psGCPs[2].dfGCPPixel = poDS->nRasterXSize;
    1658              24 :             psGCPs[2].dfGCPLine = poDS->nRasterYSize;
    1659              24 :             psGCPs[3].dfGCPPixel = 0.0;
    1660              24 :             psGCPs[3].dfGCPLine = poDS->nRasterYSize;
    1661                 :         }
    1662                 : 
    1663             124 :         psGCPs[0].dfGCPX    = psImage->dfULX;
    1664             124 :         psGCPs[0].dfGCPY    = psImage->dfULY;
    1665                 : 
    1666             124 :         psGCPs[1].dfGCPX    = psImage->dfURX;
    1667             124 :         psGCPs[1].dfGCPY    = psImage->dfURY;
    1668                 : 
    1669             124 :         psGCPs[2].dfGCPX    = psImage->dfLRX;
    1670             124 :         psGCPs[2].dfGCPY    = psImage->dfLRY;
    1671                 : 
    1672             124 :         psGCPs[3].dfGCPX    = psImage->dfLLX;
    1673             124 :         psGCPs[3].dfGCPY    = psImage->dfLLY;
    1674                 :     }
    1675                 : 
    1676                 : /* -------------------------------------------------------------------- */
    1677                 : /*      Convert the GCPs into a geotransform definition, if possible.   */
    1678                 : /* -------------------------------------------------------------------- */
    1679             509 :     if( !psImage )
    1680                 :     {
    1681                 :         /* nothing */
    1682                 :     }
    1683             506 :     else if( poDS->bGotGeoTransform == FALSE 
    1684                 :              && nGCPCount > 0 
    1685                 :              && GDALGCPsToGeoTransform( nGCPCount, psGCPs, 
    1686                 :                                         poDS->adfGeoTransform, FALSE ) )
    1687                 :     { 
    1688             122 :         poDS->bGotGeoTransform = TRUE;
    1689                 :     } 
    1690                 : 
    1691                 : /* -------------------------------------------------------------------- */
    1692                 : /*      If we have IGEOLO that isn't north up, return it as GCPs.       */
    1693                 : /* -------------------------------------------------------------------- */
    1694             384 :     else if( (psImage->dfULX != 0 || psImage->dfURX != 0 
    1695                 :               || psImage->dfLRX != 0 || psImage->dfLLX != 0)
    1696                 :              && psImage->chICORDS != ' ' && 
    1697                 :              ( poDS->bGotGeoTransform == FALSE ) &&
    1698                 :              nGCPCount == 4 )
    1699                 :     {
    1700                 :         CPLDebug( "GDAL", 
    1701                 :                   "NITFDataset::Open() wasn't able to derive a first order\n"
    1702               0 :                   "geotransform.  It will be returned as GCPs.");
    1703                 : 
    1704               0 :         poDS->nGCPCount = nGCPCount;
    1705               0 :         poDS->pasGCPList = psGCPs;
    1706                 : 
    1707               0 :         psGCPs = NULL;
    1708               0 :         nGCPCount = 0;
    1709                 : 
    1710               0 :         CPLFree( poDS->pasGCPList[0].pszId );
    1711               0 :         poDS->pasGCPList[0].pszId = CPLStrdup( "UpperLeft" );
    1712                 : 
    1713               0 :         CPLFree( poDS->pasGCPList[1].pszId );
    1714               0 :         poDS->pasGCPList[1].pszId = CPLStrdup( "UpperRight" );
    1715                 : 
    1716               0 :         CPLFree( poDS->pasGCPList[2].pszId );
    1717               0 :         poDS->pasGCPList[2].pszId = CPLStrdup( "LowerRight" );
    1718                 : 
    1719               0 :         CPLFree( poDS->pasGCPList[3].pszId );
    1720               0 :         poDS->pasGCPList[3].pszId = CPLStrdup( "LowerLeft" );
    1721                 : 
    1722               0 :         poDS->pszGCPProjection = CPLStrdup( poDS->pszProjection );
    1723                 :     }
    1724                 : 
    1725                 :     // This cleans up the original copy of the GCPs used to test if 
    1726                 :     // this IGEOLO could be used for a geotransform if we did not
    1727                 :     // steal the to use as primary gcps.
    1728             509 :     if( nGCPCount > 0 )
    1729                 :     {
    1730             124 :         GDALDeinitGCPs( nGCPCount, psGCPs );
    1731             124 :         CPLFree( psGCPs );
    1732                 :     }
    1733                 : 
    1734                 : /* -------------------------------------------------------------------- */
    1735                 : /*      Do we have PRJPSB and MAPLOB TREs to get better                 */
    1736                 : /*      georeferencing from?                                            */
    1737                 : /* -------------------------------------------------------------------- */
    1738             509 :     if (psImage)
    1739             506 :         poDS->CheckGeoSDEInfo();
    1740                 : 
    1741                 : /* -------------------------------------------------------------------- */
    1742                 : /*      Do we have metadata.                                            */
    1743                 : /* -------------------------------------------------------------------- */
    1744                 :     char **papszMergedMD;
    1745                 :     char **papszUSE00A_MD;
    1746                 : 
    1747                 :     // File and Image level metadata.
    1748             509 :     papszMergedMD = CSLDuplicate( poDS->psFile->papszMetadata );
    1749                 : 
    1750             509 :     if( psImage )
    1751                 :     {
    1752                 :         papszMergedMD = CSLInsertStrings( papszMergedMD, 
    1753                 :                                           CSLCount( papszMergedMD ),
    1754             506 :                                           psImage->papszMetadata );
    1755                 : 
    1756                 :         // Comments.
    1757             506 :         if( psImage->pszComments != NULL && strlen(psImage->pszComments) != 0 )
    1758                 :             papszMergedMD = CSLSetNameValue( 
    1759              17 :                 papszMergedMD, "NITF_IMAGE_COMMENTS", psImage->pszComments );
    1760                 :         
    1761                 :         // Compression code. 
    1762                 :         papszMergedMD = CSLSetNameValue( papszMergedMD, "NITF_IC", 
    1763             506 :                                          psImage->szIC );
    1764                 :         
    1765                 :         // IMODE
    1766                 :         char szIMODE[2];
    1767             506 :         szIMODE[0] = psImage->chIMODE;
    1768             506 :         szIMODE[1] = '\0';
    1769             506 :         papszMergedMD = CSLSetNameValue( papszMergedMD, "NITF_IMODE", szIMODE );
    1770                 : 
    1771                 :         // ILOC/Attachment info
    1772             506 :         if( psImage->nIDLVL != 0 )
    1773                 :         {
    1774                 :             NITFSegmentInfo *psSegInfo 
    1775             504 :                 = psFile->pasSegmentInfo + psImage->iSegment;
    1776                 : 
    1777                 :             papszMergedMD = 
    1778                 :                 CSLSetNameValue( papszMergedMD, "NITF_IDLVL", 
    1779             504 :                                  CPLString().Printf("%d",psImage->nIDLVL) );
    1780                 :             papszMergedMD = 
    1781                 :                 CSLSetNameValue( papszMergedMD, "NITF_IALVL", 
    1782             504 :                                  CPLString().Printf("%d",psImage->nIALVL) );
    1783                 :             papszMergedMD = 
    1784                 :                 CSLSetNameValue( papszMergedMD, "NITF_ILOC_ROW", 
    1785             504 :                                  CPLString().Printf("%d",psImage->nILOCRow) );
    1786                 :             papszMergedMD = 
    1787                 :                 CSLSetNameValue( papszMergedMD, "NITF_ILOC_COLUMN", 
    1788             504 :                                  CPLString().Printf("%d",psImage->nILOCColumn));
    1789                 :             papszMergedMD = 
    1790                 :                 CSLSetNameValue( papszMergedMD, "NITF_CCS_ROW", 
    1791             504 :                                  CPLString().Printf("%d",psSegInfo->nCCS_R) );
    1792                 :             papszMergedMD = 
    1793                 :                 CSLSetNameValue( papszMergedMD, "NITF_CCS_COLUMN", 
    1794             504 :                                  CPLString().Printf("%d", psSegInfo->nCCS_C));
    1795                 :             papszMergedMD = 
    1796                 :                 CSLSetNameValue( papszMergedMD, "NITF_IMAG", 
    1797             504 :                                  psImage->szIMAG );
    1798                 :         }
    1799                 : 
    1800                 :         // USE00A 
    1801             506 :         papszUSE00A_MD = NITFReadUSE00A( psImage );
    1802             506 :         if( papszUSE00A_MD != NULL )
    1803                 :         {
    1804                 :             papszMergedMD = CSLInsertStrings( papszMergedMD, 
    1805                 :                                               CSLCount( papszUSE00A_MD ),
    1806               5 :                                               papszUSE00A_MD );
    1807               5 :             CSLDestroy( papszUSE00A_MD );
    1808                 :         }
    1809                 :         
    1810                 :         // BLOCKA 
    1811             506 :         papszUSE00A_MD = NITFReadBLOCKA( psImage );
    1812             506 :         if( papszUSE00A_MD != NULL )
    1813                 :         {
    1814                 :             papszMergedMD = CSLInsertStrings( papszMergedMD, 
    1815                 :                                               CSLCount( papszUSE00A_MD ),
    1816              14 :                                               papszUSE00A_MD );
    1817              14 :             CSLDestroy( papszUSE00A_MD );
    1818                 :         }
    1819                 :         
    1820             506 :         papszUSE00A_MD = NITFReadSTDIDC( psImage );
    1821             506 :         if( papszUSE00A_MD != NULL )
    1822                 :         {
    1823                 :             papszMergedMD = CSLInsertStrings( papszMergedMD, 
    1824                 :                                               CSLCount( papszUSE00A_MD ),
    1825               3 :                                               papszUSE00A_MD );
    1826               3 :             CSLDestroy( papszUSE00A_MD );
    1827                 :         }
    1828                 :     }
    1829                 :         
    1830             509 :     poDS->SetMetadata( papszMergedMD );
    1831             509 :     CSLDestroy( papszMergedMD );
    1832                 : 
    1833                 : /* -------------------------------------------------------------------- */
    1834                 : /*      Image structure metadata.                                       */
    1835                 : /* -------------------------------------------------------------------- */
    1836             509 :     if( psImage == NULL )
    1837                 :         /* do nothing */;
    1838             506 :     else if( psImage->szIC[1] == '1' )
    1839                 :         poDS->SetMetadataItem( "COMPRESSION", "BILEVEL", 
    1840               1 :                                "IMAGE_STRUCTURE" );
    1841             505 :     else if( psImage->szIC[1] == '2' )
    1842                 :         poDS->SetMetadataItem( "COMPRESSION", "ARIDPCM", 
    1843               2 :                                "IMAGE_STRUCTURE" );
    1844             503 :     else if( psImage->szIC[1] == '3' )
    1845                 :         poDS->SetMetadataItem( "COMPRESSION", "JPEG", 
    1846              22 :                                "IMAGE_STRUCTURE" );
    1847             481 :     else if( psImage->szIC[1] == '4' )
    1848                 :         poDS->SetMetadataItem( "COMPRESSION", "VECTOR QUANTIZATION", 
    1849              25 :                                "IMAGE_STRUCTURE" );
    1850             456 :     else if( psImage->szIC[1] == '5' )
    1851                 :         poDS->SetMetadataItem( "COMPRESSION", "LOSSLESS JPEG", 
    1852               0 :                                "IMAGE_STRUCTURE" );
    1853             456 :     else if( psImage->szIC[1] == '8' )
    1854                 :         poDS->SetMetadataItem( "COMPRESSION", "JPEG2000", 
    1855              12 :                                "IMAGE_STRUCTURE" );
    1856                 :     
    1857                 : /* -------------------------------------------------------------------- */
    1858                 : /*      Do we have RPC info.                                            */
    1859                 : /* -------------------------------------------------------------------- */
    1860                 :     NITFRPC00BInfo sRPCInfo;
    1861                 : 
    1862             509 :     if( psImage
    1863                 :         && NITFReadRPC00B( psImage, &sRPCInfo ) && sRPCInfo.SUCCESS )
    1864                 :     {
    1865                 :         char szValue[1280];
    1866                 :         int  i;
    1867                 : 
    1868               3 :         sprintf( szValue, "%.16g", sRPCInfo.LINE_OFF );
    1869               3 :         poDS->SetMetadataItem( "LINE_OFF", szValue, "RPC" );
    1870                 : 
    1871               3 :         sprintf( szValue, "%.16g", sRPCInfo.LINE_SCALE );
    1872               3 :         poDS->SetMetadataItem( "LINE_SCALE", szValue, "RPC" );
    1873                 : 
    1874               3 :         sprintf( szValue, "%.16g", sRPCInfo.SAMP_OFF );
    1875               3 :         poDS->SetMetadataItem( "SAMP_OFF", szValue, "RPC" );
    1876                 : 
    1877               3 :         sprintf( szValue, "%.16g", sRPCInfo.SAMP_SCALE );
    1878               3 :         poDS->SetMetadataItem( "SAMP_SCALE", szValue, "RPC" );
    1879                 : 
    1880               3 :         sprintf( szValue, "%.16g", sRPCInfo.LONG_OFF );
    1881               3 :         poDS->SetMetadataItem( "LONG_OFF", szValue, "RPC" );
    1882                 : 
    1883               3 :         sprintf( szValue, "%.16g", sRPCInfo.LONG_SCALE );
    1884               3 :         poDS->SetMetadataItem( "LONG_SCALE", szValue, "RPC" );
    1885                 : 
    1886               3 :         sprintf( szValue, "%.16g", sRPCInfo.LAT_OFF );
    1887               3 :         poDS->SetMetadataItem( "LAT_OFF", szValue, "RPC" );
    1888                 : 
    1889               3 :         sprintf( szValue, "%.16g", sRPCInfo.LAT_SCALE );
    1890               3 :         poDS->SetMetadataItem( "LAT_SCALE", szValue, "RPC" );
    1891                 : 
    1892               3 :         sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_OFF );
    1893               3 :         poDS->SetMetadataItem( "HEIGHT_OFF", szValue, "RPC" );
    1894                 : 
    1895               3 :         sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_SCALE );
    1896               3 :         poDS->SetMetadataItem( "HEIGHT_SCALE", szValue, "RPC" );
    1897                 : 
    1898               3 :         szValue[0] = '\0'; 
    1899              63 :         for( i = 0; i < 20; i++ )
    1900                 :             sprintf( szValue+strlen(szValue), "%.16g ",  
    1901              60 :                      sRPCInfo.LINE_NUM_COEFF[i] );
    1902               3 :         poDS->SetMetadataItem( "LINE_NUM_COEFF", szValue, "RPC" );
    1903                 : 
    1904               3 :         szValue[0] = '\0'; 
    1905              63 :         for( i = 0; i < 20; i++ )
    1906                 :             sprintf( szValue+strlen(szValue), "%.16g ",  
    1907              60 :                      sRPCInfo.LINE_DEN_COEFF[i] );
    1908               3 :         poDS->SetMetadataItem( "LINE_DEN_COEFF", szValue, "RPC" );
    1909                 :         
    1910               3 :         szValue[0] = '\0'; 
    1911              63 :         for( i = 0; i < 20; i++ )
    1912                 :             sprintf( szValue+strlen(szValue), "%.16g ",  
    1913              60 :                      sRPCInfo.SAMP_NUM_COEFF[i] );
    1914               3 :         poDS->SetMetadataItem( "SAMP_NUM_COEFF", szValue, "RPC" );
    1915                 :         
    1916               3 :         szValue[0] = '\0'; 
    1917              63 :         for( i = 0; i < 20; i++ )
    1918                 :             sprintf( szValue+strlen(szValue), "%.16g ",  
    1919              60 :                      sRPCInfo.SAMP_DEN_COEFF[i] );
    1920               3 :         poDS->SetMetadataItem( "SAMP_DEN_COEFF", szValue, "RPC" );
    1921                 : 
    1922                 :         sprintf( szValue, "%.16g", 
    1923               3 :                  sRPCInfo.LONG_OFF - ( sRPCInfo.LONG_SCALE / 2.0 ) );
    1924               3 :         poDS->SetMetadataItem( "MIN_LONG", szValue, "RPC" );
    1925                 : 
    1926                 :         sprintf( szValue, "%.16g",
    1927               3 :                  sRPCInfo.LONG_OFF + ( sRPCInfo.LONG_SCALE / 2.0 ) );
    1928               3 :         poDS->SetMetadataItem( "MAX_LONG", szValue, "RPC" );
    1929                 : 
    1930                 :         sprintf( szValue, "%.16g", 
    1931               3 :                  sRPCInfo.LAT_OFF - ( sRPCInfo.LAT_SCALE / 2.0 ) );
    1932               3 :         poDS->SetMetadataItem( "MIN_LAT", szValue, "RPC" );
    1933                 : 
    1934                 :         sprintf( szValue, "%.16g", 
    1935               3 :                  sRPCInfo.LAT_OFF + ( sRPCInfo.LAT_SCALE / 2.0 ) );
    1936               3 :         poDS->SetMetadataItem( "MAX_LAT", szValue, "RPC" );
    1937                 :     }
    1938                 : 
    1939                 : /* -------------------------------------------------------------------- */
    1940                 : /*      Do we have Chip info?                                            */
    1941                 : /* -------------------------------------------------------------------- */
    1942                 :     NITFICHIPBInfo sChipInfo;
    1943                 : 
    1944             509 :     if( psImage
    1945                 :         && NITFReadICHIPB( psImage, &sChipInfo ) && sChipInfo.XFRM_FLAG == 0 )
    1946                 :     {
    1947                 :         char szValue[1280];
    1948                 : 
    1949               3 :         sprintf( szValue, "%.16g", sChipInfo.SCALE_FACTOR );
    1950               3 :         poDS->SetMetadataItem( "ICHIP_SCALE_FACTOR", szValue );
    1951                 : 
    1952               3 :         sprintf( szValue, "%d", sChipInfo.ANAMORPH_CORR );
    1953               3 :         poDS->SetMetadataItem( "ICHIP_ANAMORPH_CORR", szValue );
    1954                 : 
    1955               3 :         sprintf( szValue, "%d", sChipInfo.SCANBLK_NUM );
    1956               3 :         poDS->SetMetadataItem( "ICHIP_SCANBLK_NUM", szValue );
    1957                 : 
    1958               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_ROW_11 );
    1959               3 :         poDS->SetMetadataItem( "ICHIP_OP_ROW_11", szValue );
    1960                 : 
    1961               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_COL_11 );
    1962               3 :         poDS->SetMetadataItem( "ICHIP_OP_COL_11", szValue );
    1963                 : 
    1964               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_ROW_12 );
    1965               3 :         poDS->SetMetadataItem( "ICHIP_OP_ROW_12", szValue );
    1966                 : 
    1967               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_COL_12 );
    1968               3 :         poDS->SetMetadataItem( "ICHIP_OP_COL_12", szValue );
    1969                 : 
    1970               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_ROW_21 );
    1971               3 :         poDS->SetMetadataItem( "ICHIP_OP_ROW_21", szValue );
    1972                 : 
    1973               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_COL_21 );
    1974               3 :         poDS->SetMetadataItem( "ICHIP_OP_COL_21", szValue );
    1975                 : 
    1976               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_ROW_22 );
    1977               3 :         poDS->SetMetadataItem( "ICHIP_OP_ROW_22", szValue );
    1978                 : 
    1979               3 :         sprintf( szValue, "%.16g", sChipInfo.OP_COL_22 );
    1980               3 :         poDS->SetMetadataItem( "ICHIP_OP_COL_22", szValue );
    1981                 : 
    1982               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_ROW_11 );
    1983               3 :         poDS->SetMetadataItem( "ICHIP_FI_ROW_11", szValue );
    1984                 : 
    1985               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_COL_11 );
    1986               3 :         poDS->SetMetadataItem( "ICHIP_FI_COL_11", szValue );
    1987                 : 
    1988               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_ROW_12 );
    1989               3 :         poDS->SetMetadataItem( "ICHIP_FI_ROW_12", szValue );
    1990                 : 
    1991               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_COL_12 );
    1992               3 :         poDS->SetMetadataItem( "ICHIP_FI_COL_12", szValue );
    1993                 : 
    1994               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_ROW_21 );
    1995               3 :         poDS->SetMetadataItem( "ICHIP_FI_ROW_21", szValue );
    1996                 : 
    1997               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_COL_21 );
    1998               3 :         poDS->SetMetadataItem( "ICHIP_FI_COL_21", szValue );
    1999                 : 
    2000               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_ROW_22 );
    2001               3 :         poDS->SetMetadataItem( "ICHIP_FI_ROW_22", szValue );
    2002                 : 
    2003               3 :         sprintf( szValue, "%.16g", sChipInfo.FI_COL_22 );
    2004               3 :         poDS->SetMetadataItem( "ICHIP_FI_COL_22", szValue );
    2005                 : 
    2006               3 :         sprintf( szValue, "%d", sChipInfo.FI_ROW );
    2007               3 :         poDS->SetMetadataItem( "ICHIP_FI_ROW", szValue );
    2008                 : 
    2009               3 :         sprintf( szValue, "%d", sChipInfo.FI_COL );
    2010               3 :         poDS->SetMetadataItem( "ICHIP_FI_COL", szValue );
    2011                 : 
    2012                 :     }
    2013                 :     
    2014             509 :     const NITFSeries* series = NITFGetSeriesInfo(pszFilename);
    2015             509 :     if (series)
    2016                 :     {
    2017                 :         poDS->SetMetadataItem("NITF_SERIES_ABBREVIATION",
    2018              22 :                               (series->abbreviation) ? series->abbreviation : "Unknown");
    2019                 :         poDS->SetMetadataItem("NITF_SERIES_NAME",
    2020              22 :                               (series->name) ? series->name : "Unknown");
    2021                 :     }
    2022                 : 
    2023                 : /* -------------------------------------------------------------------- */
    2024                 : /*      If there are multiple image segments, and we are the zeroth,    */
    2025                 : /*      then setup the subdataset metadata.                             */
    2026                 : /* -------------------------------------------------------------------- */
    2027             509 :     int nSubDSCount = 0;
    2028                 : 
    2029             509 :     if( nIMIndex == -1 )
    2030                 :     {
    2031             496 :         char **papszSubdatasets = NULL;
    2032             496 :         int nIMCounter = 0;
    2033                 : 
    2034            3472 :         for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    2035                 :         {
    2036            2976 :             if( EQUAL(psFile->pasSegmentInfo[iSegment].szSegmentType,"IM") )
    2037                 :             {
    2038            2499 :                 CPLString oName;
    2039            2499 :                 CPLString oValue;
    2040                 : 
    2041            2499 :                 oName.Printf( "SUBDATASET_%d_NAME", nIMCounter+1 );
    2042            2499 :                 oValue.Printf( "NITF_IM:%d:%s", nIMCounter, pszFilename );
    2043                 :                 papszSubdatasets = CSLSetNameValue( papszSubdatasets, 
    2044            2499 :                                                     oName, oValue );
    2045                 : 
    2046            2499 :                 oName.Printf( "SUBDATASET_%d_DESC", nIMCounter+1 );
    2047            2499 :                 oValue.Printf( "Image %d of %s", nIMCounter+1, pszFilename );
    2048                 :                 papszSubdatasets = CSLSetNameValue( papszSubdatasets, 
    2049            2499 :                                                     oName, oValue );
    2050                 : 
    2051            2499 :                 nIMCounter++;
    2052                 :             }
    2053                 :         }
    2054                 : 
    2055             496 :         nSubDSCount = CSLCount(papszSubdatasets) / 2;
    2056             496 :         if( nSubDSCount > 1 )
    2057                 :             poDS->GDALMajorObject::SetMetadata( papszSubdatasets, 
    2058               6 :                                                 "SUBDATASETS" );
    2059                 :         
    2060             496 :         CSLDestroy( papszSubdatasets );
    2061                 :     }
    2062                 : 
    2063                 : /* -------------------------------------------------------------------- */
    2064                 : /*      Initialize any PAM information.                                 */
    2065                 : /* -------------------------------------------------------------------- */
    2066             509 :     poDS->SetDescription( poOpenInfo->pszFilename );
    2067                 :     
    2068             509 :     if( nSubDSCount > 1 || nIMIndex != -1 )
    2069                 :     {
    2070              19 :         if( nIMIndex == -1 )
    2071               6 :             nIMIndex = 0;
    2072                 : 
    2073              19 :         poDS->SetSubdatasetName( CPLString().Printf("%d",nIMIndex) );
    2074              19 :         poDS->SetPhysicalFilename( pszFilename );
    2075                 :     }
    2076                 : 
    2077             509 :     poDS->TryLoadXML();
    2078                 : 
    2079                 : /* -------------------------------------------------------------------- */
    2080                 : /*      Do we have a special overview file?  If not, do we have         */
    2081                 : /*      RSets that should be treated as an overview file?               */
    2082                 : /* -------------------------------------------------------------------- */
    2083                 :     const char *pszOverviewFile = 
    2084             509 :         poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
    2085                 : 
    2086             509 :     if( pszOverviewFile == NULL )
    2087                 :     {
    2088             506 :         if( poDS->CheckForRSets(pszFilename) )
    2089               3 :             pszOverviewFile = poDS->osRSetVRT;
    2090                 :     }        
    2091                 : 
    2092                 : /* -------------------------------------------------------------------- */
    2093                 : /*      If we have jpeg or jpeg2000 bands we may need to set the        */
    2094                 : /*      overview file on their dataset. (#3276)                         */
    2095                 : /* -------------------------------------------------------------------- */
    2096             509 :     GDALDataset *poSubDS = poDS->poJ2KDataset;
    2097             509 :     if( poDS->poJPEGDataset )
    2098              13 :         poSubDS = poDS->poJPEGDataset;
    2099                 : 
    2100             509 :     if( poSubDS && pszOverviewFile != NULL )
    2101                 :     {
    2102                 :         poSubDS->SetMetadataItem( "OVERVIEW_FILE", 
    2103                 :                                   pszOverviewFile,
    2104               2 :                                   "OVERVIEWS" );
    2105                 :     }
    2106                 : 
    2107                 : /* -------------------------------------------------------------------- */
    2108                 : /*      If we have jpeg, or jpeg2000 bands we may need to clear         */
    2109                 : /*      their PAM dirty flag too.                                       */
    2110                 : /* -------------------------------------------------------------------- */
    2111             509 :     if( poDS->poJ2KDataset != NULL )
    2112                 :         poDS->poJ2KDataset->SetPamFlags( 
    2113              12 :             poDS->poJ2KDataset->GetPamFlags() & ~GPF_DIRTY );
    2114             509 :     if( poDS->poJPEGDataset != NULL )
    2115                 :         poDS->poJPEGDataset->SetPamFlags( 
    2116              13 :             poDS->poJPEGDataset->GetPamFlags() & ~GPF_DIRTY );
    2117                 : 
    2118                 : /* -------------------------------------------------------------------- */
    2119                 : /*      Check for overviews.                                            */
    2120                 : /* -------------------------------------------------------------------- */
    2121             509 :     if( !EQUAL(poOpenInfo->pszFilename,pszFilename) )
    2122              13 :         poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
    2123                 :     else
    2124             496 :         poDS->oOvManager.Initialize( poDS, pszFilename );
    2125                 : 
    2126             509 :     return( poDS );
    2127                 : }
    2128                 : 
    2129                 : /************************************************************************/
    2130                 : /*                            LoadDODDatum()                            */
    2131                 : /*                                                                      */
    2132                 : /*      Try to turn a US military datum name into a datum definition.   */
    2133                 : /************************************************************************/
    2134                 : 
    2135                 : static OGRErr LoadDODDatum( OGRSpatialReference *poSRS,
    2136               3 :                             const char *pszDatumName )
    2137                 : 
    2138                 : {
    2139                 : /* -------------------------------------------------------------------- */
    2140                 : /*      The most common case...                                         */
    2141                 : /* -------------------------------------------------------------------- */
    2142               3 :     if( EQUALN(pszDatumName,"WGE ",4) )
    2143                 :     {
    2144               0 :         poSRS->SetWellKnownGeogCS( "WGS84" );
    2145               0 :         return OGRERR_NONE;
    2146                 :     }
    2147                 : 
    2148                 : /* -------------------------------------------------------------------- */
    2149                 : /*      All the rest we will try and load from gt_datum.csv             */
    2150                 : /*      (Geotrans datum file).                                          */
    2151                 : /* -------------------------------------------------------------------- */
    2152                 :     char szExpanded[6];
    2153               3 :     const char *pszGTDatum = CSVFilename( "gt_datum.csv" );
    2154                 : 
    2155               3 :     strncpy( szExpanded, pszDatumName, 3 );
    2156               3 :     szExpanded[3] = '\0';
    2157               3 :     if( pszDatumName[3] != ' ' )
    2158                 :     {
    2159                 :         int nLen;
    2160               3 :         strcat( szExpanded, "-" );
    2161               3 :         nLen = strlen(szExpanded);
    2162               3 :         szExpanded[nLen] = pszDatumName[3];
    2163               3 :         szExpanded[nLen + 1] = '\0';
    2164                 :     }
    2165                 : 
    2166                 :     CPLString osDName = CSVGetField( pszGTDatum, "CODE", szExpanded, 
    2167               3 :                                      CC_ApproxString, "NAME" );
    2168               3 :     if( strlen(osDName) == 0 )
    2169                 :     {
    2170                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2171                 :                   "Failed to find datum %s/%s in gt_datum.csv.",
    2172               0 :                   pszDatumName, szExpanded );
    2173               3 :         return OGRERR_FAILURE;
    2174                 :     }
    2175                 :         
    2176                 :     CPLString osEllipseCode = CSVGetField( pszGTDatum, "CODE", szExpanded, 
    2177               3 :                                            CC_ApproxString, "ELLIPSOID" );
    2178                 :     double dfDeltaX = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded, 
    2179               3 :                                            CC_ApproxString, "DELTAX" ) );
    2180                 :     double dfDeltaY = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded, 
    2181               3 :                                            CC_ApproxString, "DELTAY" ) );
    2182                 :     double dfDeltaZ = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded, 
    2183               3 :                                            CC_ApproxString, "DELTAZ" ) );
    2184                 : 
    2185                 : /* -------------------------------------------------------------------- */
    2186                 : /*      Lookup the ellipse code.                                        */
    2187                 : /* -------------------------------------------------------------------- */
    2188               3 :     const char *pszGTEllipse = CSVFilename( "gt_ellips.csv" );
    2189                 :     
    2190                 :     CPLString osEName = CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
    2191               3 :                                      CC_ApproxString, "NAME" );
    2192               3 :     if( strlen(osEName) == 0 )
    2193                 :     {
    2194                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2195                 :                   "Failed to find datum %s in gt_ellips.csv.",
    2196               0 :                   osEllipseCode.c_str() );
    2197               0 :         return OGRERR_FAILURE;
    2198                 :     }    
    2199                 :     
    2200                 :     double dfA = CPLAtof(CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
    2201               3 :                                       CC_ApproxString, "A" ));
    2202                 :     double dfInvF = CPLAtof(CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
    2203               3 :                                          CC_ApproxString, "RF" ));
    2204                 : 
    2205                 : /* -------------------------------------------------------------------- */
    2206                 : /*      Create geographic coordinate system.                            */
    2207                 : /* -------------------------------------------------------------------- */
    2208               3 :     poSRS->SetGeogCS( osDName, osDName, osEName, dfA, dfInvF );
    2209                 : 
    2210               3 :     poSRS->SetTOWGS84( dfDeltaX, dfDeltaY, dfDeltaZ );
    2211                 : 
    2212               3 :     return OGRERR_NONE;
    2213                 : }
    2214                 : 
    2215                 : /************************************************************************/
    2216                 : /*                          CheckGeoSDEInfo()                           */
    2217                 : /*                                                                      */
    2218                 : /*      Check for GeoSDE TREs (GEOPSB/PRJPSB and MAPLOB).  If we        */
    2219                 : /*      have them, use them to override our coordinate system and       */
    2220                 : /*      geotransform info.                                              */
    2221                 : /************************************************************************/
    2222                 : 
    2223             506 : void NITFDataset::CheckGeoSDEInfo()
    2224                 : 
    2225                 : {
    2226             506 :     if( !psImage )
    2227               0 :         return;
    2228                 : 
    2229                 : /* -------------------------------------------------------------------- */
    2230                 : /*      Do we have the required TREs?                                   */
    2231                 : /* -------------------------------------------------------------------- */
    2232                 :     const char *pszGEOPSB , *pszPRJPSB, *pszMAPLOB;
    2233             506 :     OGRSpatialReference oSRS;
    2234                 :     char szName[81];
    2235                 :     int nGEOPSBSize, nPRJPSBSize, nMAPLOBSize;
    2236                 : 
    2237             506 :     pszGEOPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"GEOPSB",&nGEOPSBSize);
    2238             506 :     pszPRJPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"PRJPSB",&nPRJPSBSize);
    2239             506 :     pszMAPLOB = NITFFindTRE(psImage->pachTRE,psImage->nTREBytes,"MAPLOB",&nMAPLOBSize);
    2240                 : 
    2241             506 :     if( pszGEOPSB == NULL || pszPRJPSB == NULL || pszMAPLOB == NULL )
    2242             503 :         return;
    2243                 : 
    2244                 : /* -------------------------------------------------------------------- */
    2245                 : /*      Collect projection parameters.                                  */
    2246                 : /* -------------------------------------------------------------------- */
    2247                 : 
    2248                 :     char szParm[16];
    2249               3 :     if (nPRJPSBSize < 82 + 1)
    2250                 :     {
    2251                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2252               0 :                  "Cannot read PRJPSB TRE. Not enough bytes");
    2253                 :         return;
    2254                 :     }
    2255               3 :     int nParmCount = atoi(NITFGetField(szParm,pszPRJPSB,82,1));
    2256                 :     int i;
    2257               3 :     double adfParm[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    2258                 :     double dfFN;
    2259                 :     double dfFE;
    2260               3 :     if (nPRJPSBSize < 83+15*nParmCount+15+15)
    2261                 :     {
    2262                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2263               0 :                  "Cannot read PRJPSB TRE. Not enough bytes");
    2264                 :         return;
    2265                 :     }
    2266               3 :     for( i = 0; i < nParmCount; i++ )
    2267               0 :         adfParm[i] = atof(NITFGetField(szParm,pszPRJPSB,83+15*i,15));
    2268                 : 
    2269               3 :     dfFE = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount,15));
    2270               3 :     dfFN = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount+15,15));
    2271                 : 
    2272                 : /* -------------------------------------------------------------------- */
    2273                 : /*      Try to handle the projection.                                   */
    2274                 : /* -------------------------------------------------------------------- */
    2275               3 :     if( EQUALN(pszPRJPSB+80,"AC",2) )
    2276                 :         oSRS.SetACEA( adfParm[1], adfParm[2], adfParm[3], adfParm[0], 
    2277               3 :                       dfFE, dfFN );
    2278                 : 
    2279               0 :     else if( EQUALN(pszPRJPSB+80,"AK",2) )
    2280               0 :         oSRS.SetLAEA( adfParm[1], adfParm[0], dfFE, dfFN );
    2281                 : 
    2282               0 :     else if( EQUALN(pszPRJPSB+80,"AL",2) )
    2283               0 :         oSRS.SetAE( adfParm[1], adfParm[0], dfFE, dfFN );
    2284                 : 
    2285               0 :     else if( EQUALN(pszPRJPSB+80,"BF",2) )
    2286               0 :         oSRS.SetBonne( adfParm[1], adfParm[0], dfFE, dfFN );
    2287                 : 
    2288               0 :     else if( EQUALN(pszPRJPSB+80,"CP",2) )
    2289               0 :         oSRS.SetEquirectangular( adfParm[1], adfParm[0], dfFE, dfFN );
    2290                 : 
    2291               0 :     else if( EQUALN(pszPRJPSB+80,"CS",2) )
    2292               0 :         oSRS.SetCS( adfParm[1], adfParm[0], dfFE, dfFN );
    2293                 : 
    2294               0 :     else if( EQUALN(pszPRJPSB+80,"EF",2) )
    2295               0 :         oSRS.SetEckertIV( adfParm[0], dfFE, dfFN );
    2296                 : 
    2297               0 :     else if( EQUALN(pszPRJPSB+80,"ED",2) )
    2298               0 :         oSRS.SetEckertVI( adfParm[0], dfFE, dfFN );
    2299                 : 
    2300               0 :     else if( EQUALN(pszPRJPSB+80,"GN",2) )
    2301               0 :         oSRS.SetGnomonic( adfParm[1], adfParm[0], dfFE, dfFN );
    2302                 : 
    2303               0 :     else if( EQUALN(pszPRJPSB+80,"HX",2) )
    2304                 :         oSRS.SetHOM2PNO( adfParm[1], 
    2305                 :                          adfParm[3], adfParm[2],
    2306                 :                          adfParm[5], adfParm[4],
    2307               0 :                          adfParm[0], dfFE, dfFN );
    2308                 : 
    2309               0 :     else if( EQUALN(pszPRJPSB+80,"KA",2) )
    2310                 :         oSRS.SetEC( adfParm[1], adfParm[2], adfParm[3], adfParm[0], 
    2311               0 :                     dfFE, dfFN );
    2312                 : 
    2313               0 :     else if( EQUALN(pszPRJPSB+80,"LE",2) )
    2314                 :         oSRS.SetLCC( adfParm[1], adfParm[2], adfParm[3], adfParm[0], 
    2315               0 :                      dfFE, dfFN );
    2316                 : 
    2317               0 :     else if( EQUALN(pszPRJPSB+80,"LI",2) )
    2318               0 :         oSRS.SetCEA( adfParm[1], adfParm[0], dfFE, dfFN );
    2319                 : 
    2320               0 :     else if( EQUALN(pszPRJPSB+80,"MC",2) )
    2321               0 :         oSRS.SetMercator( adfParm[2], adfParm[1], 1.0, dfFE, dfFN );
    2322                 : 
    2323               0 :     else if( EQUALN(pszPRJPSB+80,"MH",2) )
    2324               0 :         oSRS.SetMC( 0.0, adfParm[1], dfFE, dfFN );
    2325                 : 
    2326               0 :     else if( EQUALN(pszPRJPSB+80,"MP",2) )
    2327               0 :         oSRS.SetMollweide( adfParm[0], dfFE, dfFN );
    2328                 : 
    2329               0 :     else if( EQUALN(pszPRJPSB+80,"NT",2) )
    2330               0 :         oSRS.SetNZMG( adfParm[1], adfParm[0], dfFE, dfFN );
    2331                 : 
    2332               0 :     else if( EQUALN(pszPRJPSB+80,"OD",2) )
    2333               0 :         oSRS.SetOrthographic( adfParm[1], adfParm[0], dfFE, dfFN );
    2334                 : 
    2335               0 :     else if( EQUALN(pszPRJPSB+80,"PC",2) )
    2336               0 :         oSRS.SetPolyconic( adfParm[1], adfParm[0], dfFE, dfFN );
    2337                 : 
    2338               0 :     else if( EQUALN(pszPRJPSB+80,"PG",2) )
    2339               0 :         oSRS.SetPS( adfParm[1], adfParm[0], 1.0, dfFE, dfFN );
    2340                 : 
    2341               0 :     else if( EQUALN(pszPRJPSB+80,"RX",2) )
    2342               0 :         oSRS.SetRobinson( adfParm[0], dfFE, dfFN );
    2343                 : 
    2344               0 :     else if( EQUALN(pszPRJPSB+80,"SA",2) )
    2345               0 :         oSRS.SetSinusoidal( adfParm[0], dfFE, dfFN );
    2346                 : 
    2347               0 :     else if( EQUALN(pszPRJPSB+80,"TC",2) )
    2348               0 :         oSRS.SetTM( adfParm[2], adfParm[0], adfParm[1], dfFE, dfFN );
    2349                 : 
    2350               0 :     else if( EQUALN(pszPRJPSB+80,"VA",2) )
    2351               0 :         oSRS.SetVDG( adfParm[0], dfFE, dfFN );
    2352                 : 
    2353                 :     else
    2354               0 :         oSRS.SetLocalCS( NITFGetField(szName,pszPRJPSB,0,80) );
    2355                 : 
    2356                 : /* -------------------------------------------------------------------- */
    2357                 : /*      Try to apply the datum.                                         */
    2358                 : /* -------------------------------------------------------------------- */
    2359               3 :     if (nGEOPSBSize < 86 + 4)
    2360                 :     {
    2361                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2362               0 :                  "Cannot read GEOPSB TRE. Not enough bytes");
    2363                 :         return;
    2364                 :     }
    2365               3 :     LoadDODDatum( &oSRS, NITFGetField(szParm,pszGEOPSB,86,4) );
    2366                 : 
    2367                 : /* -------------------------------------------------------------------- */
    2368                 : /*      Get the geotransform                                            */
    2369                 : /* -------------------------------------------------------------------- */
    2370                 :     double adfGT[6];
    2371               3 :     double dfMeterPerUnit = 1.0;
    2372                 : 
    2373               3 :     if (nMAPLOBSize < 28 + 15)
    2374                 :     {
    2375                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2376               0 :                  "Cannot read MAPLOB TRE. Not enough bytes");
    2377                 :         return;
    2378                 :     }
    2379                 :     
    2380               3 :     if( EQUALN(pszMAPLOB+0,"DM ",3) )
    2381               0 :         dfMeterPerUnit = 0.1;
    2382               3 :     else if( EQUALN(pszMAPLOB+0,"CM ",3) )
    2383               0 :         dfMeterPerUnit = 0.01;
    2384               3 :     else if( EQUALN(pszMAPLOB+0,"MM ",3) )
    2385               0 :         dfMeterPerUnit = 0.001;
    2386               3 :     else if( EQUALN(pszMAPLOB+0,"UM ",3) )
    2387               0 :         dfMeterPerUnit = 0.000001;
    2388               3 :     else if( EQUALN(pszMAPLOB+0,"KM ",3) )
    2389               0 :         dfMeterPerUnit = 1000.0;
    2390               3 :     else if( EQUALN(pszMAPLOB+0,"M  ",3) )
    2391               3 :         dfMeterPerUnit = 1.0;
    2392                 :     else
    2393                 :     {
    2394                 :         CPLError( CE_Warning, CPLE_AppDefined,
    2395                 :                   "MAPLOB Unit=%3.3s not regonised, geolocation may be wrong.",
    2396               0 :                   pszMAPLOB+0 );
    2397                 :     }
    2398                 :     
    2399               3 :     adfGT[0] = atof(NITFGetField(szParm,pszMAPLOB,13,15));
    2400               3 :     adfGT[1] = atof(NITFGetField(szParm,pszMAPLOB,3,5)) * dfMeterPerUnit;
    2401               3 :     adfGT[2] = 0.0;
    2402               3 :     adfGT[3] = atof(NITFGetField(szParm,pszMAPLOB,28,15));
    2403               3 :     adfGT[4] = 0.0;
    2404               3 :     adfGT[5] = -atof(NITFGetField(szParm,pszMAPLOB,8,5)) * dfMeterPerUnit;
    2405                 : 
    2406                 : /* -------------------------------------------------------------------- */
    2407                 : /*      Apply back to dataset.                                          */
    2408                 : /* -------------------------------------------------------------------- */
    2409               3 :     CPLFree( pszProjection );
    2410               3 :     pszProjection = NULL;
    2411                 : 
    2412               3 :     oSRS.exportToWkt( &pszProjection );
    2413                 : 
    2414               3 :     memcpy( adfGeoTransform, adfGT, sizeof(double)*6 );
    2415               3 :     bGotGeoTransform = TRUE;
    2416                 : }
    2417                 : 
    2418                 : /************************************************************************/
    2419                 : /*                             AdviseRead()                             */
    2420                 : /************************************************************************/
    2421                 : 
    2422                 : CPLErr NITFDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
    2423                 :                                 int nBufXSize, int nBufYSize, 
    2424                 :                                 GDALDataType eDT, 
    2425                 :                                 int nBandCount, int *panBandList,
    2426               0 :                                 char **papszOptions )
    2427                 :     
    2428                 : {
    2429               0 :     if( poJ2KDataset == NULL )
    2430                 :         return GDALDataset::AdviseRead( nXOff, nYOff, nXSize, nYSize, 
    2431                 :                                         nBufXSize, nBufYSize, eDT, 
    2432                 :                                         nBandCount, panBandList, 
    2433               0 :                                         papszOptions);
    2434               0 :     else if( poJPEGDataset != NULL )
    2435                 :         return poJPEGDataset->AdviseRead( nXOff, nYOff, nXSize, nYSize, 
    2436                 :                                           nBufXSize, nBufYSize, eDT, 
    2437                 :                                           nBandCount, panBandList, 
    2438               0 :                                           papszOptions);
    2439                 :     else
    2440                 :         return poJ2KDataset->AdviseRead( nXOff, nYOff, nXSize, nYSize, 
    2441                 :                                          nBufXSize, nBufYSize, eDT, 
    2442                 :                                          nBandCount, panBandList, 
    2443               0 :                                          papszOptions);
    2444                 : }
    2445                 : 
    2446                 : /************************************************************************/
    2447                 : /*                             IRasterIO()                              */
    2448                 : /************************************************************************/
    2449                 : 
    2450                 : CPLErr NITFDataset::IRasterIO( GDALRWFlag eRWFlag,
    2451                 :                                int nXOff, int nYOff, int nXSize, int nYSize,
    2452                 :                                void * pData, int nBufXSize, int nBufYSize,
    2453                 :                                GDALDataType eBufType, 
    2454                 :                                int nBandCount, int *panBandMap,
    2455             665 :                                int nPixelSpace, int nLineSpace, int nBandSpace)
    2456                 :     
    2457                 : {
    2458             665 :     if( poJ2KDataset != NULL )
    2459                 :         return poJ2KDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2460                 :                                        pData, nBufXSize, nBufYSize, eBufType,
    2461                 :                                        nBandCount, panBandMap, 
    2462               0 :                                        nPixelSpace, nLineSpace, nBandSpace );
    2463             665 :     else if( poJPEGDataset != NULL )
    2464                 :         return poJPEGDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2465                 :                                         pData, nBufXSize, nBufYSize, eBufType,
    2466                 :                                         nBandCount, panBandMap, 
    2467              64 :                                         nPixelSpace, nLineSpace, nBandSpace );
    2468                 :     else 
    2469                 :         return GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2470                 :                                        pData, nBufXSize, nBufYSize, eBufType,
    2471                 :                                        nBandCount, panBandMap, 
    2472             601 :                                        nPixelSpace, nLineSpace, nBandSpace );
    2473                 : }
    2474                 : 
    2475                 : 
    2476                 : /************************************************************************/
    2477                 : /*                          GetGeoTransform()                           */
    2478                 : /************************************************************************/
    2479                 : 
    2480              91 : CPLErr NITFDataset::GetGeoTransform( double *padfGeoTransform )
    2481                 : 
    2482                 : {
    2483              91 :     memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
    2484                 : 
    2485              91 :     if( bGotGeoTransform )
    2486              88 :         return CE_None;
    2487                 :     else
    2488               3 :         return GDALPamDataset::GetGeoTransform( padfGeoTransform );
    2489                 : }
    2490                 : 
    2491                 : /************************************************************************/
    2492                 : /*                          SetGeoTransform()                           */
    2493                 : /************************************************************************/
    2494                 : 
    2495              55 : CPLErr NITFDataset::SetGeoTransform( double *padfGeoTransform )
    2496                 : 
    2497                 : {
    2498                 :     double dfIGEOLOULX, dfIGEOLOULY, dfIGEOLOURX, dfIGEOLOURY, 
    2499                 :            dfIGEOLOLRX, dfIGEOLOLRY, dfIGEOLOLLX, dfIGEOLOLLY;
    2500                 : 
    2501              55 :     bGotGeoTransform = TRUE;
    2502                 :     /* Valgrind would complain because SetGeoTransform() is called */
    2503                 :     /* from SetProjection() with adfGeoTransform as argument */
    2504              55 :     if (adfGeoTransform != padfGeoTransform)
    2505              54 :         memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
    2506                 : 
    2507                 :     dfIGEOLOULX = padfGeoTransform[0] + 0.5 * padfGeoTransform[1] 
    2508              55 :                                       + 0.5 * padfGeoTransform[2];
    2509                 :     dfIGEOLOULY = padfGeoTransform[3] + 0.5 * padfGeoTransform[4] 
    2510              55 :                                       + 0.5 * padfGeoTransform[5];
    2511              55 :     dfIGEOLOURX = dfIGEOLOULX + padfGeoTransform[1] * (nRasterXSize - 1);
    2512              55 :     dfIGEOLOURY = dfIGEOLOULY + padfGeoTransform[4] * (nRasterXSize - 1);
    2513                 :     dfIGEOLOLRX = dfIGEOLOULX + padfGeoTransform[1] * (nRasterXSize - 1)
    2514              55 :                               + padfGeoTransform[2] * (nRasterYSize - 1);
    2515                 :     dfIGEOLOLRY = dfIGEOLOULY + padfGeoTransform[4] * (nRasterXSize - 1)
    2516              55 :                               + padfGeoTransform[5] * (nRasterYSize - 1);
    2517              55 :     dfIGEOLOLLX = dfIGEOLOULX + padfGeoTransform[2] * (nRasterYSize - 1);
    2518              55 :     dfIGEOLOLLY = dfIGEOLOULY + padfGeoTransform[5] * (nRasterYSize - 1);
    2519                 : 
    2520              55 :     if( NITFWriteIGEOLO( psImage, psImage->chICORDS, 
    2521                 :                          psImage->nZone, 
    2522                 :                          dfIGEOLOULX, dfIGEOLOULY, dfIGEOLOURX, dfIGEOLOURY, 
    2523                 :                          dfIGEOLOLRX, dfIGEOLOLRY, dfIGEOLOLLX, dfIGEOLOLLY ) )
    2524              36 :         return CE_None;
    2525                 :     else
    2526              19 :         return GDALPamDataset::SetGeoTransform( padfGeoTransform );
    2527                 : }
    2528                 : 
    2529                 : /************************************************************************/
    2530                 : /*                          GetProjectionRef()                          */
    2531                 : /************************************************************************/
    2532                 : 
    2533             102 : const char *NITFDataset::GetProjectionRef()
    2534                 : 
    2535                 : {
    2536             102 :     if( bGotGeoTransform )
    2537              96 :         return pszProjection;
    2538                 :     else
    2539               6 :         return GDALPamDataset::GetProjectionRef();
    2540                 : }
    2541                 : 
    2542                 : /************************************************************************/
    2543                 : /*                            SetProjection()                           */
    2544                 : /************************************************************************/
    2545                 : 
    2546              20 : CPLErr NITFDataset::SetProjection(const char* _pszProjection)
    2547                 : 
    2548                 : {
    2549                 :     int    bNorth;
    2550              20 :     OGRSpatialReference oSRS, oSRS_WGS84;
    2551              20 :     char *pszWKT = (char *) _pszProjection;
    2552                 : 
    2553              20 :     if( pszWKT != NULL )
    2554              20 :         oSRS.importFromWkt( &pszWKT );
    2555                 :     else
    2556               0 :         return CE_Failure;
    2557                 : 
    2558              20 :     oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
    2559              20 :     if ( oSRS.IsSameGeogCS(&oSRS_WGS84) == FALSE)
    2560                 :     {
    2561                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2562               0 :                  "NITF only supports WGS84 geographic and UTM projections.\n");
    2563               0 :         return CE_Failure;
    2564                 :     }
    2565                 : 
    2566              20 :     if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0)
    2567                 :     {
    2568              19 :         if (psImage->chICORDS != 'G' && psImage->chICORDS != 'D')
    2569                 :         {
    2570                 :             CPLError(CE_Failure, CPLE_NotSupported,
    2571              19 :                      "NITF file should have been created with creation option 'ICORDS=G' (or 'ICORDS=D').\n");
    2572              19 :             return CE_Failure;
    2573                 :         }
    2574                 :     }
    2575               1 :     else if( oSRS.GetUTMZone( &bNorth ) > 0)
    2576                 :     {
    2577               1 :         if (bNorth && psImage->chICORDS != 'N')
    2578                 :         {
    2579                 :             CPLError(CE_Failure, CPLE_NotSupported,
    2580               0 :                      "NITF file should have been created with creation option 'ICORDS=N'.\n");
    2581               0 :             return CE_Failure;
    2582                 :         }
    2583               1 :         else if (!bNorth && psImage->chICORDS != 'S')
    2584                 :         {
    2585                 :             CPLError(CE_Failure, CPLE_NotSupported,
    2586               0 :                      "NITF file should have been created with creation option 'ICORDS=S'.\n");
    2587               0 :             return CE_Failure;
    2588                 :         }
    2589                 : 
    2590               1 :         psImage->nZone = oSRS.GetUTMZone( NULL );
    2591                 :     }
    2592                 :     else
    2593                 :     {
    2594                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2595               0 :                  "NITF only supports WGS84 geographic and UTM projections.\n");
    2596               0 :         return CE_Failure;
    2597                 :     }
    2598                 : 
    2599               1 :     CPLFree(pszProjection);
    2600               1 :     pszProjection = CPLStrdup(_pszProjection);
    2601                 : 
    2602               1 :     if (bGotGeoTransform)
    2603               1 :         SetGeoTransform(adfGeoTransform);
    2604                 : 
    2605               1 :     return CE_None;
    2606                 : }
    2607                 : 
    2608                 : /************************************************************************/
    2609                 : /*                       InitializeCGMMetadata()                        */
    2610                 : /************************************************************************/
    2611                 : 
    2612              11 : void NITFDataset::InitializeCGMMetadata()
    2613                 : 
    2614                 : {
    2615              11 :     if( oSpecialMD.GetMetadataItem( "SEGMENT_COUNT", "CGM" ) != NULL )
    2616               1 :         return;
    2617                 : 
    2618                 :     int iSegment;
    2619              10 :     int iCGM = 0;
    2620              10 :     char **papszCGMMetadata = NULL;
    2621                 : 
    2622                 :     papszCGMMetadata = 
    2623              10 :         CSLSetNameValue( papszCGMMetadata, "SEGMENT_COUNT", "0" );
    2624                 : 
    2625                 : /* ==================================================================== */
    2626                 : /*      Process all graphics segments.                                  */
    2627                 : /* ==================================================================== */
    2628              38 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    2629                 :     {
    2630              28 :         NITFSegmentInfo *psSegment = psFile->pasSegmentInfo + iSegment;
    2631                 : 
    2632              28 :         if( !EQUAL(psSegment->szSegmentType,"GR") 
    2633                 :             && !EQUAL(psSegment->szSegmentType,"SY") )
    2634              14 :             continue;
    2635                 : 
    2636                 :         papszCGMMetadata = 
    2637                 :             CSLSetNameValue( papszCGMMetadata, 
    2638                 :                              CPLString().Printf("SEGMENT_%d_SLOC_ROW", iCGM), 
    2639              14 :                              CPLString().Printf("%d",psSegment->nLOC_R) );
    2640                 :         papszCGMMetadata = 
    2641                 :             CSLSetNameValue( papszCGMMetadata, 
    2642                 :                              CPLString().Printf("SEGMENT_%d_SLOC_COL", iCGM), 
    2643              28 :                              CPLString().Printf("%d",psSegment->nLOC_C) );
    2644                 : 
    2645                 :         papszCGMMetadata = 
    2646                 :             CSLSetNameValue( papszCGMMetadata, 
    2647                 :                              CPLString().Printf("SEGMENT_%d_CCS_ROW", iCGM), 
    2648              28 :                              CPLString().Printf("%d",psSegment->nCCS_R) );
    2649                 :         papszCGMMetadata = 
    2650                 :             CSLSetNameValue( papszCGMMetadata, 
    2651                 :                              CPLString().Printf("SEGMENT_%d_CCS_COL", iCGM), 
    2652              28 :                              CPLString().Printf("%d",psSegment->nCCS_C) );
    2653                 : 
    2654                 :         papszCGMMetadata = 
    2655                 :             CSLSetNameValue( papszCGMMetadata, 
    2656                 :                              CPLString().Printf("SEGMENT_%d_SDLVL", iCGM), 
    2657              28 :                              CPLString().Printf("%d",psSegment->nDLVL) );
    2658                 :         papszCGMMetadata = 
    2659                 :             CSLSetNameValue( papszCGMMetadata, 
    2660                 :                              CPLString().Printf("SEGMENT_%d_SALVL", iCGM), 
    2661              28 :                              CPLString().Printf("%d",psSegment->nALVL) );
    2662                 : 
    2663                 : /* -------------------------------------------------------------------- */
    2664                 : /*      Load the raw CGM data itself.                                   */
    2665                 : /* -------------------------------------------------------------------- */
    2666                 :         char *pabyCGMData, *pszEscapedCGMData;
    2667                 : 
    2668              14 :         pabyCGMData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize);
    2669              28 :         if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart, 
    2670                 :                        SEEK_SET ) != 0 
    2671                 :             || VSIFReadL( pabyCGMData, 1, (size_t)psSegment->nSegmentSize, 
    2672                 :                           psFile->fp ) != psSegment->nSegmentSize )
    2673                 :         {
    2674                 :             CPLError( CE_Warning, CPLE_FileIO, 
    2675                 :                       "Failed to read " CPL_FRMT_GUIB " bytes of graphic data at " CPL_FRMT_GUIB ".", 
    2676                 :                       psSegment->nSegmentSize,
    2677               0 :                       psSegment->nSegmentStart );
    2678               0 :             CPLFree(pabyCGMData);
    2679               0 :             return;
    2680                 :         }
    2681                 : 
    2682                 :         pszEscapedCGMData = CPLEscapeString( pabyCGMData, 
    2683                 :                                              (int)psSegment->nSegmentSize, 
    2684              14 :                                              CPLES_BackslashQuotable );
    2685                 : 
    2686                 :         papszCGMMetadata = 
    2687                 :             CSLSetNameValue( papszCGMMetadata, 
    2688                 :                              CPLString().Printf("SEGMENT_%d_DATA", iCGM), 
    2689              14 :                              pszEscapedCGMData );
    2690              14 :         CPLFree( pszEscapedCGMData );
    2691              14 :         CPLFree( pabyCGMData );
    2692                 : 
    2693              14 :         iCGM++;
    2694                 :     }
    2695                 : 
    2696                 : /* -------------------------------------------------------------------- */
    2697                 : /*      Record the CGM segment count.                                   */
    2698                 : /* -------------------------------------------------------------------- */
    2699                 :     papszCGMMetadata = 
    2700                 :         CSLSetNameValue( papszCGMMetadata, 
    2701                 :                          "SEGMENT_COUNT", 
    2702              10 :                          CPLString().Printf( "%d", iCGM ) );
    2703                 : 
    2704              10 :     oSpecialMD.SetMetadata( papszCGMMetadata, "CGM" );
    2705                 : 
    2706              10 :     CSLDestroy( papszCGMMetadata );
    2707                 : }
    2708                 : 
    2709                 : /************************************************************************/
    2710                 : /*                       InitializeTextMetadata()                       */
    2711                 : /************************************************************************/
    2712                 : 
    2713              12 : void NITFDataset::InitializeTextMetadata()
    2714                 : 
    2715                 : {
    2716              12 :     if( oSpecialMD.GetMetadata( "TEXT" ) != NULL )
    2717               2 :         return;
    2718                 : 
    2719                 :     int iSegment;
    2720              10 :     int iText = 0;
    2721                 : 
    2722                 : /* ==================================================================== */
    2723                 : /*      Process all text segments.                                  */
    2724                 : /* ==================================================================== */
    2725             237 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    2726                 :     {
    2727             227 :         NITFSegmentInfo *psSegment = psFile->pasSegmentInfo + iSegment;
    2728                 : 
    2729             227 :         if( !EQUAL(psSegment->szSegmentType,"TX") )
    2730             216 :             continue;
    2731                 : 
    2732                 : /* -------------------------------------------------------------------- */
    2733                 : /*      Load the text header                                            */
    2734                 : /* -------------------------------------------------------------------- */
    2735                 : 
    2736                 :         /* Allocate one extra byte for the NULL terminating character */
    2737                 :         char *pabyHeaderData = (char *) CPLCalloc(1,
    2738              11 :                 (size_t) psSegment->nSegmentHeaderSize + 1);
    2739              11 :         if (VSIFSeekL(psFile->fp, psSegment->nSegmentHeaderStart,
    2740                 :                       SEEK_SET) != 0 ||
    2741                 :             VSIFReadL(pabyHeaderData, 1, (size_t) psSegment->nSegmentHeaderSize,
    2742                 :                       psFile->fp) != psSegment->nSegmentHeaderSize)
    2743                 :         {
    2744                 :             CPLError( CE_Warning, CPLE_FileIO,
    2745                 :                       "Failed to read %d bytes of text header data at " CPL_FRMT_GUIB ".",
    2746                 :                       psSegment->nSegmentHeaderSize,
    2747               0 :                       psSegment->nSegmentHeaderStart);
    2748               0 :             CPLFree(pabyHeaderData);
    2749               0 :             return;
    2750                 :         }
    2751                 : 
    2752                 :         oSpecialMD.SetMetadataItem( CPLString().Printf("HEADER_%d", iText),
    2753              11 :                                     pabyHeaderData, "TEXT");
    2754              11 :         CPLFree(pabyHeaderData);
    2755                 : 
    2756                 : /* -------------------------------------------------------------------- */
    2757                 : /*      Load the raw TEXT data itself.                                  */
    2758                 : /* -------------------------------------------------------------------- */
    2759                 :         char *pabyTextData;
    2760                 : 
    2761                 :         /* Allocate one extra byte for the NULL terminating character */
    2762              11 :         pabyTextData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize+1);
    2763              22 :         if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart, 
    2764                 :                        SEEK_SET ) != 0 
    2765                 :             || VSIFReadL( pabyTextData, 1, (size_t)psSegment->nSegmentSize, 
    2766                 :                           psFile->fp ) != psSegment->nSegmentSize )
    2767                 :         {
    2768                 :             CPLError( CE_Warning, CPLE_FileIO, 
    2769                 :                       "Failed to read " CPL_FRMT_GUIB " bytes of text data at " CPL_FRMT_GUIB ".", 
    2770                 :                       psSegment->nSegmentSize,
    2771               0 :                       psSegment->nSegmentStart );
    2772               0 :             CPLFree( pabyTextData );
    2773               0 :             return;
    2774                 :         }
    2775                 : 
    2776                 :         oSpecialMD.SetMetadataItem( CPLString().Printf( "DATA_%d", iText),
    2777              11 :                                     pabyTextData, "TEXT" );
    2778              11 :         CPLFree( pabyTextData );
    2779                 : 
    2780              11 :         iText++;
    2781                 :     }
    2782                 : }
    2783                 : 
    2784                 : /************************************************************************/
    2785                 : /*                       InitializeTREMetadata()                        */
    2786                 : /************************************************************************/
    2787                 : 
    2788              12 : void NITFDataset::InitializeTREMetadata()
    2789                 : 
    2790                 : {
    2791              12 :     if( oSpecialMD.GetMetadata( "TRE" ) != NULL )
    2792               2 :         return;
    2793                 : 
    2794                 : /* -------------------------------------------------------------------- */
    2795                 : /*      Loop over TRE sources (file and image).                         */
    2796                 : /* -------------------------------------------------------------------- */
    2797                 :     int nTRESrc;
    2798                 : 
    2799              30 :     for( nTRESrc = 0; nTRESrc < 2; nTRESrc++ )
    2800                 :     {
    2801                 :         int nTREBytes;
    2802                 :         char *pszTREData;
    2803                 : 
    2804              20 :         if( nTRESrc == 0 )
    2805                 :         {
    2806              10 :             nTREBytes = psFile->nTREBytes;
    2807              10 :             pszTREData = psFile->pachTRE;
    2808                 :         }
    2809                 :         else
    2810                 :         {
    2811              10 :             if( psImage ) 
    2812                 :             {
    2813              10 :                 nTREBytes = psImage->nTREBytes;
    2814              10 :                 pszTREData = psImage->pachTRE;
    2815                 :             }
    2816                 :             else
    2817                 :             {
    2818               0 :                 nTREBytes = 0;
    2819               0 :                 pszTREData = NULL;
    2820                 :             }
    2821                 :         }
    2822                 : 
    2823                 : /* -------------------------------------------------------------------- */
    2824                 : /*      Loop over TREs.                                                 */
    2825                 : /* -------------------------------------------------------------------- */
    2826                 : 
    2827              46 :         while( nTREBytes >= 11 )
    2828                 :         {
    2829                 :             char szTemp[100];
    2830                 :             char szTag[7];
    2831                 :             char *pszEscapedData;
    2832               6 :             int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
    2833                 : 
    2834               6 :             if (nThisTRESize < 0)
    2835                 :             {
    2836               0 :                 NITFGetField(szTemp, pszTREData, 0, 6 );
    2837                 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
    2838               0 :                         nThisTRESize, szTemp);
    2839               0 :                 return;
    2840                 :             }
    2841               6 :             if (nThisTRESize > nTREBytes - 11)
    2842                 :             {
    2843               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes in TRE");
    2844               0 :                 return;
    2845                 :             }
    2846                 : 
    2847               6 :             strncpy( szTag, pszTREData, 6 );
    2848               6 :             szTag[6] = '\0';
    2849                 : 
    2850                 :             // trim white off tag. 
    2851              12 :             while( strlen(szTag) > 0 && szTag[strlen(szTag)-1] == ' ' )
    2852               0 :                 szTag[strlen(szTag)-1] = '\0';
    2853                 :             
    2854                 :             // escape data. 
    2855                 :             pszEscapedData = CPLEscapeString( pszTREData + 11,
    2856                 :                                               nThisTRESize,
    2857               6 :                                               CPLES_BackslashQuotable );
    2858                 : 
    2859               6 :             oSpecialMD.SetMetadataItem( szTag, pszEscapedData, "TRE" );
    2860               6 :             CPLFree( pszEscapedData );
    2861                 :             
    2862               6 :             nTREBytes -= (nThisTRESize + 11);
    2863               6 :             pszTREData += (nThisTRESize + 11);
    2864                 :         }
    2865                 :     }
    2866                 : 
    2867                 : /* -------------------------------------------------------------------- */
    2868                 : /*      Loop over TRE in DES                                            */
    2869                 : /* -------------------------------------------------------------------- */
    2870                 :     int iSegment;
    2871              23 :     for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
    2872                 :     {
    2873              13 :         NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
    2874                 :         NITFDES *psDES;
    2875              13 :         int nOffset = 0;
    2876                 :         char szTREName[7];
    2877                 :         int nThisTRESize;
    2878                 : 
    2879              13 :         if( !EQUAL(psSegInfo->szSegmentType,"DE") )
    2880              12 :             continue;
    2881                 : 
    2882               1 :         psDES = NITFDESAccess( psFile, iSegment );
    2883               1 :         if( psDES == NULL )
    2884               0 :             continue;
    2885                 : 
    2886               1 :         char* pabyTREData = NULL;
    2887               1 :         nOffset = 0;
    2888               6 :         while (NITFDESGetTRE( psDES, nOffset, szTREName, &pabyTREData, &nThisTRESize))
    2889                 :         {
    2890                 :             char* pszEscapedData = CPLEscapeString( pabyTREData, nThisTRESize,
    2891               4 :                                                 CPLES_BackslashQuotable );
    2892                 : 
    2893                 :             // trim white off tag. 
    2894               8 :             while( strlen(szTREName) > 0 && szTREName[strlen(szTREName)-1] == ' ' )
    2895               0 :                 szTREName[strlen(szTREName)-1] = '\0';
    2896                 : 
    2897               4 :             oSpecialMD.SetMetadataItem( szTREName, pszEscapedData, "TRE" );
    2898                 : 
    2899               4 :             CPLFree(pszEscapedData);
    2900                 : 
    2901               4 :             nOffset += 11 + nThisTRESize;
    2902                 : 
    2903               4 :             NITFDESFreeTREData(pabyTREData);
    2904                 :         }
    2905                 : 
    2906               1 :         NITFDESDeaccess(psDES);
    2907                 :     }
    2908                 : }
    2909                 : 
    2910                 : /************************************************************************/
    2911                 : /*                            GetMetadata()                             */
    2912                 : /************************************************************************/
    2913                 : 
    2914             129 : char **NITFDataset::GetMetadata( const char * pszDomain )
    2915                 : 
    2916                 : {
    2917             129 :     if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
    2918                 :     {
    2919              10 :         InitializeCGMMetadata();
    2920              10 :         return oSpecialMD.GetMetadata( pszDomain );
    2921                 :     }
    2922                 : 
    2923             119 :     if( pszDomain != NULL && EQUAL(pszDomain,"TEXT") )
    2924                 :     {
    2925              11 :         InitializeTextMetadata();
    2926              11 :         return oSpecialMD.GetMetadata( pszDomain );
    2927                 :     }
    2928                 : 
    2929             108 :     if( pszDomain != NULL && EQUAL(pszDomain,"TRE") )
    2930                 :     {
    2931              10 :         InitializeTREMetadata();
    2932              10 :         return oSpecialMD.GetMetadata( pszDomain );
    2933                 :     }
    2934                 : 
    2935              98 :     return GDALPamDataset::GetMetadata( pszDomain );
    2936                 : }
    2937                 : 
    2938                 : /************************************************************************/
    2939                 : /*                          GetMetadataItem()                           */
    2940                 : /************************************************************************/
    2941                 : 
    2942                 : const char *NITFDataset::GetMetadataItem(const char * pszName,
    2943            1257 :                                          const char * pszDomain )
    2944                 : 
    2945                 : {
    2946            1257 :     if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
    2947                 :     {
    2948               1 :         InitializeCGMMetadata();
    2949               1 :         return oSpecialMD.GetMetadataItem( pszName, pszDomain );
    2950                 :     }
    2951                 : 
    2952            1256 :     if( pszDomain != NULL && EQUAL(pszDomain,"TEXT") )
    2953                 :     {
    2954               1 :         InitializeTextMetadata();
    2955               1 :         return oSpecialMD.GetMetadataItem( pszName, pszDomain );
    2956                 :     }
    2957                 : 
    2958            1255 :     if( pszDomain != NULL && EQUAL(pszDomain,"TRE") )
    2959                 :     {
    2960               2 :         InitializeTREMetadata();
    2961               2 :         return oSpecialMD.GetMetadataItem( pszName, pszDomain );
    2962                 :     }
    2963                 : 
    2964            1253 :     if( pszDomain != NULL && EQUAL(pszDomain,"OVERVIEWS") 
    2965                 :         && osRSetVRT.size() > 0 )
    2966               1 :         return osRSetVRT;
    2967                 : 
    2968            1252 :     return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
    2969                 : }
    2970                 : 
    2971                 : 
    2972                 : /************************************************************************/
    2973                 : /*                            GetGCPCount()                             */
    2974                 : /************************************************************************/
    2975                 : 
    2976              10 : int NITFDataset::GetGCPCount()
    2977                 : 
    2978                 : {
    2979              10 :     return nGCPCount;
    2980                 : }
    2981                 : 
    2982                 : /************************************************************************/
    2983                 : /*                          GetGCPProjection()                          */
    2984                 : /************************************************************************/
    2985                 : 
    2986               0 : const char *NITFDataset::GetGCPProjection()
    2987                 : 
    2988                 : {
    2989               0 :     if( nGCPCount > 0 && pszGCPProjection != NULL )
    2990               0 :         return pszGCPProjection;
    2991                 :     else
    2992               0 :         return "";
    2993                 : }
    2994                 : 
    2995                 : /************************************************************************/
    2996                 : /*                               GetGCP()                               */
    2997                 : /************************************************************************/
    2998                 : 
    2999               0 : const GDAL_GCP *NITFDataset::GetGCPs()
    3000                 : 
    3001                 : {
    3002               0 :     return pasGCPList;
    3003                 : }
    3004                 : 
    3005                 : /************************************************************************/
    3006                 : /*                           CheckForRSets()                            */
    3007                 : /*                                                                      */
    3008                 : /*      Check for reduced resolution images in .r<n> files and if       */
    3009                 : /*      found return filename for a virtual file wrapping them as an    */
    3010                 : /*      overview file. (#3457)                                          */
    3011                 : /************************************************************************/
    3012                 : 
    3013             506 : int NITFDataset::CheckForRSets( const char *pszNITFFilename )
    3014                 : 
    3015                 : {
    3016             506 :     bool isR0File = EQUAL(CPLGetExtension(pszNITFFilename),"r0");
    3017                 : 
    3018                 : /* -------------------------------------------------------------------- */
    3019                 : /*      Check to see if we have RSets.                                  */
    3020                 : /* -------------------------------------------------------------------- */
    3021             506 :     std::vector<CPLString> aosRSetFilenames;
    3022                 :     int i;
    3023                 : 
    3024             512 :     for( i = 1; i <= 5; i++ )
    3025                 :     {
    3026             512 :         CPLString osTarget;
    3027                 :         VSIStatBufL sStat;
    3028                 : 
    3029             512 :         if ( isR0File )
    3030                 :         {
    3031               9 :           osTarget = pszNITFFilename;
    3032               9 :           osTarget[osTarget.size()-1] = ('0' + i );
    3033                 :         }
    3034                 :         else
    3035             503 :           osTarget.Printf( "%s.r%d", pszNITFFilename, i );
    3036                 : 
    3037             512 :         if( VSIStatL( osTarget, &sStat ) != 0 )
    3038             506 :             break;
    3039                 : 
    3040               6 :         aosRSetFilenames.push_back( osTarget );
    3041                 :     }
    3042                 :    
    3043             506 :     if( aosRSetFilenames.size() == 0 )
    3044             503 :         return FALSE;
    3045                 :     
    3046                 : /* -------------------------------------------------------------------- */
    3047                 : /*      We do, so try to create a wrapping VRT file.                    */
    3048                 : /* -------------------------------------------------------------------- */
    3049               3 :     CPLString osFragment;
    3050                 :     int iBand;
    3051                 : 
    3052                 :     osRSetVRT.Printf( "<VRTDataset rasterXSize=\"%d\" rasterYSize=\"%d\">\n",
    3053               3 :                   GetRasterXSize()/2, GetRasterYSize()/2 );
    3054                 : 
    3055              12 :     for( iBand = 0; iBand < GetRasterCount(); iBand++ )
    3056                 :     {
    3057               9 :         GDALRasterBand *poBand = GetRasterBand(iBand+1);
    3058                 : 
    3059                 :         osRSetVRT += osFragment.
    3060                 :             Printf( "  <VRTRasterBand dataType=\"%s\" band=\"%d\">\n", 
    3061                 :                     GDALGetDataTypeName( poBand->GetRasterDataType() ),
    3062               9 :                     iBand+1 );
    3063                 : 
    3064              27 :         for( i = 0; i < (int) aosRSetFilenames.size(); i++ )
    3065                 :         {
    3066              18 :             if( i == 0 )
    3067                 :                 osRSetVRT += osFragment.Printf(
    3068                 :                     "    <SimpleSource><SourceFilename>%s</SourceFilename><SourceBand>%d</SourceBand></SimpleSource>\n", 
    3069               9 :                     aosRSetFilenames[i].c_str(), iBand+1 );
    3070                 :             else
    3071                 :                 osRSetVRT += osFragment.Printf(
    3072                 :                     "    <Overview><SourceFilename>%s</SourceFilename><SourceBand>%d</SourceBand></Overview>\n", 
    3073               9 :                     aosRSetFilenames[i].c_str(), iBand+1 );
    3074                 :         }
    3075                 :         osRSetVRT += osFragment.
    3076               9 :             Printf( "  </VRTRasterBand>\n" );
    3077                 :     }
    3078                 : 
    3079               3 :     osRSetVRT += "</VRTDataset>\n";
    3080                 : 
    3081               3 :     return TRUE;
    3082                 : }
    3083                 : 
    3084                 : /************************************************************************/
    3085                 : /*                          IBuildOverviews()                           */
    3086                 : /************************************************************************/
    3087                 : 
    3088                 : CPLErr NITFDataset::IBuildOverviews( const char *pszResampling, 
    3089                 :                                      int nOverviews, int *panOverviewList, 
    3090                 :                                      int nListBands, int *panBandList,
    3091                 :                                      GDALProgressFunc pfnProgress, 
    3092               4 :                                      void * pProgressData )
    3093                 :     
    3094                 : {
    3095                 : /* -------------------------------------------------------------------- */
    3096                 : /*      If we have been using RSets we will need to clear them first.   */
    3097                 : /* -------------------------------------------------------------------- */
    3098               4 :     if( osRSetVRT.size() > 0 )
    3099                 :     {
    3100               1 :         oOvManager.CleanOverviews();
    3101               1 :         osRSetVRT = "";
    3102                 :     }
    3103                 : 
    3104                 : /* -------------------------------------------------------------------- */
    3105                 : /*      If we have an underlying JPEG2000 dataset (hopefully via        */
    3106                 : /*      JP2KAK) we will try and build zero overviews as a way of        */
    3107                 : /*      tricking it into clearing existing overviews-from-jpeg2000.     */
    3108                 : /* -------------------------------------------------------------------- */
    3109               4 :     if( poJ2KDataset != NULL 
    3110                 :         && !poJ2KDataset->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" ) )
    3111                 :         poJ2KDataset->IBuildOverviews( pszResampling, 0, NULL, 
    3112                 :                                        nListBands, panBandList, 
    3113               1 :                                        GDALDummyProgress, NULL );
    3114                 : 
    3115                 : /* -------------------------------------------------------------------- */
    3116                 : /*      Use the overview manager to build requested overviews.          */
    3117                 : /* -------------------------------------------------------------------- */
    3118                 :     CPLErr eErr = GDALPamDataset::IBuildOverviews( pszResampling, 
    3119                 :                                                    nOverviews, panOverviewList,
    3120                 :                                                    nListBands, panBandList,
    3121               4 :                                                    pfnProgress, pProgressData );
    3122                 : 
    3123                 : /* -------------------------------------------------------------------- */
    3124                 : /*      If we are working with jpeg or jpeg2000, let the underlying     */
    3125                 : /*      dataset know about the overview file.                           */
    3126                 : /* -------------------------------------------------------------------- */
    3127               4 :     GDALDataset *poSubDS = poJ2KDataset;
    3128               4 :     if( poJPEGDataset )
    3129               1 :         poSubDS = poJPEGDataset;
    3130                 : 
    3131                 :     const char *pszOverviewFile = 
    3132               4 :         GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
    3133                 : 
    3134               4 :     if( poSubDS && pszOverviewFile != NULL && eErr == CE_None
    3135                 :         && poSubDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS") == NULL )
    3136                 :     {
    3137                 :         poSubDS->SetMetadataItem( "OVERVIEW_FILE", 
    3138                 :                                   pszOverviewFile,
    3139               2 :                                   "OVERVIEWS" );
    3140                 :     }
    3141                 : 
    3142               4 :     return eErr;
    3143                 : }
    3144                 : 
    3145                 : /************************************************************************/
    3146                 : /*                           ScanJPEGQLevel()                           */
    3147                 : /*                                                                      */
    3148                 : /*      Search the NITF APP header in the jpeg data stream to find      */
    3149                 : /*      out what predefined Q level tables should be used (or -1 if     */
    3150                 : /*      they are inline).                                               */
    3151                 : /************************************************************************/
    3152                 : 
    3153              41 : int NITFDataset::ScanJPEGQLevel( GUIntBig *pnDataStart )
    3154                 : 
    3155                 : {
    3156                 :     GByte abyHeader[100];
    3157                 : 
    3158              41 :     if( VSIFSeekL( psFile->fp, *pnDataStart,
    3159                 :                    SEEK_SET ) != 0 )
    3160                 :     {
    3161                 :         CPLError( CE_Failure, CPLE_FileIO, 
    3162               0 :                   "Seek error to jpeg data stream." );
    3163               0 :         return 0;
    3164                 :     }
    3165                 :         
    3166              41 :     if( VSIFReadL( abyHeader, 1, sizeof(abyHeader), psFile->fp ) 
    3167                 :         < sizeof(abyHeader) )
    3168                 :     {
    3169                 :         CPLError( CE_Failure, CPLE_FileIO, 
    3170               0 :                   "Read error to jpeg data stream." );
    3171               0 :         return 0;
    3172                 :     }
    3173                 : 
    3174                 : /* -------------------------------------------------------------------- */
    3175                 : /*      Scan ahead for jpeg magic code.  In some files (eg. NSIF)       */
    3176                 : /*      there seems to be some extra junk before the image data stream. */
    3177                 : /* -------------------------------------------------------------------- */
    3178              41 :     GUInt32 nOffset = 0;
    3179              82 :     while( nOffset < sizeof(abyHeader) - 23 
    3180                 :            && (abyHeader[nOffset+0] != 0xff
    3181                 :                || abyHeader[nOffset+1] != 0xd8
    3182                 :                || abyHeader[nOffset+2] != 0xff) )
    3183               0 :         nOffset++;
    3184                 : 
    3185              41 :     if( nOffset >= sizeof(abyHeader) - 23 )
    3186               0 :         return 0;
    3187                 : 
    3188              41 :     *pnDataStart += nOffset;
    3189                 : 
    3190              41 :     if( nOffset > 0 )
    3191                 :         CPLDebug( "NITF", 
    3192                 :                   "JPEG data stream at offset %d from start of data segement, NSIF?", 
    3193               0 :                   nOffset );
    3194                 : 
    3195                 : /* -------------------------------------------------------------------- */
    3196                 : /*      Do we have an NITF app tag?  If so, pull out the Q level.       */
    3197                 : /* -------------------------------------------------------------------- */
    3198              41 :     if( !EQUAL((char *)abyHeader+nOffset+6,"NITF") )
    3199              25 :         return 0;
    3200                 : 
    3201              16 :     return abyHeader[22+nOffset];
    3202                 : }
    3203                 : 
    3204                 : /************************************************************************/
    3205                 : /*                           ScanJPEGBlocks()                           */
    3206                 : /************************************************************************/
    3207                 : 
    3208               3 : CPLErr NITFDataset::ScanJPEGBlocks()
    3209                 : 
    3210                 : {
    3211                 :     int iBlock;
    3212                 :     GUIntBig nJPEGStart = 
    3213               3 :         psFile->pasSegmentInfo[psImage->iSegment].nSegmentStart;
    3214                 : 
    3215               3 :     nQLevel = ScanJPEGQLevel( &nJPEGStart );
    3216                 : 
    3217                 : /* -------------------------------------------------------------------- */
    3218                 : /*      Allocate offset array                                           */
    3219                 : /* -------------------------------------------------------------------- */
    3220                 :     panJPEGBlockOffset = (GIntBig *) 
    3221                 :         CPLCalloc(sizeof(GIntBig),
    3222               3 :                   psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
    3223               3 :     panJPEGBlockOffset[0] = nJPEGStart;
    3224                 : 
    3225               3 :     if ( psImage->nBlocksPerRow * psImage->nBlocksPerColumn == 1)
    3226               0 :         return CE_None;
    3227                 : 
    3228              26 :     for( iBlock = psImage->nBlocksPerRow * psImage->nBlocksPerColumn - 1;
    3229                 :          iBlock > 0; iBlock-- )
    3230              23 :         panJPEGBlockOffset[iBlock] = -1;
    3231                 :     
    3232                 : /* -------------------------------------------------------------------- */
    3233                 : /*      Scan through the whole image data stream identifying all        */
    3234                 : /*      block boundaries.  Each block starts with 0xFFD8 (SOI).         */
    3235                 : /*      They also end with 0xFFD9, but we don't currently look for      */
    3236                 : /*      that.                                                           */
    3237                 : /* -------------------------------------------------------------------- */
    3238               3 :     int iNextBlock = 1;
    3239               3 :     GIntBig iSegOffset = 2;
    3240                 :     GIntBig iSegSize = psFile->pasSegmentInfo[psImage->iSegment].nSegmentSize
    3241               3 :         - (nJPEGStart - psFile->pasSegmentInfo[psImage->iSegment].nSegmentStart);
    3242                 :     GByte abyBlock[512];
    3243               3 :     int ignoreBytes = 0;
    3244                 : 
    3245            3587 :     while( iSegOffset < iSegSize-1 )
    3246                 :     {
    3247            3584 :         size_t nReadSize = MIN((size_t)sizeof(abyBlock),(size_t)(iSegSize - iSegOffset));
    3248                 :         size_t i;
    3249                 : 
    3250            3584 :         if( VSIFSeekL( psFile->fp, panJPEGBlockOffset[0] + iSegOffset, 
    3251                 :                        SEEK_SET ) != 0 )
    3252                 :         {
    3253                 :             CPLError( CE_Failure, CPLE_FileIO, 
    3254               0 :                       "Seek error to jpeg data stream." );
    3255               0 :             return CE_Failure;
    3256                 :         }
    3257                 :         
    3258            3584 :         if( VSIFReadL( abyBlock, 1, nReadSize, psFile->fp ) < (size_t)nReadSize)
    3259                 :         {
    3260                 :             CPLError( CE_Failure, CPLE_FileIO, 
    3261               0 :                       "Read error to jpeg data stream." );
    3262               0 :             return CE_Failure;
    3263                 :         }
    3264                 : 
    3265         1834360 :         for( i = 0; i < nReadSize-1; i++ )
    3266                 :         {
    3267         1830779 :             if (ignoreBytes == 0)
    3268                 :             {
    3269         1830582 :                 if( abyBlock[i] == 0xff )
    3270                 :                 {
    3271                 :                     /* start-of-image marker */ 
    3272            9984 :                     if ( abyBlock[i+1] == 0xd8 )
    3273                 :                     {
    3274                 :                         panJPEGBlockOffset[iNextBlock++] 
    3275              23 :                              = panJPEGBlockOffset[0] + iSegOffset + i; 
    3276                 : 
    3277              23 :                         if( iNextBlock == psImage->nBlocksPerRow*psImage->nBlocksPerColumn) 
    3278                 :                         {
    3279               3 :                             return CE_None;
    3280                 :                         }
    3281                 :                     }
    3282                 :                     /* Skip application-specific data to avoid false positive while detecting */ 
    3283                 :                     /* start-of-image markers (#2927). The size of the application data is */
    3284                 :                     /* found in the two following bytes */
    3285                 :                     /* We need this complex mechanism of ignoreBytes for dealing with */
    3286                 :                     /* application data crossing several abyBlock ... */
    3287            9961 :                     else if ( abyBlock[i+1] >= 0xe0 && abyBlock[i+1] < 0xf0 ) 
    3288                 :                     {
    3289               7 :                         ignoreBytes = -2;
    3290                 :                     }
    3291                 :                 }
    3292                 :             }
    3293             197 :             else if (ignoreBytes < 0)
    3294                 :             {
    3295              14 :                 if (ignoreBytes == -1)
    3296                 :                 {
    3297                 :                     /* Size of the application data */
    3298               7 :                     ignoreBytes = abyBlock[i]*256 + abyBlock[i+1];
    3299                 :                 }
    3300                 :                 else
    3301               7 :                     ignoreBytes++;
    3302                 :             }
    3303                 :             else
    3304                 :             {
    3305             183 :                 ignoreBytes--;
    3306                 :             }
    3307                 :         }
    3308                 : 
    3309            3581 :         iSegOffset += nReadSize - 1;
    3310                 :     }
    3311                 : 
    3312               0 :     return CE_None;
    3313                 : }
    3314                 : 
    3315                 : /************************************************************************/
    3316                 : /*                           ReadJPEGBlock()                            */
    3317                 : /************************************************************************/
    3318                 : 
    3319              55 : CPLErr NITFDataset::ReadJPEGBlock( int iBlockX, int iBlockY )
    3320                 : 
    3321                 : {
    3322                 :     CPLErr eErr;
    3323                 : 
    3324                 : /* -------------------------------------------------------------------- */
    3325                 : /*      If this is our first request, do a scan for block boundaries.   */
    3326                 : /* -------------------------------------------------------------------- */
    3327              55 :     if( panJPEGBlockOffset == NULL )
    3328                 :     {
    3329               5 :         if (EQUAL(psImage->szIC,"M3"))
    3330                 :         {
    3331                 : /* -------------------------------------------------------------------- */
    3332                 : /*      When a data mask subheader is present, we don't need to scan    */
    3333                 : /*      the whole file. We just use the psImage->panBlockStart table    */
    3334                 : /* -------------------------------------------------------------------- */
    3335                 :             panJPEGBlockOffset = (GIntBig *) 
    3336                 :                 CPLCalloc(sizeof(GIntBig),
    3337               2 :                         psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
    3338                 :             int i;
    3339              31 :             for (i=0;i< psImage->nBlocksPerRow*psImage->nBlocksPerColumn;i++)
    3340                 :             {
    3341              29 :                 panJPEGBlockOffset[i] = psImage->panBlockStart[i];
    3342              29 :                 if (panJPEGBlockOffset[i] != -1 && panJPEGBlockOffset[i] != 0xffffffff)
    3343                 :                 {
    3344              25 :                     GUIntBig nOffset = panJPEGBlockOffset[i];
    3345              25 :                     nQLevel = ScanJPEGQLevel(&nOffset);
    3346                 :                     /* The beginning of the JPEG stream should be the offset */
    3347                 :                     /* from the panBlockStart table */
    3348              25 :                     if (nOffset != (GUIntBig)panJPEGBlockOffset[i])
    3349                 :                     {
    3350                 :                         CPLError(CE_Failure, CPLE_AppDefined,
    3351               0 :                                  "JPEG block doesn't start at expected offset");
    3352               0 :                         return CE_Failure;
    3353                 :                     }
    3354                 :                 }
    3355                 :             }
    3356                 :         }
    3357                 :         else /* 'C3' case */
    3358                 :         {
    3359                 : /* -------------------------------------------------------------------- */
    3360                 : /*      Scan through the whole image data stream identifying all        */
    3361                 : /*      block boundaries.                                               */
    3362                 : /* -------------------------------------------------------------------- */
    3363               3 :             eErr = ScanJPEGBlocks();
    3364               3 :             if( eErr != CE_None )
    3365               0 :                 return eErr;
    3366                 :         }
    3367                 :     }
    3368                 :     
    3369                 : /* -------------------------------------------------------------------- */
    3370                 : /*    Allocate image data block (where the uncompressed image will go)  */
    3371                 : /* -------------------------------------------------------------------- */
    3372              55 :     if( pabyJPEGBlock == NULL )
    3373                 :     {
    3374                 :         /* Allocate enough memory to hold 12bit JPEG data */
    3375                 :         pabyJPEGBlock = (GByte *) 
    3376                 :             CPLCalloc(psImage->nBands,
    3377               5 :                       psImage->nBlockWidth * psImage->nBlockHeight * 2);
    3378                 :     }
    3379                 : 
    3380                 : 
    3381                 : /* -------------------------------------------------------------------- */
    3382                 : /*      Read JPEG Chunk.                                                */
    3383                 : /* -------------------------------------------------------------------- */
    3384              55 :     CPLString osFilename;
    3385              55 :     int iBlock = iBlockX + iBlockY * psImage->nBlocksPerRow;
    3386                 :     GDALDataset *poDS;
    3387              55 :     int anBands[3] = { 1, 2, 3 };
    3388                 : 
    3389              55 :     if (panJPEGBlockOffset[iBlock] == -1 || panJPEGBlockOffset[iBlock] == 0xffffffff)
    3390                 :     {
    3391               4 :         memset(pabyJPEGBlock, 0, psImage->nBands*psImage->nBlockWidth*psImage->nBlockHeight*2);
    3392               4 :         return CE_None;
    3393                 :     }
    3394                 : 
    3395                 :     osFilename.Printf( "JPEG_SUBFILE:Q%d," CPL_FRMT_GIB ",%d,%s", 
    3396                 :                        nQLevel,
    3397                 :                        panJPEGBlockOffset[iBlock], 0, 
    3398              51 :                        osNITFFilename.c_str() );
    3399                 : 
    3400              51 :     poDS = (GDALDataset *) GDALOpen( osFilename, GA_ReadOnly );
    3401              51 :     if( poDS == NULL )
    3402               0 :         return CE_Failure;
    3403                 : 
    3404              51 :     if( poDS->GetRasterXSize() != psImage->nBlockWidth
    3405                 :         || poDS->GetRasterYSize() != psImage->nBlockHeight )
    3406                 :     {
    3407                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3408                 :                   "JPEG block %d not same size as NITF blocksize.", 
    3409               0 :                   iBlock );
    3410               0 :         delete poDS;
    3411               0 :         return CE_Failure;
    3412                 :     }
    3413                 : 
    3414              51 :     if( poDS->GetRasterCount() < psImage->nBands )
    3415                 :     {
    3416                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3417                 :                   "JPEG block %d has not enough bands.", 
    3418               0 :                   iBlock );
    3419               0 :         delete poDS;
    3420               0 :         return CE_Failure;
    3421                 :     }
    3422                 : 
    3423              51 :     if( poDS->GetRasterBand(1)->GetRasterDataType() != GetRasterBand(1)->GetRasterDataType())
    3424                 :     {
    3425                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3426                 :                   "JPEG block %d data type (%s) not consistant with band data type (%s).", 
    3427                 :                   iBlock, GDALGetDataTypeName(poDS->GetRasterBand(1)->GetRasterDataType()),
    3428               0 :                   GDALGetDataTypeName(GetRasterBand(1)->GetRasterDataType()) );
    3429               0 :         delete poDS;
    3430              55 :         return CE_Failure;
    3431                 :     }
    3432                 : 
    3433                 :     eErr = poDS->RasterIO( GF_Read, 
    3434                 :                            0, 0, 
    3435                 :                            psImage->nBlockWidth, psImage->nBlockHeight,
    3436                 :                            pabyJPEGBlock, 
    3437                 :                            psImage->nBlockWidth, psImage->nBlockHeight,
    3438              51 :                            GetRasterBand(1)->GetRasterDataType(), psImage->nBands, anBands, 0, 0, 0 );
    3439                 : 
    3440              51 :     delete poDS;
    3441                 : 
    3442              51 :     return eErr;
    3443                 : }
    3444                 : 
    3445                 : /************************************************************************/
    3446                 : /*                         GDALToNITFDataType()                         */
    3447                 : /************************************************************************/
    3448                 : 
    3449             205 : static const char *GDALToNITFDataType( GDALDataType eType )
    3450                 : 
    3451                 : {
    3452                 :     const char *pszPVType;
    3453                 : 
    3454             205 :     switch( eType )
    3455                 :     {
    3456                 :       case GDT_Byte:
    3457                 :       case GDT_UInt16:
    3458                 :       case GDT_UInt32:
    3459             175 :         pszPVType = "INT";
    3460             175 :         break;
    3461                 : 
    3462                 :       case GDT_Int16:
    3463                 :       case GDT_Int32:
    3464              10 :         pszPVType = "SI";
    3465              10 :         break;
    3466                 : 
    3467                 :       case GDT_Float32:
    3468                 :       case GDT_Float64:
    3469               8 :         pszPVType = "R";
    3470               8 :         break;
    3471                 : 
    3472                 :       case GDT_CInt16:
    3473                 :       case GDT_CInt32:
    3474                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    3475               6 :                   "NITF format does not support complex integer data." );
    3476               6 :         return NULL;
    3477                 : 
    3478                 :       case GDT_CFloat32:
    3479               3 :         pszPVType = "C";
    3480               3 :         break;
    3481                 : 
    3482                 :       default:
    3483                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3484                 :                   "Unsupported raster pixel type (%s).", 
    3485               3 :                   GDALGetDataTypeName(eType) );
    3486               3 :         return NULL;
    3487                 :     }
    3488                 : 
    3489             196 :     return pszPVType;
    3490                 : }
    3491                 : 
    3492                 : /************************************************************************/
    3493                 : /*                           NITFJP2Options()                           */
    3494                 : /*                                                                      */
    3495                 : /*      Prepare JP2-in-NITF creation options based in part of the       */
    3496                 : /*      NITF creation options.                                          */
    3497                 : /************************************************************************/
    3498                 : 
    3499               0 : static char **NITFJP2Options( char **papszOptions )
    3500                 : 
    3501                 : {
    3502                 :     int i;
    3503               0 :     char** papszJP2Options = NULL;
    3504                 :     
    3505               0 :     papszJP2Options = CSLAddString(papszJP2Options, "PROFILE=NPJE");
    3506               0 :     papszJP2Options = CSLAddString(papszJP2Options, "CODESTREAM_ONLY=TRUE");
    3507                 :     
    3508               0 :     for( i = 0; papszOptions != NULL && papszOptions[i] != NULL; i++ )
    3509                 :     {
    3510               0 :         if( EQUALN(papszOptions[i],"PROFILE=",8) )
    3511                 :         {
    3512               0 :             CPLFree(papszJP2Options[0]);
    3513               0 :             papszJP2Options[0] = CPLStrdup(papszOptions[i]);
    3514                 :         }
    3515               0 :         else if( EQUALN(papszOptions[i],"TARGET=",7) )
    3516               0 :             papszJP2Options = CSLAddString(papszJP2Options, papszOptions[i]);
    3517                 :     }
    3518                 : 
    3519               0 :     return papszJP2Options;
    3520                 : }
    3521                 : 
    3522                 : 
    3523                 : 
    3524                 : /************************************************************************/
    3525                 : /*              NITFExtractTEXTAndCGMCreationOption()                   */
    3526                 : /************************************************************************/
    3527                 : 
    3528                 : static char** NITFExtractTEXTAndCGMCreationOption( GDALDataset* poSrcDS,
    3529                 :                                                    char **papszOptions,
    3530                 :                                                    char ***ppapszTextMD,
    3531             199 :                                                    char ***ppapszCgmMD )
    3532                 : {
    3533             199 :     char** papszFullOptions = CSLDuplicate(papszOptions);
    3534                 : 
    3535                 : /* -------------------------------------------------------------------- */
    3536                 : /*      Prepare for text segments.                                      */
    3537                 : /* -------------------------------------------------------------------- */
    3538             199 :     int iOpt, nNUMT = 0;
    3539             199 :     char **papszTextMD = CSLFetchNameValueMultiple (papszOptions, "TEXT");
    3540                 :     // Notice: CSLFetchNameValueMultiple remove the leading "TEXT=" when
    3541                 :     // returning the list, which is what we want.
    3542                 : 
    3543                 :     // Use TEXT information from original image if no creation option is passed in.
    3544             199 :     if (poSrcDS != NULL && papszTextMD == NULL)
    3545                 :     {
    3546                 :         // Read CGM adata from original image, duplicate the list becuase
    3547                 :         // we frees papszCgmMD at end of the function.
    3548              37 :         papszTextMD = CSLDuplicate( poSrcDS->GetMetadata( "TEXT" ));
    3549                 :     }
    3550                 : 
    3551             207 :     for( iOpt = 0; 
    3552                 :          papszTextMD != NULL && papszTextMD[iOpt] != NULL; 
    3553                 :          iOpt++ )
    3554                 :     {
    3555               8 :         if( !EQUALN(papszTextMD[iOpt],"DATA_",5) )
    3556               3 :             continue;
    3557                 : 
    3558               5 :         nNUMT++;
    3559                 :     }
    3560                 : 
    3561             199 :     if( nNUMT > 0 )
    3562                 :     {
    3563                 :         papszFullOptions = CSLAddString( papszFullOptions, 
    3564                 :                                          CPLString().Printf( "NUMT=%d", 
    3565               4 :                                                              nNUMT ) );
    3566                 :     }
    3567                 : 
    3568                 : /* -------------------------------------------------------------------- */
    3569                 : /*      Prepare for CGM segments.                                       */
    3570                 : /* -------------------------------------------------------------------- */
    3571                 :     const char *pszNUMS; // graphic segment option string
    3572             199 :     int nNUMS = 0;
    3573                 : 
    3574             199 :     char **papszCgmMD = CSLFetchNameValueMultiple (papszOptions, "CGM");
    3575                 :     // Notice: CSLFetchNameValueMultiple remove the leading "CGM=" when
    3576                 :     // returning the list, which is what we want.
    3577                 : 
    3578                 :     // Use CGM information from original image if no creation option is passed in.
    3579             199 :     if (poSrcDS != NULL && papszCgmMD == NULL)
    3580                 :     {
    3581                 :         // Read CGM adata from original image, duplicate the list becuase
    3582                 :         // we frees papszCgmMD at end of the function.
    3583              37 :         papszCgmMD = CSLDuplicate( poSrcDS->GetMetadata( "CGM" ));
    3584                 :     }
    3585                 : 
    3586                 :     // Set NUMS based on the number of segments
    3587             199 :     if (papszCgmMD != NULL)
    3588                 :     {
    3589               8 :         pszNUMS = CSLFetchNameValue(papszCgmMD, "SEGMENT_COUNT");
    3590                 : 
    3591               8 :         if (pszNUMS != NULL) {
    3592               8 :             nNUMS = atoi(pszNUMS);
    3593                 :         }
    3594                 :         papszFullOptions = CSLAddString(papszFullOptions,
    3595               8 :                                         CPLString().Printf("NUMS=%d", nNUMS));
    3596                 :     }
    3597                 : 
    3598             199 :     *ppapszTextMD = papszTextMD;
    3599             199 :     *ppapszCgmMD = papszCgmMD;
    3600                 : 
    3601             199 :     return papszFullOptions;
    3602                 : }
    3603                 : 
    3604                 : /************************************************************************/
    3605                 : /*                         NITFDatasetCreate()                          */
    3606                 : /************************************************************************/
    3607                 : 
    3608                 : GDALDataset *
    3609                 : NITFDataset::NITFDatasetCreate( const char *pszFilename, int nXSize, int nYSize, int nBands,
    3610             167 :                                 GDALDataType eType, char **papszOptions )
    3611                 : 
    3612                 : {
    3613             167 :     const char *pszPVType = GDALToNITFDataType( eType );
    3614             167 :     const char *pszIC = CSLFetchNameValue( papszOptions, "IC" );
    3615                 : 
    3616             167 :     if( pszPVType == NULL )
    3617               6 :         return NULL;
    3618                 : 
    3619                 : /* -------------------------------------------------------------------- */
    3620                 : /*      We disallow any IC value except NC when creating this way.      */
    3621                 : /* -------------------------------------------------------------------- */
    3622             161 :     GDALDriver *poJ2KDriver = NULL;
    3623                 : 
    3624             161 :     if( pszIC != NULL && EQUAL(pszIC,"C8") )
    3625                 :     {
    3626               0 :         int bHasCreate = FALSE;
    3627                 : 
    3628               0 :         poJ2KDriver = GetGDALDriverManager()->GetDriverByName( "JP2ECW" );
    3629               0 :         if( poJ2KDriver != NULL )
    3630                 :             bHasCreate = poJ2KDriver->GetMetadataItem( GDAL_DCAP_CREATE, 
    3631               0 :                                                        NULL ) != NULL;
    3632               0 :         if( !bHasCreate )
    3633                 :         {
    3634                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    3635                 :                       "Unable to create JPEG2000 encoded NITF files.  The\n"
    3636               0 :                       "JP2ECW driver is unavailable, or missing Create support." );
    3637               0 :             return NULL;
    3638                 :         }
    3639                 :     }
    3640                 : 
    3641             161 :     else if( pszIC != NULL && !EQUAL(pszIC,"NC") )
    3642                 :     {
    3643                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    3644                 :                   "Unsupported compression (IC=%s) used in direct\n"
    3645                 :                   "NITF File creation", 
    3646               0 :                   pszIC );
    3647               0 :         return NULL;
    3648                 :     }
    3649                 : 
    3650                 : /* -------------------------------------------------------------------- */
    3651                 : /*      Prepare for text and CGM segments.                              */
    3652                 : /* -------------------------------------------------------------------- */
    3653             161 :     char **papszTextMD = NULL;
    3654             161 :     char **papszCgmMD = NULL;
    3655                 :     char **papszFullOptions = NITFExtractTEXTAndCGMCreationOption( NULL,
    3656                 :                                                           papszOptions,
    3657                 :                                                           &papszTextMD,
    3658             161 :                                                           &papszCgmMD );
    3659                 : 
    3660                 : /* -------------------------------------------------------------------- */
    3661                 : /*      Create the file.                                                */
    3662                 : /* -------------------------------------------------------------------- */
    3663                 : 
    3664             161 :     if( !NITFCreate( pszFilename, nXSize, nYSize, nBands, 
    3665                 :                      GDALGetDataTypeSize( eType ), pszPVType, 
    3666                 :                      papszFullOptions ) )
    3667                 :     {
    3668               9 :         CSLDestroy(papszTextMD);
    3669               9 :         CSLDestroy(papszCgmMD);
    3670               9 :         CSLDestroy(papszFullOptions);
    3671               9 :         return NULL;
    3672                 :     }
    3673                 : 
    3674             152 :     CSLDestroy(papszFullOptions);
    3675             152 :     papszFullOptions = NULL;
    3676                 : 
    3677                 : /* -------------------------------------------------------------------- */
    3678                 : /*      Various special hacks related to JPEG2000 encoded files.        */
    3679                 : /* -------------------------------------------------------------------- */
    3680             152 :     GDALDataset* poWritableJ2KDataset = NULL;
    3681             152 :     if( poJ2KDriver )
    3682                 :     {
    3683               0 :         NITFFile *psFile = NITFOpen( pszFilename, TRUE );
    3684               0 :         GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
    3685                 : 
    3686               0 :         CPLString osDSName;
    3687                 : 
    3688               0 :         osDSName.Printf("J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1, pszFilename);
    3689                 : 
    3690               0 :         NITFClose( psFile );
    3691                 : 
    3692               0 :         char** papszJP2Options = NITFJP2Options(papszOptions);
    3693                 :         poWritableJ2KDataset = 
    3694                 :             poJ2KDriver->Create( osDSName, nXSize, nYSize, nBands, eType, 
    3695               0 :                                  papszJP2Options );
    3696               0 :         CSLDestroy(papszJP2Options);
    3697                 : 
    3698               0 :         if( poWritableJ2KDataset == NULL )
    3699                 :         {
    3700               0 :             CSLDestroy(papszTextMD);
    3701               0 :             CSLDestroy(papszCgmMD);
    3702               0 :             return NULL;
    3703               0 :         }
    3704                 :     }
    3705                 : 
    3706                 : /* -------------------------------------------------------------------- */
    3707                 : /*      Open the dataset in update mode.                                */
    3708                 : /* -------------------------------------------------------------------- */
    3709             152 :     GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
    3710                 :     NITFDataset* poDS = (NITFDataset*)
    3711             152 :             NITFDataset::Open(&oOpenInfo, poWritableJ2KDataset, TRUE);
    3712             152 :     if (poDS)
    3713                 :     {
    3714             152 :         poDS->papszTextMDToWrite = papszTextMD;
    3715             152 :         poDS->papszCgmMDToWrite = papszCgmMD;
    3716                 :     }
    3717                 :     else
    3718                 :     {
    3719               0 :         CSLDestroy(papszTextMD);
    3720               0 :         CSLDestroy(papszCgmMD);
    3721                 :     }
    3722             152 :     return poDS;
    3723                 : }
    3724                 : 
    3725                 : /************************************************************************/
    3726                 : /*                           NITFCreateCopy()                           */
    3727                 : /************************************************************************/
    3728                 : 
    3729                 : GDALDataset *
    3730                 : NITFDataset::NITFCreateCopy( 
    3731                 :     const char *pszFilename, GDALDataset *poSrcDS,
    3732                 :     int bStrict, char **papszOptions, 
    3733              39 :     GDALProgressFunc pfnProgress, void * pProgressData )
    3734                 : 
    3735                 : {
    3736                 :     GDALDataType eType;
    3737                 :     GDALRasterBand *poBand1;
    3738              39 :     int   bJPEG2000 = FALSE;
    3739              39 :     int   bJPEG = FALSE;
    3740              39 :     NITFDataset *poDstDS = NULL;
    3741              39 :     GDALDriver *poJ2KDriver = NULL;
    3742                 : 
    3743              39 :     int  nBands = poSrcDS->GetRasterCount();
    3744              39 :     if( nBands == 0 )
    3745                 :     {
    3746                 :         CPLError( CE_Failure, CPLE_NotSupported,
    3747               1 :                   "Unable to export files with zero bands." );
    3748               1 :         return NULL;
    3749                 :     }
    3750                 : 
    3751              38 :     poBand1 = poSrcDS->GetRasterBand(1);
    3752              38 :     if( poBand1 == NULL )
    3753                 :     {
    3754               0 :         return NULL;
    3755                 :     }
    3756                 : 
    3757                 : /* -------------------------------------------------------------------- */
    3758                 : /*      Only allow supported compression values.                        */
    3759                 : /* -------------------------------------------------------------------- */
    3760              38 :     const char* pszIC = CSLFetchNameValue( papszOptions, "IC" );
    3761              38 :     if( pszIC != NULL )
    3762                 :     {
    3763               6 :         if( EQUAL(pszIC,"NC") )
    3764                 :             /* ok */;
    3765               6 :         else if( EQUAL(pszIC,"C8") )
    3766                 :         {
    3767                 :             poJ2KDriver = 
    3768               1 :                 GetGDALDriverManager()->GetDriverByName( "JP2ECW" );
    3769               1 :             if( poJ2KDriver == NULL )
    3770                 :             {
    3771                 :                 /* Try with Jasper as an alternate driver */
    3772                 :                 poJ2KDriver = 
    3773               1 :                     GetGDALDriverManager()->GetDriverByName( "JPEG2000" );
    3774                 :             }
    3775               1 :             if( poJ2KDriver == NULL )
    3776                 :             {
    3777                 :                 CPLError( 
    3778                 :                     CE_Failure, CPLE_AppDefined, 
    3779                 :                     "Unable to write JPEG2000 compressed NITF file.\n"
    3780                 :                     "No 'subfile' JPEG2000 write supporting drivers are\n"
    3781               0 :                     "configured." );
    3782               0 :                 return NULL;
    3783                 :             }
    3784               1 :             bJPEG2000 = TRUE;
    3785                 :         }
    3786              10 :         else if( EQUAL(pszIC,"C3") || EQUAL(pszIC,"M3") )
    3787                 :         {
    3788               5 :             bJPEG = TRUE;
    3789                 : #ifndef JPEG_SUPPORTED
    3790                 :             CPLError( 
    3791                 :                 CE_Failure, CPLE_AppDefined, 
    3792                 :                 "Unable to write JPEG compressed NITF file.\n"
    3793                 :                 "Libjpeg is not configured into build." );
    3794                 :             return NULL;
    3795                 : #endif
    3796                 :         }
    3797                 :         else
    3798                 :         {
    3799                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    3800                 :                       "Only IC=NC (uncompressed), IC=C3/M3 (JPEG) and IC=C8 (JPEG2000)\n"
    3801               0 :                       "allowed with NITF CreateCopy method." );
    3802               0 :             return NULL;
    3803                 :         }
    3804                 :     }
    3805                 : 
    3806                 : /* -------------------------------------------------------------------- */
    3807                 : /*      Get the data type.  Complex integers isn't supported by         */
    3808                 : /*      NITF, so map that to complex float if we aren't in strict       */
    3809                 : /*      mode.                                                           */
    3810                 : /* -------------------------------------------------------------------- */
    3811              38 :     eType = poBand1->GetRasterDataType();
    3812              38 :     if( !bStrict && (eType == GDT_CInt16 || eType == GDT_CInt32) )
    3813               0 :         eType = GDT_CFloat32;
    3814                 : 
    3815                 : /* -------------------------------------------------------------------- */
    3816                 : /*      Prepare for text and CGM segments.                              */
    3817                 : /* -------------------------------------------------------------------- */
    3818              38 :     char **papszTextMD = NULL;
    3819              38 :     char **papszCgmMD = NULL;
    3820                 :     char **papszFullOptions = NITFExtractTEXTAndCGMCreationOption( poSrcDS,
    3821                 :                                                          papszOptions,
    3822                 :                                                          &papszTextMD,
    3823              38 :                                                          &papszCgmMD );
    3824                 : 
    3825                 : /* -------------------------------------------------------------------- */
    3826                 : /*      Copy over other source metadata items as creation options       */
    3827                 : /*      that seem useful.                                               */
    3828                 : /* -------------------------------------------------------------------- */
    3829              38 :     char **papszSrcMD = poSrcDS->GetMetadata();
    3830                 :     int iMD;
    3831                 : 
    3832             401 :     for( iMD = 0; papszSrcMD && papszSrcMD[iMD]; iMD++ )
    3833                 :     {
    3834             363 :         if( EQUALN(papszSrcMD[iMD],"NITF_BLOCKA",11) 
    3835                 :             || EQUALN(papszSrcMD[iMD],"NITF_FHDR",9) )
    3836                 :         {
    3837              15 :             char *pszName = NULL;
    3838                 :             const char *pszValue = CPLParseNameValue( papszSrcMD[iMD], 
    3839              15 :                                                       &pszName );
    3840              15 :             if( CSLFetchNameValue( papszFullOptions, pszName+5 ) == NULL )
    3841                 :                 papszFullOptions = 
    3842              14 :                     CSLSetNameValue( papszFullOptions, pszName+5, pszValue );
    3843              15 :             CPLFree(pszName);
    3844                 :         }
    3845                 :     }
    3846                 : 
    3847                 : /* -------------------------------------------------------------------- */
    3848                 : /*      Copy TRE definitions as creation options.                       */
    3849                 : /* -------------------------------------------------------------------- */
    3850              38 :     papszSrcMD = poSrcDS->GetMetadata( "TRE" );
    3851                 : 
    3852              39 :     for( iMD = 0; papszSrcMD && papszSrcMD[iMD]; iMD++ )
    3853                 :     {
    3854               1 :         CPLString osTRE;
    3855                 : 
    3856               1 :         if (EQUALN(papszSrcMD[iMD], "RPFHDR", 6) ||
    3857                 :             EQUALN(papszSrcMD[iMD], "RPFIMG", 6) ||
    3858                 :             EQUALN(papszSrcMD[iMD], "RPFDES", 6))
    3859                 :         {
    3860                 :             /* Do not copy RPF TRE. They contain absolute offsets */
    3861                 :             /* No chance that they make sense in the new NITF file */
    3862               0 :             continue;
    3863                 :         }
    3864                 : 
    3865               1 :         osTRE = "TRE=";
    3866               1 :         osTRE += papszSrcMD[iMD];
    3867                 : 
    3868               1 :         papszFullOptions = CSLAddString( papszFullOptions, osTRE );
    3869                 :     }
    3870                 : 
    3871                 : /* -------------------------------------------------------------------- */
    3872                 : /*      Set if we can set IREP.                                         */
    3873                 : /* -------------------------------------------------------------------- */
    3874              38 :     if( CSLFetchNameValue(papszFullOptions,"IREP") == NULL )
    3875                 :     {
    3876              38 :         if ( ((poSrcDS->GetRasterCount() == 3 && bJPEG) ||
    3877                 :               (poSrcDS->GetRasterCount() >= 3 && !bJPEG)) && eType == GDT_Byte &&
    3878                 :              poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_RedBand &&
    3879                 :              poSrcDS->GetRasterBand(2)->GetColorInterpretation() == GCI_GreenBand &&
    3880                 :              poSrcDS->GetRasterBand(3)->GetColorInterpretation() == GCI_BlueBand)
    3881                 :         {
    3882               7 :             if( bJPEG )
    3883                 :                 papszFullOptions = 
    3884               3 :                     CSLSetNameValue( papszFullOptions, "IREP", "YCbCr601" );
    3885                 :             else
    3886                 :                 papszFullOptions = 
    3887               4 :                     CSLSetNameValue( papszFullOptions, "IREP", "RGB" );
    3888                 :         }
    3889              31 :         else if( poSrcDS->GetRasterCount() == 1 && eType == GDT_Byte
    3890                 :                  && poBand1->GetColorTable() != NULL )
    3891                 :         {
    3892                 :             papszFullOptions = 
    3893               1 :                 CSLSetNameValue( papszFullOptions, "IREP", "RGB/LUT" );
    3894                 :             papszFullOptions = 
    3895                 :                 CSLSetNameValue( papszFullOptions, "LUT_SIZE", 
    3896                 :                                  CPLString().Printf(
    3897               1 :                                      "%d", poBand1->GetColorTable()->GetColorEntryCount()) );
    3898                 :         }
    3899              30 :         else if( GDALDataTypeIsComplex(eType) )
    3900                 :             papszFullOptions = 
    3901               4 :                 CSLSetNameValue( papszFullOptions, "IREP", "NODISPLY" );
    3902                 :         
    3903                 :         else
    3904                 :             papszFullOptions = 
    3905              26 :                 CSLSetNameValue( papszFullOptions, "IREP", "MONO" );
    3906                 :     }
    3907                 : 
    3908                 : /* -------------------------------------------------------------------- */
    3909                 : /*      Do we have lat/long georeferencing information?                 */
    3910                 : /* -------------------------------------------------------------------- */
    3911                 :     double adfGeoTransform[6];
    3912              38 :     int    bWriteGeoTransform = FALSE;
    3913              38 :     int    bNorth, nZone = 0;
    3914              38 :     OGRSpatialReference oSRS, oSRS_WGS84;
    3915              38 :     char *pszWKT = (char *) poSrcDS->GetProjectionRef();
    3916                 : 
    3917              38 :     if( pszWKT != NULL && pszWKT[0] != '\0' )
    3918                 :     {
    3919              32 :         oSRS.importFromWkt( &pszWKT );
    3920                 : 
    3921                 :         /* NITF is only WGS84 */
    3922              32 :         oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
    3923              32 :         if ( oSRS.IsSameGeogCS(&oSRS_WGS84) == FALSE)
    3924                 :         {
    3925                 :             CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    3926               9 :                     "NITF only supports WGS84 geographic and UTM projections.\n");
    3927               9 :             if (bStrict)
    3928                 :             {
    3929               0 :                 CSLDestroy(papszFullOptions);
    3930               0 :                 CSLDestroy(papszCgmMD);
    3931               0 :                 CSLDestroy(papszTextMD);
    3932              38 :                 return NULL;
    3933                 :             }
    3934                 :         }
    3935                 : 
    3936              32 :         const char* pszICORDS = CSLFetchNameValue(papszFullOptions, "ICORDS");
    3937                 : 
    3938              32 :         if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0 
    3939                 :             && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
    3940                 :         {
    3941              23 :             if (pszICORDS == NULL)
    3942                 :             {
    3943                 :                 papszFullOptions = 
    3944              23 :                     CSLSetNameValue( papszFullOptions, "ICORDS", "G" );
    3945                 :             }
    3946               0 :             else if (EQUAL(pszICORDS, "G") || EQUAL(pszICORDS, "D"))
    3947                 :             {
    3948                 :                 /* Do nothing */
    3949                 :             }
    3950                 :             else
    3951                 :             {
    3952                 :                 CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    3953                 :                     "Inconsistant ICORDS value with SRS : %s%s.\n", pszICORDS,
    3954               0 :                     (!bStrict) ? ". Setting it to G instead" : "");
    3955               0 :                 if (bStrict)
    3956                 :                 {
    3957               0 :                     CSLDestroy(papszFullOptions);
    3958               0 :                     return NULL;
    3959                 :                 }
    3960                 :                 papszFullOptions = 
    3961               0 :                     CSLSetNameValue( papszFullOptions, "ICORDS", "G" );
    3962                 :             }
    3963              23 :             bWriteGeoTransform = TRUE;
    3964                 :         }
    3965                 : 
    3966               9 :         else if( oSRS.GetUTMZone( &bNorth ) > 0 
    3967                 :             && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
    3968                 :         {
    3969               9 :             if( bNorth )
    3970                 :                 papszFullOptions = 
    3971               9 :                     CSLSetNameValue( papszFullOptions, "ICORDS", "N" );
    3972                 :             else
    3973                 :                 papszFullOptions = 
    3974               0 :                     CSLSetNameValue( papszFullOptions, "ICORDS", "S" );
    3975                 : 
    3976               9 :             nZone = oSRS.GetUTMZone( NULL );
    3977               9 :             bWriteGeoTransform = TRUE;
    3978                 :         }
    3979                 :         else
    3980                 :         {
    3981                 :             CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    3982               0 :                     "NITF only supports WGS84 geographic and UTM projections.\n");
    3983               0 :             if (bStrict)
    3984                 :             {
    3985               0 :                 CSLDestroy(papszFullOptions);
    3986               0 :                 CSLDestroy(papszCgmMD);
    3987               0 :                 CSLDestroy(papszTextMD);
    3988               0 :                 return NULL;
    3989                 :             }
    3990                 :         }
    3991                 :     }
    3992                 : 
    3993                 : /* -------------------------------------------------------------------- */
    3994                 : /*      Create the output file.                                         */
    3995                 : /* -------------------------------------------------------------------- */
    3996              38 :     int nXSize = poSrcDS->GetRasterXSize();
    3997              38 :     int nYSize = poSrcDS->GetRasterYSize();
    3998              38 :     const char *pszPVType = GDALToNITFDataType( eType );
    3999                 : 
    4000              38 :     if( pszPVType == NULL )
    4001                 :     {
    4002               3 :         CSLDestroy(papszFullOptions);
    4003               3 :         CSLDestroy(papszCgmMD);
    4004               3 :         CSLDestroy(papszTextMD);
    4005               3 :         return NULL;
    4006                 :     }
    4007                 : 
    4008              35 :     if (!NITFCreate( pszFilename, nXSize, nYSize, poSrcDS->GetRasterCount(),
    4009                 :                 GDALGetDataTypeSize( eType ), pszPVType, 
    4010                 :                 papszFullOptions ))
    4011                 :     {
    4012               1 :         CSLDestroy( papszFullOptions );
    4013               1 :         CSLDestroy(papszCgmMD);
    4014               1 :         CSLDestroy(papszTextMD);
    4015               1 :         return NULL;
    4016                 :     }
    4017                 : 
    4018              34 :     CSLDestroy( papszFullOptions );
    4019              34 :     papszFullOptions = NULL;
    4020                 : 
    4021                 : /* ==================================================================== */
    4022                 : /*      JPEG2000 case.  We need to write the data through a J2K         */
    4023                 : /*      driver in pixel interleaved form.                               */
    4024                 : /* ==================================================================== */
    4025              34 :     if( bJPEG2000 )
    4026                 :     {
    4027               1 :         NITFFile *psFile = NITFOpen( pszFilename, TRUE );
    4028               1 :         GDALDataset *poJ2KDataset = NULL;
    4029               1 :         GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
    4030               1 :         CPLString osDSName;
    4031                 : 
    4032               1 :         if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
    4033                 :         {
    4034                 :             osDSName.Printf( "J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1,
    4035               0 :                              pszFilename );
    4036                 :         }
    4037                 :         else
    4038                 :         {
    4039                 :             /* Jasper case */
    4040                 :             osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_%d,%s", nImageOffset, -1,
    4041               1 :                              pszFilename );
    4042                 :         }
    4043                 :                              
    4044               1 :         NITFClose( psFile );
    4045                 : 
    4046               1 :         if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
    4047                 :         {
    4048               0 :             char** papszJP2Options = NITFJP2Options(papszOptions);
    4049                 :             poJ2KDataset = 
    4050                 :                 poJ2KDriver->CreateCopy( osDSName, poSrcDS, FALSE,
    4051                 :                                          papszJP2Options,
    4052               0 :                                          pfnProgress, pProgressData );
    4053               0 :             CSLDestroy(papszJP2Options);
    4054                 :         }
    4055                 :         else
    4056                 :         {
    4057                 :             /* Jasper case */
    4058               1 :             const char* apszOptions[] = { "FORMAT=JPC", NULL };
    4059                 :             poJ2KDataset = 
    4060                 :                 poJ2KDriver->CreateCopy( osDSName, poSrcDS, FALSE,
    4061                 :                                          (char **)apszOptions,
    4062               1 :                                          pfnProgress, pProgressData );
    4063                 :         }
    4064               1 :         if( poJ2KDataset == NULL )
    4065                 :         {
    4066               0 :             CSLDestroy(papszCgmMD);
    4067               0 :             CSLDestroy(papszTextMD);
    4068               0 :             return NULL;
    4069                 :         }
    4070                 : 
    4071               1 :         delete poJ2KDataset;
    4072                 : 
    4073                 :         // Now we need to figure out the actual length of the file
    4074                 :         // and correct the image segment size information.
    4075                 :         GIntBig nPixelCount = nXSize * ((GIntBig) nYSize) * 
    4076               1 :             poSrcDS->GetRasterCount();
    4077                 : 
    4078               1 :         NITFPatchImageLength( pszFilename, nImageOffset, nPixelCount, "C8" );
    4079               1 :         NITFWriteCGMSegments( pszFilename, papszCgmMD );
    4080               1 :         NITFWriteTextSegments( pszFilename, papszTextMD );
    4081                 : 
    4082               1 :         GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
    4083               1 :         poDstDS = (NITFDataset *) Open( &oOpenInfo );
    4084                 : 
    4085               1 :         if( poDstDS == NULL )
    4086                 :         {
    4087               0 :             CSLDestroy(papszCgmMD);
    4088               0 :             CSLDestroy(papszTextMD);
    4089               0 :             return NULL;
    4090               0 :         }
    4091                 :     }
    4092                 : 
    4093                 : /* ==================================================================== */
    4094                 : /*      Loop copying bands to an uncompressed file.                     */
    4095                 : /* ==================================================================== */
    4096              33 :     else if( bJPEG )
    4097                 :     {
    4098                 : #ifdef JPEG_SUPPORTED
    4099               4 :         NITFFile *psFile = NITFOpen( pszFilename, TRUE );
    4100               4 :         GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
    4101                 :         int bSuccess;
    4102                 :         
    4103                 :         bSuccess = 
    4104                 :             NITFWriteJPEGImage( poSrcDS, psFile->fp, nImageOffset,
    4105                 :                                 papszOptions,
    4106               4 :                                 pfnProgress, pProgressData );
    4107                 :         
    4108               4 :         if( !bSuccess )
    4109                 :         {
    4110               0 :             NITFClose( psFile );
    4111               0 :             CSLDestroy(papszCgmMD);
    4112               0 :             CSLDestroy(papszTextMD);
    4113               0 :             return NULL;
    4114                 :         }
    4115                 : 
    4116                 :         // Now we need to figure out the actual length of the file
    4117                 :         // and correct the image segment size information.
    4118                 :         GIntBig nPixelCount = nXSize * ((GIntBig) nYSize) * 
    4119               4 :             poSrcDS->GetRasterCount();
    4120                 : 
    4121               4 :         NITFClose( psFile );
    4122                 : 
    4123                 :         NITFPatchImageLength( pszFilename, nImageOffset,
    4124               4 :                               nPixelCount, pszIC );
    4125                 : 
    4126               4 :         NITFWriteCGMSegments( pszFilename, papszCgmMD );
    4127               4 :         NITFWriteTextSegments( pszFilename, papszTextMD );
    4128                 :         
    4129               4 :         GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
    4130               4 :         poDstDS = (NITFDataset *) Open( &oOpenInfo );
    4131                 : 
    4132               4 :         if( poDstDS == NULL )
    4133                 :         {
    4134               0 :             CSLDestroy(papszCgmMD);
    4135               0 :             CSLDestroy(papszTextMD);
    4136               0 :             return NULL;
    4137               0 :         }
    4138                 : #endif /* def JPEG_SUPPORTED */
    4139                 :     }
    4140                 : 
    4141                 : /* ==================================================================== */
    4142                 : /*      Loop copying bands to an uncompressed file.                     */
    4143                 : /* ==================================================================== */
    4144                 :     else
    4145                 :     {
    4146              29 :         NITFWriteCGMSegments( pszFilename, papszCgmMD );
    4147              29 :         NITFWriteTextSegments( pszFilename, papszTextMD );
    4148                 : 
    4149              29 :         GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
    4150              29 :         poDstDS = (NITFDataset *) Open( &oOpenInfo );
    4151              29 :         if( poDstDS == NULL )
    4152                 :         {
    4153               0 :             CSLDestroy(papszCgmMD);
    4154               0 :             CSLDestroy(papszTextMD);
    4155               0 :             return NULL;
    4156                 :         }
    4157                 :         
    4158              29 :         void  *pData = VSIMalloc2(nXSize, (GDALGetDataTypeSize(eType) / 8));
    4159              29 :         if (pData == NULL)
    4160                 :         {
    4161               0 :             delete poDstDS;
    4162               0 :             CSLDestroy(papszCgmMD);
    4163               0 :             CSLDestroy(papszTextMD);
    4164               0 :             return NULL;
    4165                 :         }
    4166                 :         
    4167              29 :         CPLErr eErr = CE_None;
    4168                 : 
    4169              74 :         for( int iBand = 0; eErr == CE_None && iBand < poSrcDS->GetRasterCount(); iBand++ )
    4170                 :         {
    4171              45 :             GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
    4172              45 :             GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
    4173                 : 
    4174                 : /* -------------------------------------------------------------------- */
    4175                 : /*      Do we need to copy a colortable or other metadata?              */
    4176                 : /* -------------------------------------------------------------------- */
    4177                 :             GDALColorTable *poCT;
    4178                 : 
    4179              45 :             poCT = poSrcBand->GetColorTable();
    4180              45 :             if( poCT != NULL )
    4181               1 :                 poDstBand->SetColorTable( poCT );
    4182                 : 
    4183                 : /* -------------------------------------------------------------------- */
    4184                 : /*      Copy image data.                                                */
    4185                 : /* -------------------------------------------------------------------- */
    4186            1087 :             for( int iLine = 0; iLine < nYSize; iLine++ )
    4187                 :             {
    4188                 :                 eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    4189            1042 :                                             pData, nXSize, 1, eType, 0, 0 );
    4190            1042 :                 if( eErr != CE_None )
    4191               0 :                     break;   
    4192                 :                     
    4193                 :                 eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1, 
    4194            1042 :                                             pData, nXSize, 1, eType, 0, 0 );
    4195                 : 
    4196            1042 :                 if( eErr != CE_None )
    4197               0 :                     break;   
    4198                 : 
    4199            1042 :                 if( !pfnProgress( (iBand + (iLine+1) / (double) nYSize)
    4200                 :                                   / (double) poSrcDS->GetRasterCount(), 
    4201                 :                                   NULL, pProgressData ) )
    4202                 :                 {
    4203               0 :                     CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    4204               0 :                     eErr = CE_Failure;
    4205               0 :                     break;
    4206                 :                 }
    4207                 :             }
    4208                 :         }
    4209                 : 
    4210              29 :         CPLFree( pData );
    4211                 :         
    4212              29 :         if ( eErr != CE_None )
    4213                 :         {
    4214               0 :             delete poDstDS;
    4215               0 :             CSLDestroy(papszCgmMD);
    4216               0 :             CSLDestroy(papszTextMD);
    4217               0 :             return NULL;
    4218               0 :         }
    4219                 :     }
    4220                 : 
    4221                 : /* -------------------------------------------------------------------- */
    4222                 : /*      Set the georeferencing.                                         */
    4223                 : /* -------------------------------------------------------------------- */
    4224              34 :     if( bWriteGeoTransform )
    4225                 :     {
    4226              29 :         poDstDS->psImage->nZone = nZone;
    4227              29 :         poDstDS->SetGeoTransform( adfGeoTransform );
    4228                 :     }
    4229                 : 
    4230              34 :     poDstDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    4231                 : 
    4232              34 :     CSLDestroy(papszCgmMD);
    4233              34 :     CSLDestroy(papszTextMD);
    4234                 : 
    4235              34 :     return poDstDS;
    4236                 : }
    4237                 : 
    4238                 : /************************************************************************/
    4239                 : /*                        NITFPatchImageLength()                        */
    4240                 : /*                                                                      */
    4241                 : /*      Fixup various stuff we don't know till we have written the      */
    4242                 : /*      imagery.  In particular the file length, image data length      */
    4243                 : /*      and the compression ratio achieved.                             */
    4244                 : /************************************************************************/
    4245                 : 
    4246                 : static void NITFPatchImageLength( const char *pszFilename,
    4247                 :                                   GUIntBig nImageOffset,
    4248                 :                                   GIntBig nPixelCount,
    4249               5 :                                   const char *pszIC )
    4250                 : 
    4251                 : {
    4252               5 :     FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
    4253               5 :     if( fpVSIL == NULL )
    4254               0 :         return;
    4255                 :     
    4256               5 :     VSIFSeekL( fpVSIL, 0, SEEK_END );
    4257               5 :     GUIntBig nFileLen = VSIFTellL( fpVSIL );
    4258                 : 
    4259                 : /* -------------------------------------------------------------------- */
    4260                 : /*      Update total file length.                                       */
    4261                 : /* -------------------------------------------------------------------- */
    4262               5 :     if (nFileLen >= (GUIntBig)(1e12 - 1))
    4263                 :     {
    4264                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4265                 :                  "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
    4266               0 :                  nFileLen);
    4267               0 :         nFileLen = (GUIntBig)(1e12 - 2);
    4268                 :     }
    4269               5 :     VSIFSeekL( fpVSIL, 342, SEEK_SET );
    4270               5 :     CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
    4271              10 :     VSIFWriteL( (void *) osLen.c_str(), 1, 12, fpVSIL );
    4272                 :     
    4273                 : /* -------------------------------------------------------------------- */
    4274                 : /*      Update the image data length.                                   */
    4275                 : /* -------------------------------------------------------------------- */
    4276               5 :     GUIntBig nImageSize = nFileLen-nImageOffset;
    4277               5 :     if (GUINTBIG_TO_DOUBLE(nImageSize) >= 1e10 - 1)
    4278                 :     {
    4279                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4280                 :                  "Too big image size : " CPL_FRMT_GUIB". Truncating to 9999999998",
    4281               0 :                  nImageSize);
    4282               0 :         nImageSize = (GUIntBig)(1e10 - 2);
    4283                 :     }
    4284               5 :     VSIFSeekL( fpVSIL, 369, SEEK_SET );
    4285               5 :     osLen = CPLString().Printf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "u",nImageSize);
    4286               5 :     VSIFWriteL( (void *) osLen.c_str(), 1, 10, fpVSIL );
    4287                 : 
    4288                 : /* -------------------------------------------------------------------- */
    4289                 : /*      Update COMRAT, the compression rate variable.  It is a bit      */
    4290                 : /*      hard to know right here whether we have an IGEOLO segment,      */
    4291                 : /*      so the COMRAT will either be at offset 778 or 838.              */
    4292                 : /* -------------------------------------------------------------------- */
    4293                 :     char szICBuf[2];
    4294                 :     char achNUM[4]; // buffer for segment size.  3 digits plus null character
    4295               5 :     achNUM[3] = '\0';
    4296                 : 
    4297                 :     // get number of graphic and text segment so we can calculate offset for
    4298                 :     // image IC.
    4299               5 :     int nNumIOffset = 360;
    4300               5 :     VSIFSeekL( fpVSIL, nNumIOffset, SEEK_SET );
    4301               5 :     VSIFReadL( achNUM, 1, 3, fpVSIL );
    4302               5 :     int nIM = atoi(achNUM); // number of image segment
    4303                 : 
    4304               5 :     int nNumSOffset = nNumIOffset + 3 + nIM * 16;
    4305               5 :     VSIFSeekL( fpVSIL,  nNumSOffset, SEEK_SET );
    4306               5 :     VSIFReadL( achNUM, 1, 3, fpVSIL );
    4307               5 :     int nGS = atoi(achNUM); // number of graphic segment
    4308                 : 
    4309               5 :     int nNumTOffset = nNumSOffset + 3 + 10 * nGS + 3;
    4310               5 :     VSIFSeekL( fpVSIL, nNumTOffset, SEEK_SET );
    4311               5 :     VSIFReadL( achNUM, 1, 3, fpVSIL );
    4312               5 :     int nTS = atoi(achNUM); // number of text segment
    4313                 : 
    4314               5 :     int nAdditionalOffset = nGS * 10 + nTS * 9;
    4315                 : 
    4316                 :     // 779-2 is the offset for IC without taking into account of the size
    4317                 :     // changes as the result of additional text and graphics segments.
    4318                 :     // 839-2 is the offset if IGOLO exist.
    4319                 : 
    4320               5 :     VSIFSeekL( fpVSIL, 779 -2 + nAdditionalOffset , SEEK_SET );
    4321               5 :     VSIFReadL( szICBuf, 2, 1, fpVSIL );
    4322               5 :     if( !EQUALN(szICBuf,pszIC,2) )
    4323                 :     {
    4324               4 :         VSIFSeekL( fpVSIL, 839 -2 + nAdditionalOffset, SEEK_SET );
    4325               4 :         VSIFReadL( szICBuf, 2, 1, fpVSIL );
    4326                 :     }
    4327                 :     
    4328                 :     /* The following line works around a "feature" of *BSD libc (at least PC-BSD 7.1) */
    4329                 :     /* that makes the position of the file offset unreliable when executing a */
    4330                 :     /* "seek, read and write" sequence. After the read(), the file offset seen by */
    4331                 :     /* the write() is approximatively the size of a block further... */
    4332               5 :     VSIFSeekL( fpVSIL, VSIFTellL( fpVSIL ), SEEK_SET );
    4333                 :     
    4334               5 :     if( !EQUALN(szICBuf,pszIC,2) )
    4335                 :     {
    4336                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    4337               0 :                   "Unable to locate COMRAT to update in NITF header." );
    4338                 :     }
    4339                 :     else
    4340                 :     {
    4341                 :         char szCOMRAT[5];
    4342                 : 
    4343               5 :         if( EQUAL(pszIC,"C8") ) /* jpeg2000 */
    4344                 :         {
    4345               1 :             double dfRate = (GIntBig)(nFileLen-nImageOffset) * 8 / (double) nPixelCount;
    4346               1 :             dfRate = MAX(0.01,MIN(99.99,dfRate));
    4347                 :         
    4348                 :             // We emit in wxyz format with an implicit decimal place
    4349                 :             // between wx and yz as per spec for lossy compression. 
    4350                 :             // We really should have a special case for lossless compression.
    4351               1 :             sprintf( szCOMRAT, "%04d", (int) (dfRate * 100));
    4352                 :         }
    4353               4 :         else if( EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3") ) /* jpeg */
    4354                 :         {
    4355               4 :             strcpy( szCOMRAT, "00.0" );
    4356                 :         }
    4357                 : 
    4358               5 :         VSIFWriteL( szCOMRAT, 4, 1, fpVSIL );
    4359                 :     }
    4360                 :     
    4361               5 :     VSIFCloseL( fpVSIL );
    4362                 : }
    4363                 : 
    4364                 : /************************************************************************/
    4365                 : /*                       NITFWriteCGMSegments()                        */
    4366                 : /************************************************************************/
    4367             543 : static int NITFWriteCGMSegments( const char *pszFilename, char **papszList)
    4368                 : {
    4369             543 :     char errorMessage[255] = "";
    4370                 : 
    4371                 :     // size of each Cgm header entry (LS (4) + LSSH (6))
    4372             543 :     const int nCgmHdrEntrySz = 10;
    4373                 :     
    4374             543 :     if (papszList == NULL)
    4375             535 :         return TRUE;
    4376                 : 
    4377               8 :     int nNUMS = 0;
    4378                 :     const char *pszNUMS;
    4379               8 :     pszNUMS = CSLFetchNameValue(papszList, "SEGMENT_COUNT");
    4380               8 :     if (pszNUMS != NULL)
    4381                 :     {
    4382               8 :         nNUMS = atoi(pszNUMS);
    4383                 :     }
    4384                 : 
    4385                 :     /* -------------------------------------------------------------------- */
    4386                 :     /*      Open the target file.                                           */
    4387                 :     /* -------------------------------------------------------------------- */
    4388               8 :     FILE *fpVSIL = VSIFOpenL(pszFilename, "r+b");
    4389                 : 
    4390               8 :     if (fpVSIL == NULL)
    4391               0 :         return FALSE;
    4392                 : 
    4393                 :     // Calculates the offset for NUMS so we can update header data
    4394                 :     char achNUMI[4]; // 3 digits plus null character
    4395               8 :     achNUMI[3] = '\0';
    4396                 : 
    4397                 :     // NUMI offset is at a fixed offset 363
    4398               8 :     int nNumIOffset = 360;
    4399               8 :     VSIFSeekL(fpVSIL, nNumIOffset, SEEK_SET );
    4400               8 :     VSIFReadL(achNUMI, 1, 3, fpVSIL);
    4401               8 :     int nIM = atoi(achNUMI);
    4402                 : 
    4403                 :     // 6 for size of LISH and 10 for size of LI
    4404                 :     // NUMS offset is NumI offset plus the size of NumI + size taken up each
    4405                 :     // the header data multiply by the number of data
    4406                 : 
    4407               8 :     int nNumSOffset = nNumIOffset + 3+ nIM * (6 + 10);
    4408                 : 
    4409                 :     /* -------------------------------------------------------------------- */
    4410                 :     /*      Confirm that the NUMS in the file header already matches the    */
    4411                 :     /*      number of graphic segments we want to write                     */
    4412                 :     /* -------------------------------------------------------------------- */
    4413                 :     char achNUMS[4];
    4414                 : 
    4415               8 :     VSIFSeekL( fpVSIL, nNumSOffset, SEEK_SET );
    4416               8 :     VSIFReadL( achNUMS, 1, 3, fpVSIL );
    4417               8 :     achNUMS[3] = '\0';
    4418                 : 
    4419               8 :     if( atoi(achNUMS) != nNUMS )
    4420                 :     {
    4421                 :         CPLError( CE_Failure, CPLE_AppDefined,
    4422                 :                   "It appears an attempt was made to add or update graphic\n"
    4423                 :                   "segments on an NITF file with existing segments.  This\n"
    4424               0 :                   "is not currently supported by the GDAL NITF driver." );
    4425                 : 
    4426               0 :         VSIFCloseL( fpVSIL );
    4427               0 :         return FALSE;
    4428                 :     }
    4429                 : 
    4430                 : 
    4431                 :     // allocate space for graphic header.
    4432                 :     // Size of LS = 4, size of LSSH = 6, and 1 for null character
    4433               8 :     char *pachLS = (char *) CPLCalloc(nNUMS * nCgmHdrEntrySz + 1, 1);
    4434                 : 
    4435                 :     /* -------------------------------------------------------------------- */
    4436                 :     /*  Assume no extended data such as SXSHDL, SXSHD           */
    4437                 :     /* -------------------------------------------------------------------- */
    4438                 : 
    4439                 :     /* ==================================================================== */
    4440                 :     /*      Write the Graphics segments at the end of the file.             */
    4441                 :     /* ==================================================================== */
    4442                 : 
    4443                 :     #define PLACE(location,name,text)  strncpy(location,text,strlen(text))
    4444                 : 
    4445              12 :     for (int i = 0; i < nNUMS; i++)
    4446                 :     {
    4447                 : 
    4448                 :         // Get all the fields for current CGM segment
    4449                 :         const char *pszSlocRow = CSLFetchNameValue(papszList,
    4450               4 :                         CPLString().Printf("SEGMENT_%d_SLOC_ROW", i));
    4451                 :         const char *pszSlocCol = CSLFetchNameValue(papszList,
    4452               8 :                         CPLString().Printf("SEGMENT_%d_SLOC_COL", i));
    4453                 :         const char *pszSdlvl = CSLFetchNameValue(papszList,
    4454               8 :                         CPLString().Printf("SEGMENT_%d_SDLVL", i));
    4455                 :         const char *pszSalvl = CSLFetchNameValue(papszList,
    4456               8 :                         CPLString().Printf("SEGMENT_%d_SALVL", i));
    4457                 :         const char *pszData = CSLFetchNameValue(papszList,
    4458               8 :                         CPLString().Printf("SEGMENT_%d_DATA", i));
    4459                 : 
    4460                 :         // Error checking
    4461               4 :         if (pszSlocRow == NULL)
    4462                 :         {
    4463               0 :             sprintf(errorMessage, "NITF graphic segment writing error: SLOC_ROW for segment %d is not defined",i);
    4464               0 :             break;
    4465                 :         }
    4466               4 :         if (pszSlocCol == NULL)
    4467                 :         {
    4468               0 :             sprintf(errorMessage, "NITF graphic segment writing error: SLOC_COL for segment %d is not defined",i);
    4469               0 :             break;
    4470                 :         }
    4471               4 :         if (pszSdlvl == NULL)
    4472                 :         {
    4473               0 :             sprintf(errorMessage, "NITF graphic segment writing error: SDLVL for segment %d is not defined", i);
    4474               0 :             break;
    4475                 :         }
    4476               4 :         if (pszSalvl == NULL)
    4477                 :         {
    4478               0 :             sprintf(errorMessage, "NITF graphic segment writing error: SALVLfor segment %d is not defined", i);
    4479               0 :             break;
    4480                 :         }
    4481               4 :         if (pszData == NULL)
    4482                 :         {
    4483               0 :             sprintf(errorMessage, "NITF graphic segment writing error: DATA for segment %d is not defined", i);
    4484               0 :             break;
    4485                 :         }
    4486                 : 
    4487               4 :         int nSlocCol = atoi(pszSlocRow);
    4488               4 :         int nSlocRow = atoi(pszSlocCol);
    4489               4 :         int nSdlvl = atoi(pszSdlvl);
    4490               4 :         int nSalvl = atoi(pszSalvl);
    4491                 : 
    4492                 :         // Create a buffer for graphics segment header, 258 is the size of
    4493                 :         // the header that we will be writing.
    4494                 :         char achGSH[258];
    4495                 : 
    4496               4 :         memset(achGSH, ' ', sizeof(achGSH));
    4497                 : 
    4498                 : 
    4499               4 :         PLACE( achGSH+ 0, SY , "SY" );
    4500               4 :         PLACE( achGSH+ 2, SID ,CPLSPrintf("%010d", i) );
    4501               4 :         PLACE( achGSH+ 12, SNAME , "DEFAULT NAME        " );
    4502               4 :         PLACE( achGSH+32, SSCLAS , "U" );
    4503               4 :         PLACE( achGSH+33, SSCLASY , "0" );
    4504               4 :         PLACE( achGSH+199, ENCRYP , "0" );
    4505               4 :         PLACE( achGSH+200, SFMT , "C" );
    4506               4 :         PLACE( achGSH+201, SSTRUCT , "0000000000000" );
    4507               4 :         PLACE( achGSH+214, SDLVL , CPLSPrintf("%03d",nSdlvl)); // size3
    4508               4 :         PLACE( achGSH+217, SALVL , CPLSPrintf("%03d",nSalvl)); // size3
    4509               4 :         PLACE( achGSH+220, SLOC , CPLSPrintf("%05d%05d",nSlocRow,nSlocCol) ); // size 10
    4510               4 :         PLACE( achGSH+230, SBAND1 , "0000000000" );
    4511               4 :         PLACE( achGSH+240, SCOLOR, "C" );
    4512               4 :         PLACE( achGSH+241, SBAND2, "0000000000" );
    4513               4 :         PLACE( achGSH+251, SRES2, "00" );
    4514               4 :         PLACE( achGSH+253, SXSHDL, "00000" );
    4515                 : 
    4516                 :         // Move to the end of the file
    4517               4 :         VSIFSeekL(fpVSIL, 0, SEEK_END );
    4518               4 :         VSIFWriteL(achGSH, 1, sizeof(achGSH), fpVSIL);
    4519                 : 
    4520                 :         /* -------------------------------------- ------------------------------ */
    4521                 :         /*      Prepare and write CGM segment data.                            */
    4522                 :         /* -------------------------------------------------------------------- */
    4523               4 :         int nCGMSize = 0;
    4524                 :         char *pszCgmToWrite = CPLUnescapeString(pszData, &nCGMSize,
    4525               4 :                         CPLES_BackslashQuotable);
    4526                 : 
    4527               4 :         if (nCGMSize > 999998)
    4528                 :         {
    4529                 :             CPLError(CE_Warning, CPLE_NotSupported,
    4530                 :                      "Length of SEGMENT_%d_DATA is %d, which is greater than 999998. Truncating...",
    4531               0 :                      i + 1, nCGMSize);
    4532               0 :             nCGMSize = 999998;
    4533                 :         }
    4534                 : 
    4535               4 :         VSIFWriteL(pszCgmToWrite, 1, nCGMSize, fpVSIL);
    4536                 : 
    4537                 :         /* -------------------------------------------------------------------- */
    4538                 :         /*      Update the subheader and data size info in the file header.     */
    4539                 :         /* -------------------------------------------------------------------- */
    4540               4 :         sprintf( pachLS + nCgmHdrEntrySz * i, "%04d%06d",(int) sizeof(achGSH), nCGMSize );
    4541                 : 
    4542               4 :         CPLFree(pszCgmToWrite);
    4543                 : 
    4544                 :     } // End For
    4545                 : 
    4546                 : 
    4547                 :     /* -------------------------------------------------------------------- */
    4548                 :     /*      Write out the graphic segment info.                             */
    4549                 :     /* -------------------------------------------------------------------- */
    4550                 : 
    4551               8 :     VSIFSeekL(fpVSIL, nNumSOffset + 3, SEEK_SET );
    4552               8 :     VSIFWriteL(pachLS, 1, nNUMS * nCgmHdrEntrySz, fpVSIL);
    4553                 : 
    4554                 :     /* -------------------------------------------------------------------- */
    4555                 :     /*      Update total file length.                                       */
    4556                 :     /* -------------------------------------------------------------------- */
    4557               8 :     VSIFSeekL(fpVSIL, 0, SEEK_END );
    4558               8 :     GUIntBig nFileLen = VSIFTellL(fpVSIL);
    4559                 :     // Offset to file length entry
    4560               8 :     VSIFSeekL(fpVSIL, 342, SEEK_SET );
    4561               8 :     if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12 - 1)
    4562                 :     {
    4563                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4564                 :                         "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
    4565               0 :                         nFileLen);
    4566               0 :         nFileLen = (GUIntBig) (1e12 - 2);
    4567                 :     }
    4568                 :     CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",
    4569               8 :                     nFileLen);
    4570              16 :     VSIFWriteL((void *) osLen.c_str(), 1, 12, fpVSIL);
    4571                 : 
    4572               8 :     VSIFCloseL(fpVSIL);
    4573                 : 
    4574               8 :     CPLFree(pachLS);
    4575                 : 
    4576               8 :     if (strlen(errorMessage) != 0)
    4577                 :     {
    4578               0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", errorMessage);
    4579               8 :         return FALSE;
    4580                 :     }
    4581                 : 
    4582               8 :     return TRUE;
    4583                 : }
    4584                 : 
    4585                 : /************************************************************************/
    4586                 : /*                       NITFWriteTextSegments()                        */
    4587                 : /************************************************************************/
    4588                 : 
    4589                 : static void NITFWriteTextSegments( const char *pszFilename,
    4590             543 :                                    char **papszList )
    4591                 : 
    4592                 : {
    4593                 : /* -------------------------------------------------------------------- */
    4594                 : /*      Count the number of apparent text segments to write.  There     */
    4595                 : /*      is nothing at all to do if there are none to write.             */
    4596                 : /* -------------------------------------------------------------------- */
    4597             543 :     int iOpt, nNUMT = 0;
    4598                 : 
    4599             551 :     for( iOpt = 0; papszList != NULL && papszList[iOpt] != NULL; iOpt++ )
    4600                 :     {
    4601               8 :         if( EQUALN(papszList[iOpt],"DATA_",5) )
    4602               5 :             nNUMT++;
    4603                 :     }
    4604                 : 
    4605             543 :     if( nNUMT == 0 )
    4606             539 :         return;
    4607                 : 
    4608                 : /* -------------------------------------------------------------------- */
    4609                 : /*      Open the target file.                                           */
    4610                 : /* -------------------------------------------------------------------- */
    4611               4 :     FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
    4612                 : 
    4613               4 :     if( fpVSIL == NULL )
    4614               0 :         return;
    4615                 : 
    4616                 :     // Get number of text field.  Since there there could be multiple images
    4617                 :     // or graphic segment, the  offset need to be calculated dynamically.
    4618                 : 
    4619                 :     char achNUMI[4]; // 3 digits plus null character
    4620               4 :     achNUMI[3] = '\0';
    4621                 :     // NUMI offset is at a fixed offset 363
    4622               4 :     int nNumIOffset = 360;
    4623               4 :     VSIFSeekL( fpVSIL, nNumIOffset, SEEK_SET );
    4624               4 :     VSIFReadL( achNUMI, 1, 3, fpVSIL );
    4625               4 :     int nIM = atoi(achNUMI);
    4626                 : 
    4627                 :     char achNUMG[4]; // 3 digits plus null character
    4628               4 :     achNUMG[3] = '\0';
    4629                 : 
    4630                 :     // 3 for size of NUMI.  6 and 10 are the field size for LISH and LI
    4631               4 :     int nNumGOffset = nNumIOffset + 3 + nIM * (6 + 10);
    4632               4 :     VSIFSeekL( fpVSIL, nNumGOffset, SEEK_SET );
    4633               4 :     VSIFReadL( achNUMG, 1, 3, fpVSIL );
    4634               4 :     int nGS = atoi(achNUMG);
    4635                 : 
    4636                 :     // NUMT offset
    4637                 :     // 3 for size of NUMG.  4 and 6 are filed size of LSSH and LS.
    4638                 :     // the last + 3 is for NUMX field, which is not used
    4639               4 :     int nNumTOffset = nNumGOffset + 3 + nGS * (4 + 6) + 3;
    4640                 : 
    4641                 :     /* -------------------------------------------------------------------- */
    4642                 :     /*      Confirm that the NUMT in the file header already matches the    */
    4643                 :     /*      number of text segements we want to write, and that the         */
    4644                 :     /*      segment header/data size info is blank.                         */
    4645                 :     /* -------------------------------------------------------------------- */
    4646                 :     char achNUMT[4];
    4647               4 :     char *pachLT = (char *) CPLCalloc(nNUMT * 9 + 1, 1);
    4648                 : 
    4649               4 :     VSIFSeekL( fpVSIL, nNumTOffset, SEEK_SET );
    4650               4 :     VSIFReadL( achNUMT, 1, 3, fpVSIL );
    4651               4 :     achNUMT[3] = '\0';
    4652                 : 
    4653               4 :     VSIFReadL( pachLT, 1, nNUMT * 9, fpVSIL );
    4654                 : 
    4655               4 :     if( atoi(achNUMT) != nNUMT )
    4656                 :     {
    4657                 :         CPLError( CE_Failure, CPLE_AppDefined,
    4658                 :                   "It appears an attempt was made to add or update text\n"
    4659                 :                   "segments on an NITF file with existing segments.  This\n"
    4660               0 :                   "is not currently supported by the GDAL NITF driver." );
    4661                 : 
    4662               0 :         VSIFCloseL( fpVSIL );
    4663               0 :         CPLFree( pachLT );
    4664               0 :         return;
    4665                 :     }
    4666                 : 
    4667               4 :     if( !EQUALN(pachLT,"         ",9) )
    4668                 :     {
    4669               0 :         CPLFree( pachLT );
    4670                 :         // presumably the text segments are already written, do nothing.
    4671               0 :         VSIFCloseL( fpVSIL );
    4672               0 :         return;
    4673                 :     }
    4674                 : 
    4675                 : /* -------------------------------------------------------------------- */
    4676                 : /*      At this point we likely ought to confirm NUMDES, NUMRES,        */
    4677                 : /*      UDHDL and XHDL are zero.  Consider adding later...              */
    4678                 : /* -------------------------------------------------------------------- */
    4679                 : 
    4680                 : /* ==================================================================== */
    4681                 : /*      Write the text segments at the end of the file.                 */
    4682                 : /* ==================================================================== */
    4683                 : #define PLACE(location,name,text)  strncpy(location,text,strlen(text))
    4684               4 :     int iTextSeg = 0;
    4685                 :     
    4686              12 :     for( iOpt = 0; papszList != NULL && papszList[iOpt] != NULL; iOpt++ )
    4687                 :     {
    4688                 :         const char *pszTextToWrite;
    4689                 : 
    4690               8 :         if( !EQUALN(papszList[iOpt],"DATA_",5) )
    4691               3 :             continue;
    4692                 : 
    4693               5 :         const char *pszHeaderBuffer = NULL;
    4694                 : 
    4695                 : /* -------------------------------------------------------------------- */
    4696                 : /*      Locate corresponding header data in the buffer                  */
    4697                 : /* -------------------------------------------------------------------- */
    4698                 : 
    4699              11 :         for( int iOpt2 = 0; papszList != NULL && papszList[iOpt2] != NULL; iOpt2++ ) {
    4700               9 :             if( !EQUALN(papszList[iOpt2],"HEADER_",7) )
    4701               6 :                 continue;
    4702                 : 
    4703                 :             char *pszHeaderKey, *pszDataKey;
    4704               3 :             CPLParseNameValue( papszList[iOpt2], &pszHeaderKey );
    4705               3 :             CPLParseNameValue( papszList[iOpt], &pszDataKey );
    4706                 : 
    4707                 :             char *pszHeaderId, *pszDataId; //point to header and data number
    4708               3 :             pszHeaderId = pszHeaderKey + 7;
    4709               3 :             pszDataId = pszDataKey + 5;
    4710                 : 
    4711               3 :             bool bIsSameId = strcmp(pszHeaderId, pszDataId) == 0;
    4712               3 :             CPLFree(pszHeaderKey);
    4713               3 :             CPLFree(pszDataKey);
    4714                 : 
    4715                 :             // if ID matches, read the header information and exit the loop
    4716               3 :             if (bIsSameId) {
    4717               3 :               pszHeaderBuffer = CPLParseNameValue( papszList[iOpt2], NULL);
    4718               3 :               break;
    4719                 :             }
    4720                 :         }
    4721                 : 
    4722                 : /* -------------------------------------------------------------------- */
    4723                 : /*      Prepare and write text header.                                  */
    4724                 : /* -------------------------------------------------------------------- */
    4725                 :         char achTSH[282];
    4726               5 :         memset( achTSH, ' ', sizeof(achTSH) );
    4727               5 :         VSIFSeekL( fpVSIL, 0, SEEK_END );
    4728                 : 
    4729               5 :         if (pszHeaderBuffer!= NULL) {
    4730               3 :             memcpy( achTSH, pszHeaderBuffer, MIN(strlen(pszHeaderBuffer), sizeof(achTSH)) );
    4731                 : 
    4732                 :             // Take care NITF2.0 date format changes
    4733               3 :             char chTimeZone = achTSH[20];
    4734                 : 
    4735                 :             // Check for Zulu time zone character.  IpachLTf that exist, then
    4736                 :             // it's NITF2.0 format.
    4737               3 :             if (chTimeZone == 'Z') {
    4738               0 :                 char *achOrigDate=achTSH+12;  // original date string
    4739                 : 
    4740                 :                 // The date value taken from default NITF file date
    4741               0 :                 char achNewDate[]="20021216151629";
    4742                 :                 char achYear[3];
    4743                 :                 int nYear;
    4744                 : 
    4745                 :                 // Offset to the year
    4746               0 :                 strncpy(achYear,achOrigDate+12, 2);
    4747               0 :                 achYear[2] = '\0';
    4748               0 :                 nYear = atoi(achYear);
    4749                 : 
    4750                 :                 // Set century.
    4751                 :                 // Since NITF2.0 does not track the century, we are going to
    4752                 :                 // assume any year number greater then 94 (the year NITF2.0
    4753                 :                 // spec published), will be 1900s, otherwise, it's 2000s.
    4754               0 :                 if (nYear > 94) strncpy(achNewDate,"19",2);
    4755               0 :                 else strncpy(achNewDate,"20",2);
    4756                 : 
    4757               0 :                 strncpy(achNewDate+6, achOrigDate,8); // copy cover DDhhmmss
    4758               0 :                 strncpy(achNewDate+2, achOrigDate+12,2); // copy over years
    4759                 : 
    4760                 :                 // Perform month conversion
    4761               0 :                 char *pszOrigMonth = achOrigDate+9;
    4762               0 :                 char *pszNewMonth = achNewDate+4;
    4763                 : 
    4764               0 :                 if (strncmp(pszOrigMonth,"JAN",3) == 0) strncpy(pszNewMonth,"01",2);
    4765               0 :                 else if (strncmp(pszOrigMonth,"FEB",3) == 0) strncpy(pszNewMonth,"02",2);
    4766               0 :                 else if (strncmp(pszOrigMonth,"MAR",3) == 0) strncpy(pszNewMonth,"03",2);
    4767               0 :                 else if (strncmp(pszOrigMonth,"APR",3) == 0) strncpy(pszNewMonth,"04",2);
    4768               0 :                 else if (strncmp(pszOrigMonth,"MAY",3) == 0) strncpy(pszNewMonth,"05",2);
    4769               0 :                 else if (strncmp(pszOrigMonth,"JUN",3) == 0) strncpy(pszNewMonth,"07",2);
    4770               0 :                 else if (strncmp(pszOrigMonth,"AUG",3) == 0) strncpy(pszNewMonth,"08",2);
    4771               0 :                 else if (strncmp(pszOrigMonth,"SEP",3) == 0) strncpy(pszNewMonth,"09",2);
    4772               0 :                 else if (strncmp(pszOrigMonth,"OCT",3) == 0) strncpy(pszNewMonth,"10",2);
    4773               0 :                 else if (strncmp(pszOrigMonth,"NOV",3) == 0) strncpy(pszNewMonth,"11",2);
    4774               0 :                 else if (strncmp(pszOrigMonth,"DEC",3) == 0) strncpy(pszNewMonth,"12",2);
    4775                 : 
    4776               0 :                 PLACE( achTSH+ 12, TXTDT         , achNewDate             );
    4777                 : 
    4778                 :             }
    4779                 :         } else { // Use default value if header information is not found
    4780               2 :             PLACE( achTSH+  0, TE            , "TE"                          );
    4781               2 :             PLACE( achTSH+  9, TXTALVL       , "000"                         );
    4782               2 :             PLACE( achTSH+ 12, TXTDT         , "20021216151629"              );
    4783               2 :             PLACE( achTSH+106, TSCLAS        , "U"                           );
    4784               2 :             PLACE( achTSH+273, ENCRYP        , "0"                           );
    4785               2 :             PLACE( achTSH+274, TXTFMT        , "STA"                         );
    4786               2 :             PLACE( achTSH+277, TXSHDL        , "00000"                       );
    4787                 :         }
    4788                 : 
    4789                 : 
    4790               5 :         VSIFWriteL( achTSH, 1, sizeof(achTSH), fpVSIL );
    4791                 : 
    4792                 : /* -------------------------------------------------------------------- */
    4793                 : /*      Prepare and write text segment data.                            */
    4794                 : /* -------------------------------------------------------------------- */
    4795               5 :         pszTextToWrite = CPLParseNameValue( papszList[iOpt], NULL );
    4796                 :         
    4797               5 :         int nTextLength = (int) strlen(pszTextToWrite);
    4798               5 :         if (nTextLength > 99998)
    4799                 :         {
    4800                 :             CPLError(CE_Warning, CPLE_NotSupported,
    4801                 :                      "Length of DATA_%d is %d, which is greater than 99998. Truncating...",
    4802               0 :                      iTextSeg + 1, nTextLength);
    4803               0 :             nTextLength = 99998;
    4804                 :         }
    4805                 : 
    4806               5 :         VSIFWriteL( pszTextToWrite, 1, nTextLength, fpVSIL );
    4807                 :         
    4808                 : /* -------------------------------------------------------------------- */
    4809                 : /*      Update the subheader and data size info in the file header.     */
    4810                 : /* -------------------------------------------------------------------- */
    4811                 :         sprintf( pachLT + 9*iTextSeg+0, "%04d%05d",
    4812               5 :                  (int) sizeof(achTSH), nTextLength );
    4813                 : 
    4814               5 :         iTextSeg++;
    4815                 :     }
    4816                 : 
    4817                 : /* -------------------------------------------------------------------- */
    4818                 : /*      Write out the text segment info.                                */
    4819                 : /* -------------------------------------------------------------------- */
    4820                 : 
    4821               4 :     VSIFSeekL( fpVSIL, nNumTOffset + 3, SEEK_SET );
    4822               4 :     VSIFWriteL( pachLT, 1, nNUMT * 9, fpVSIL );
    4823                 : 
    4824                 : /* -------------------------------------------------------------------- */
    4825                 : /*      Update total file length.                                       */
    4826                 : /* -------------------------------------------------------------------- */
    4827               4 :     VSIFSeekL( fpVSIL, 0, SEEK_END );
    4828               4 :     GUIntBig nFileLen = VSIFTellL( fpVSIL );
    4829                 : 
    4830               4 :     VSIFSeekL( fpVSIL, 342, SEEK_SET );
    4831               4 :     if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12 - 1)
    4832                 :     {
    4833                 :         CPLError(CE_Failure, CPLE_AppDefined,
    4834                 :                  "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
    4835               0 :                  nFileLen);
    4836               0 :         nFileLen = (GUIntBig)(1e12 - 2);
    4837                 :     }
    4838               4 :     CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
    4839               8 :     VSIFWriteL( (void *) osLen.c_str(), 1, 12, fpVSIL );
    4840                 :     
    4841               4 :     VSIFCloseL( fpVSIL );
    4842               4 :     CPLFree( pachLT );
    4843                 : }
    4844                 :         
    4845                 : /************************************************************************/
    4846                 : /*                         NITFWriteJPEGImage()                         */
    4847                 : /************************************************************************/
    4848                 : 
    4849                 : #ifdef JPEG_SUPPORTED
    4850                 : 
    4851                 : int 
    4852                 : NITFWriteJPEGBlock( GDALDataset *poSrcDS, FILE *fp,
    4853                 :                     int nBlockXOff, int nBlockYOff,
    4854                 :                     int nBlockXSize, int nBlockYSize,
    4855                 :                     int bProgressive, int nQuality,
    4856                 :                     const GByte* pabyAPP6, int nRestartInterval,
    4857                 :                     GDALProgressFunc pfnProgress, void * pProgressData );
    4858                 : 
    4859                 : static int 
    4860                 : NITFWriteJPEGImage( GDALDataset *poSrcDS, FILE *fp, vsi_l_offset nStartOffset, 
    4861                 :                     char **papszOptions,
    4862               4 :                     GDALProgressFunc pfnProgress, void * pProgressData )
    4863                 : {
    4864               4 :     int  nBands = poSrcDS->GetRasterCount();
    4865               4 :     int  nXSize = poSrcDS->GetRasterXSize();
    4866               4 :     int  nYSize = poSrcDS->GetRasterYSize();
    4867               4 :     int  nQuality = 75;
    4868               4 :     int  bProgressive = FALSE;
    4869               4 :     int  nRestartInterval = -1;
    4870                 : 
    4871               4 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
    4872               0 :         return FALSE;
    4873                 : 
    4874                 : /* -------------------------------------------------------------------- */
    4875                 : /*      Some some rudimentary checks                                    */
    4876                 : /* -------------------------------------------------------------------- */
    4877               4 :     if( nBands != 1 && nBands != 3 )
    4878                 :     {
    4879                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    4880                 :                   "JPEG driver doesn't support %d bands.  Must be 1 (grey) "
    4881               0 :                   "or 3 (RGB) bands.\n", nBands );
    4882                 : 
    4883               0 :         return FALSE;
    4884                 :     }
    4885                 : 
    4886               4 :     GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
    4887                 : 
    4888                 : #if defined(JPEG_LIB_MK1) || defined(JPEG_DUAL_MODE_8_12)
    4889               4 :     if( eDT != GDT_Byte && eDT != GDT_UInt16 )
    4890                 :     {
    4891                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    4892                 :                   "JPEG driver doesn't support data type %s. "
    4893                 :                   "Only eight and twelve bit bands supported (Mk1 libjpeg).\n",
    4894                 :                   GDALGetDataTypeName( 
    4895               0 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
    4896                 : 
    4897               0 :         return FALSE;
    4898                 :     }
    4899                 : 
    4900               5 :     if( eDT == GDT_UInt16 || eDT == GDT_Int16 )
    4901               1 :         eDT = GDT_UInt16;
    4902                 :     else
    4903               3 :         eDT = GDT_Byte;
    4904                 : 
    4905                 : #else
    4906                 :     if( eDT != GDT_Byte )
    4907                 :     {
    4908                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    4909                 :                   "JPEG driver doesn't support data type %s. "
    4910                 :                   "Only eight bit byte bands supported.\n", 
    4911                 :                   GDALGetDataTypeName( 
    4912                 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
    4913                 : 
    4914                 :         return FALSE;
    4915                 :     }
    4916                 :     
    4917                 :     eDT = GDT_Byte; // force to 8bit. 
    4918                 : #endif
    4919                 : 
    4920                 : /* -------------------------------------------------------------------- */
    4921                 : /*      What options has the user selected?                             */
    4922                 : /* -------------------------------------------------------------------- */
    4923               4 :     if( CSLFetchNameValue(papszOptions,"QUALITY") != NULL )
    4924                 :     {
    4925               2 :         nQuality = atoi(CSLFetchNameValue(papszOptions,"QUALITY"));
    4926               2 :         if( nQuality < 10 || nQuality > 100 )
    4927                 :         {
    4928                 :             CPLError( CE_Failure, CPLE_IllegalArg,
    4929                 :                       "QUALITY=%s is not a legal value in the range 10-100.",
    4930               0 :                       CSLFetchNameValue(papszOptions,"QUALITY") );
    4931               0 :             return FALSE;
    4932                 :         }
    4933                 :     }
    4934                 : 
    4935               4 :     if( CSLFetchNameValue(papszOptions,"RESTART_INTERVAL") != NULL )
    4936                 :     {
    4937               0 :         nRestartInterval = atoi(CSLFetchNameValue(papszOptions,"RESTART_INTERVAL"));
    4938                 :     }
    4939                 : 
    4940               4 :     bProgressive = CSLFetchBoolean( papszOptions, "PROGRESSIVE", FALSE );
    4941                 : 
    4942                 : /* -------------------------------------------------------------------- */
    4943                 : /*      Compute blocking factors                                        */
    4944                 : /* -------------------------------------------------------------------- */
    4945               4 :     int nNPPBH = nXSize;
    4946               4 :     int nNPPBV = nYSize;
    4947                 : 
    4948               4 :     if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
    4949               2 :         nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
    4950                 : 
    4951               4 :     if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
    4952               0 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
    4953                 : 
    4954               4 :     if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
    4955               0 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
    4956                 :     
    4957               4 :     if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
    4958               0 :         nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
    4959                 :     
    4960               4 :     if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
    4961               0 :         nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
    4962                 :     
    4963               4 :     if( nNPPBH <= 0 || nNPPBV <= 0 ||
    4964                 :         nNPPBH > 9999 || nNPPBV > 9999  )
    4965               0 :         nNPPBH = nNPPBV = 256;
    4966                 : 
    4967               4 :     int nNBPR = (nXSize + nNPPBH - 1) / nNPPBH;
    4968               4 :     int nNBPC = (nYSize + nNPPBV - 1) / nNPPBV;
    4969                 : 
    4970                 : /* -------------------------------------------------------------------- */
    4971                 : /*  Creates APP6 NITF application segment (required by MIL-STD-188-198) */
    4972                 : /*  see #3345                                                           */
    4973                 : /* -------------------------------------------------------------------- */
    4974                 :     GByte abyAPP6[23];
    4975                 :     GUInt16 nUInt16;
    4976               4 :     int nOffset = 0;
    4977                 : 
    4978               4 :     memcpy(abyAPP6, "NITF", 4);
    4979               4 :     abyAPP6[4] = 0;
    4980               4 :     nOffset += 5;
    4981                 : 
    4982                 :     /* Version : 2.0 */
    4983               4 :     nUInt16 = 0x0200;
    4984               4 :     CPL_MSBPTR16(&nUInt16);
    4985               4 :     memcpy(abyAPP6 + nOffset, &nUInt16, sizeof(nUInt16));
    4986               4 :     nOffset += sizeof(nUInt16);
    4987                 : 
    4988                 :     /* IMODE */
    4989               4 :     abyAPP6[nOffset] = (nBands == 1) ? 'B' : 'P';
    4990               4 :     nOffset ++;
    4991                 : 
    4992                 :     /* Number of image blocks per row */
    4993               4 :     nUInt16 = nNBPR;
    4994               4 :     CPL_MSBPTR16(&nUInt16);
    4995               4 :     memcpy(abyAPP6 + nOffset, &nUInt16, sizeof(nUInt16));
    4996               4 :     nOffset += sizeof(nUInt16);
    4997                 : 
    4998                 :     /* Number of image blocks per column */
    4999               4 :     nUInt16 = nNBPC;
    5000               4 :     CPL_MSBPTR16(&nUInt16);
    5001               4 :     memcpy(abyAPP6 + nOffset, &nUInt16, sizeof(nUInt16));
    5002               4 :     nOffset += sizeof(nUInt16);
    5003                 : 
    5004                 :     /* Image color */
    5005               4 :     abyAPP6[nOffset] = (nBands == 1) ? 0 : 1;
    5006               4 :     nOffset ++;
    5007                 : 
    5008                 :     /* Original sample precision */
    5009               4 :     abyAPP6[nOffset] = (eDT == GDT_UInt16) ? 12 : 8;
    5010               4 :     nOffset ++;
    5011                 : 
    5012                 :     /* Image class */
    5013               4 :     abyAPP6[nOffset] = 0;
    5014               4 :     nOffset ++;
    5015                 : 
    5016                 :     /* JPEG coding process */
    5017               4 :     abyAPP6[nOffset] = (eDT == GDT_UInt16) ? 4 : 1;
    5018               4 :     nOffset ++;
    5019                 : 
    5020                 :     /* Quality */
    5021               4 :     abyAPP6[nOffset] = 0;
    5022               4 :     nOffset ++;
    5023                 : 
    5024                 :     /* Stream color */
    5025               4 :     abyAPP6[nOffset] = (nBands == 1) ? 0 /* Monochrome */ : 2 /* YCbCr*/ ;
    5026               4 :     nOffset ++;
    5027                 : 
    5028                 :     /* Stream bits */
    5029               4 :     abyAPP6[nOffset] = (eDT == GDT_UInt16) ? 12 : 8;
    5030               4 :     nOffset ++;
    5031                 : 
    5032                 :     /* Horizontal filtering */
    5033               4 :     abyAPP6[nOffset] = 1;
    5034               4 :     nOffset ++;
    5035                 : 
    5036                 :     /* Vertical filtering */
    5037               4 :     abyAPP6[nOffset] = 1;
    5038               4 :     nOffset ++;
    5039                 : 
    5040                 :     /* Reserved */
    5041               4 :     abyAPP6[nOffset] = 0;
    5042               4 :     nOffset ++;
    5043               4 :     abyAPP6[nOffset] = 0;
    5044               4 :     nOffset ++;
    5045                 : 
    5046               4 :     CPLAssert(nOffset == sizeof(abyAPP6));
    5047                 : 
    5048                 : /* -------------------------------------------------------------------- */
    5049                 : /*      Prepare block map if necessary                                  */
    5050                 : /* -------------------------------------------------------------------- */
    5051                 : 
    5052               4 :     VSIFSeekL( fp, nStartOffset, SEEK_SET );
    5053                 : 
    5054               4 :     const char* pszIC = CSLFetchNameValue( papszOptions, "IC" );
    5055               4 :     GUInt32  nIMDATOFF = 0;
    5056               4 :     if (EQUAL(pszIC, "M3"))
    5057                 :     {
    5058                 :         GUInt32  nIMDATOFF_MSB;
    5059                 :         GUInt16  nBMRLNTH, nTMRLNTH, nTPXCDLNTH;
    5060                 : 
    5061                 :         /* Prepare the block map */
    5062                 : #define BLOCKMAP_HEADER_SIZE    (4 + 2 + 2 + 2)
    5063               1 :         nIMDATOFF_MSB = nIMDATOFF = BLOCKMAP_HEADER_SIZE + nNBPC * nNBPR * 4;
    5064               1 :         nBMRLNTH = 4;
    5065               1 :         nTMRLNTH = 0;
    5066               1 :         nTPXCDLNTH = 0;
    5067                 : 
    5068               1 :         CPL_MSBPTR32( &nIMDATOFF_MSB );
    5069               1 :         CPL_MSBPTR16( &nBMRLNTH );
    5070               1 :         CPL_MSBPTR16( &nTMRLNTH );
    5071               1 :         CPL_MSBPTR16( &nTPXCDLNTH );
    5072                 : 
    5073               1 :         VSIFWriteL( &nIMDATOFF_MSB, 1, 4, fp );
    5074               1 :         VSIFWriteL( &nBMRLNTH, 1, 2, fp );
    5075               1 :         VSIFWriteL( &nTMRLNTH, 1, 2, fp );
    5076               1 :         VSIFWriteL( &nTPXCDLNTH, 1, 2, fp );
    5077                 : 
    5078                 :         /* Reserve space for the table itself */
    5079               1 :         VSIFSeekL( fp, nNBPC * nNBPR * 4, SEEK_CUR );
    5080                 :     }
    5081                 : 
    5082                 : /* -------------------------------------------------------------------- */
    5083                 : /*      Copy each block                                                 */
    5084                 : /* -------------------------------------------------------------------- */
    5085                 :     int nBlockXOff, nBlockYOff;
    5086              10 :     for(nBlockYOff=0;nBlockYOff<nNBPC;nBlockYOff++)
    5087                 :     {
    5088              16 :         for(nBlockXOff=0;nBlockXOff<nNBPR;nBlockXOff++)
    5089                 :         {
    5090                 :             /*CPLDebug("NITF", "nBlockXOff=%d/%d, nBlockYOff=%d/%d",
    5091                 :                      nBlockXOff, nNBPR, nBlockYOff, nNBPC);*/
    5092              10 :             if (EQUAL(pszIC, "M3"))
    5093                 :             {
    5094                 :                 /* Write block offset for current block */
    5095                 : 
    5096               4 :                 GUIntBig nCurPos = VSIFTellL(fp);
    5097               4 :                 VSIFSeekL( fp, nStartOffset + BLOCKMAP_HEADER_SIZE + 4 * (nBlockYOff * nNBPR + nBlockXOff), SEEK_SET );
    5098               4 :                 GUIntBig nBlockOffset = nCurPos - nStartOffset - nIMDATOFF;
    5099               4 :                 GUInt32 nBlockOffset32 = (GUInt32)nBlockOffset;
    5100               4 :                 if (nBlockOffset == (GUIntBig)nBlockOffset32)
    5101                 :                 {
    5102               4 :                     CPL_MSBPTR32( &nBlockOffset32 );
    5103               4 :                     VSIFWriteL( &nBlockOffset32, 1, 4, fp );
    5104                 :                 }
    5105                 :                 else
    5106                 :                 {
    5107                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    5108                 :                             "Offset for block (%d, %d) = " CPL_FRMT_GUIB ". Cannot fit into 32 bits...",
    5109               0 :                             nBlockXOff, nBlockYOff, nBlockOffset);
    5110                 : 
    5111               0 :                     nBlockOffset32 = 0xffffffff;
    5112                 :                     int i;
    5113               0 :                     for(i=nBlockYOff * nNBPR + nBlockXOff; i < nNBPC * nNBPR; i++)
    5114                 :                     {
    5115               0 :                         VSIFWriteL( &nBlockOffset32, 1, 4, fp );
    5116                 :                     }
    5117               0 :                     return FALSE;
    5118                 :                 }
    5119               4 :                 VSIFSeekL( fp, nCurPos, SEEK_SET );
    5120                 :             }
    5121                 : 
    5122              10 :             if (!NITFWriteJPEGBlock(poSrcDS, fp,
    5123                 :                                     nBlockXOff, nBlockYOff,
    5124                 :                                     nNPPBH, nNPPBV,
    5125                 :                                     bProgressive, nQuality,
    5126                 :                                     (nBlockXOff == 0 && nBlockYOff == 0) ? abyAPP6 : NULL,
    5127                 :                                     nRestartInterval,
    5128                 :                                     pfnProgress, pProgressData))
    5129                 :             {
    5130               0 :                 return FALSE;
    5131                 :             }
    5132                 :         }
    5133                 :     }
    5134               4 :     return TRUE;
    5135                 : }
    5136                 : 
    5137                 : #endif /* def JPEG_SUPPORTED */
    5138                 : 
    5139                 : /************************************************************************/
    5140                 : /*                          GDALRegister_NITF()                         */
    5141                 : /************************************************************************/
    5142                 : 
    5143                 : typedef struct
    5144                 : {
    5145                 :     int         nMaxLen;
    5146                 :     const char* pszName;
    5147                 :     const char* pszDescription;
    5148                 : } NITFFieldDescription;
    5149                 : 
    5150                 : /* Keep in sync with NITFCreate */
    5151                 : static const NITFFieldDescription asFieldDescription [] =
    5152                 : {
    5153                 :     { 2, "CLEVEL", "Complexity level" } ,
    5154                 :     { 10, "OSTAID", "Originating Station ID" } ,
    5155                 :     { 14, "FDT", "File Date and Time" } ,
    5156                 :     { 80, "FTITLE", "File Title" } ,
    5157                 :     { 1, "FSCLAS", "File Security Classification" } ,
    5158                 :     { 2, "FSCLSY", "File Classification Security System" } ,
    5159                 :     { 11, "FSCODE", "File Codewords" } ,
    5160                 :     { 2, "FSCTLH", "File Control and Handling" } ,
    5161                 :     { 20, "FSREL", "File Releasing Instructions" } ,
    5162                 :     { 2, "FSDCTP", "File Declassification Type" } ,
    5163                 :     { 8, "FSDCDT", "File Declassification Date" } ,
    5164                 :     { 4, "FSDCXM", "File Declassification Exemption" } ,
    5165                 :     { 1, "FSDG", "File Downgrade" } ,
    5166                 :     { 8, "FSDGDT", "File Downgrade Date" } ,
    5167                 :     { 43, "FSCLTX", "File Classification Text" } ,
    5168                 :     { 1, "FSCATP", "File Classification Authority Type" } ,
    5169                 :     { 40, "FSCAUT", "File Classification Authority" } ,
    5170                 :     { 1, "FSCRSN", "File Classification Reason" } ,
    5171                 :     { 8, "FSSRDT", "File Security Source Date" } ,
    5172                 :     { 15, "FSCTLN", "File Security Control Number" } ,
    5173                 :     { 5, "FSCOP", "File Copy Number" } ,
    5174                 :     { 5, "FSCPYS", "File Number of Copies" } ,
    5175                 :     { 24, "ONAME", "Originator Name" } ,
    5176                 :     { 18, "OPHONE", "Originator Phone Number" } ,
    5177                 :     { 10, "IID1", "Image Identifier 1" } ,
    5178                 :     { 14, "IDATIM", "Image Date and Time" } ,
    5179                 :     { 17, "TGTID", "Target Identifier" } ,
    5180                 :     { 80, "IID2", "Image Identifier 2" } ,
    5181                 :     {  1, "ISCLAS", "Image Security Classification" } ,
    5182                 :     {  2, "ISCLSY", "Image Classification Security System" } ,
    5183                 :     { 11, "ISCODE", "Image Codewords" } ,
    5184                 :     {  2, "ISCTLH", "Image Control and Handling" } ,
    5185                 :     { 20, "ISREL", "Image Releasing Instructions" } ,
    5186                 :     {  2, "ISDCTP", "Image Declassification Type" } ,
    5187                 :     {  8, "ISDCDT", "Image Declassification Date" } ,
    5188                 :     {  4, "ISDCXM", "Image Declassification Exemption" } ,
    5189                 :     {  1, "ISDG", "Image Downgrade" } ,
    5190                 :     {  8, "ISDGDT", "Image Downgrade Date" } ,
    5191                 :     { 43, "ISCLTX", "Image Classification Text" } ,
    5192                 :     {  1, "ISCATP", "Image Classification Authority Type" } ,
    5193                 :     { 40, "ISCAUT", "Image Classification Authority" } ,
    5194                 :     {  1, "ISCRSN", "Image Classification Reason" } ,
    5195                 :     {  8, "ISSRDT", "Image Security Source Date" } ,
    5196                 :     { 15, "ISCTLN", "Image Security Control Number" } ,
    5197                 :     { 42, "ISORCE", "Image Source" } ,
    5198                 :     {  8, "ICAT", "Image Category" } ,
    5199                 :     {  2, "ABPP", "Actual Bits-Per-Pixel Per Band" } ,
    5200                 :     {  1, "PJUST", "Pixel Justification" } ,
    5201                 :     {780, "ICOM", "Image Comments (up to 9x80 characters)" } ,
    5202                 : };
    5203                 : 
    5204                 : /* Keep in sync with NITFWriteBLOCKA */
    5205                 : static const char *apszFieldsBLOCKA[] = { 
    5206                 :         "BLOCK_INSTANCE", "0", "2",
    5207                 :         "N_GRAY",         "2", "5",
    5208                 :         "L_LINES",        "7", "5",
    5209                 :         "LAYOVER_ANGLE",  "12", "3",
    5210                 :         "SHADOW_ANGLE",   "15", "3",
    5211                 :         "BLANKS",         "18", "16",
    5212                 :         "FRLC_LOC",       "34", "21",
    5213                 :         "LRLC_LOC",       "55", "21",
    5214                 :         "LRFC_LOC",       "76", "21",
    5215                 :         "FRFC_LOC",       "97", "21",
    5216                 :         NULL,             NULL, NULL };
    5217                 : 
    5218             409 : void GDALRegister_NITF()
    5219                 : 
    5220                 : {
    5221                 :     GDALDriver  *poDriver;
    5222                 : 
    5223             409 :     if( GDALGetDriverByName( "NITF" ) == NULL )
    5224                 :     {
    5225                 :         unsigned int i;
    5226             392 :         CPLString osCreationOptions;
    5227                 : 
    5228                 :         osCreationOptions =
    5229                 : "<CreationOptionList>"
    5230                 : "   <Option name='IC' type='string-select' default='NC' description='Compression mode. NC=no compression. "
    5231                 : #ifdef JPEG_SUPPORTED
    5232                 :                 "C3/M3=JPEG compression. "
    5233                 : #endif
    5234                 :                 "C8=JP2 compression through the JP2ECW driver"
    5235                 :                 "'>"
    5236                 : "       <Value>NC</Value>"
    5237                 : #ifdef JPEG_SUPPORTED
    5238                 : "       <Value>C3</Value>"
    5239                 : "       <Value>M3</Value>"
    5240                 : #endif
    5241                 : "       <Value>C8</Value>"
    5242                 : "   </Option>"
    5243                 : #ifdef JPEG_SUPPORTED
    5244                 : "   <Option name='QUALITY' type='int' description='JPEG quality 10-100' default='75'/>"
    5245                 : "   <Option name='PROGRESSIVE' type='boolean' description='JPEG progressive mode'/>"
    5246                 : "   <Option name='RESTART_INTERVAL' type='int' description='Restart interval (in MCUs). -1 for auto, 0 for none, > 0 for user specified' default='-1'/>"
    5247                 : #endif
    5248                 : "   <Option name='NUMI' type='int' default='1' description='Number of images to create (1-999). Only works with IC=NC'/>"
    5249                 : "   <Option name='TARGET' type='float' description='For JP2 only. Compression Percentage'/>"
    5250                 : "   <Option name='PROFILE' type='string-select' description='For JP2 only.'>"
    5251                 : "       <Value>BASELINE_0</Value>"
    5252                 : "       <Value>BASELINE_1</Value>"
    5253                 : "       <Value>BASELINE_2</Value>"
    5254                 : "       <Value>NPJE</Value>"
    5255                 : "       <Value>EPJE</Value>"
    5256                 : "   </Option>"
    5257                 : "   <Option name='ICORDS' type='string-select' description='To ensure that space will be reserved for geographic corner coordinates in DMS (G), in decimal degrees (D), UTM North (N) or UTM South (S)'>"
    5258                 : "       <Value>G</Value>"
    5259                 : "       <Value>D</Value>"
    5260                 : "       <Value>N</Value>"
    5261                 : "       <Value>S</Value>"
    5262                 : "   </Option>"
    5263                 : "   <Option name='FHDR' type='string-select' description='File version' default='NITF02.10'>"
    5264                 : "       <Value>NITF02.10</Value>"
    5265                 : "       <Value>NSIF01.00</Value>"
    5266                 : "   </Option>"
    5267                 : "   <Option name='IREP' type='string' description='Set to RGB/LUT to reserve space for a color table for each output band. (Only needed for Create() method, not CreateCopy())'/>"
    5268                 : "   <Option name='LUT_SIZE' type='integer' description='Set to control the size of pseudocolor tables for RGB/LUT bands' default='256'/>"
    5269                 : "   <Option name='BLOCKXSIZE' type='int' description='Set the block width'/>"
    5270                 : "   <Option name='BLOCKYSIZE' type='int' description='Set the block height'/>"
    5271                 : "   <Option name='BLOCKSIZE' type='int' description='Set the block with and height. Overridden by BLOCKXSIZE and BLOCKYSIZE'/>"
    5272                 : "   <Option name='TEXT' type='string' description='TEXT options as text-option-name=text-option-content'/>"
    5273             392 : "   <Option name='CGM' type='string' description='CGM options in cgm-option-name=cgm-option-content'/>";
    5274                 : 
    5275           19600 :         for(i=0;i<sizeof(asFieldDescription) / sizeof(asFieldDescription[0]); i++)
    5276                 :         {
    5277                 :             osCreationOptions += CPLString().Printf("   <Option name='%s' type='string' description='%s' maxsize='%d'/>",
    5278           19208 :                     asFieldDescription[i].pszName, asFieldDescription[i].pszDescription, asFieldDescription[i].nMaxLen);
    5279                 :         }
    5280                 : 
    5281                 :         osCreationOptions +=
    5282                 : "   <Option name='TRE' type='string' description='Under the format TRE=tre-name,tre-contents'/>"
    5283                 : "   <Option name='FILE_TRE' type='string' description='Under the format FILE_TRE=tre-name,tre-contents'/>"
    5284             392 : "   <Option name='BLOCKA_BLOCK_COUNT' type='int'/>";
    5285                 : 
    5286            4312 :         for(i=0; apszFieldsBLOCKA[i] != NULL; i+=3)
    5287                 :         {
    5288                 :             char szFieldDescription[128];
    5289                 :             sprintf(szFieldDescription, "   <Option name='BLOCKA_%s_*' type='string' maxsize='%d'/>",
    5290            3920 :                     apszFieldsBLOCKA[i], atoi(apszFieldsBLOCKA[i+2]));
    5291            3920 :             osCreationOptions += szFieldDescription;
    5292                 :         }
    5293                 : 
    5294             392 :         osCreationOptions += "</CreationOptionList>";
    5295                 : 
    5296             392 :         poDriver = new GDALDriver();
    5297                 :         
    5298             392 :         poDriver->SetDescription( "NITF" );
    5299                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    5300             392 :                                    "National Imagery Transmission Format" );
    5301                 :         
    5302             392 :         poDriver->pfnIdentify = NITFDataset::Identify;
    5303             392 :         poDriver->pfnOpen = NITFDataset::Open;
    5304             392 :         poDriver->pfnCreate = NITFDataset::NITFDatasetCreate;
    5305             392 :         poDriver->pfnCreateCopy = NITFDataset::NITFCreateCopy;
    5306                 : 
    5307             392 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_nitf.html" );
    5308             392 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ntf" );
    5309                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    5310             392 :                                    "Byte UInt16 Int16 UInt32 Int32 Float32" );
    5311                 : 
    5312             392 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, osCreationOptions);
    5313             392 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    5314                 : 
    5315             392 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    5316                 :     }
    5317             409 : }

Generated by: LTP GCOV extension version 1.5