LCOV - code coverage report
Current view: directory - frmts/nitf - nitfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1662 1105 66.5 %
Date: 2010-01-09 Functions: 56 52 92.9 %

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

Generated by: LCOV version 1.7