LCOV - code coverage report
Current view: directory - frmts/nitf - nitfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 2053 1647 80.2 %
Date: 2012-12-26 Functions: 45 41 91.1 %

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

Generated by: LCOV version 1.7