LCOV - code coverage report
Current view: directory - frmts/nitf - nitfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 2054 1650 80.3 %
Date: 2013-03-30 Functions: 45 41 91.1 %

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

Generated by: LCOV version 1.7