LCOV - code coverage report
Current view: directory - frmts/nitf - rpftocdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 527 425 80.6 %
Date: 2012-12-26 Functions: 50 39 78.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: rpftocdataset.cpp
       3                 :  *
       4                 :  * Project:  RPF TOC read Translator
       5                 :  * Purpose:  Implementation of RPFTOCDataset and RPFTOCSubDataset.
       6                 :  * Author:   Even Rouault, even.rouault at mines-paris.org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "gdal_proxy.h"
      32                 : #include "rpftoclib.h"
      33                 : #include "ogr_spatialref.h"
      34                 : #include "cpl_string.h"
      35                 : #include "vrtdataset.h"
      36                 : #include "cpl_multiproc.h"
      37                 : 
      38                 : #define GEOTRSFRM_TOPLEFT_X            0
      39                 : #define GEOTRSFRM_WE_RES               1
      40                 : #define GEOTRSFRM_ROTATION_PARAM1      2
      41                 : #define GEOTRSFRM_TOPLEFT_Y            3
      42                 : #define GEOTRSFRM_ROTATION_PARAM2      4
      43                 : #define GEOTRSFRM_NS_RES               5
      44                 : 
      45                 : CPL_CVSID("$Id: rpftocdataset.cpp 24857 2012-08-26 06:58:30Z rouault $");
      46                 : 
      47                 : 
      48                 : /** Overview of used classes :
      49                 :    - RPFTOCDataset : lists the different subdatasets, listed in the A.TOC,
      50                 :                      as subdatasets
      51                 :    - RPFTOCSubDataset : one of these subdatasets, implemented as a VRT, of
      52                 :                         the relevant NITF tiles
      53                 :    - RPFTOCProxyRasterDataSet : a "proxy" dataset that maps to a NITF tile
      54                 :    - RPFTOCProxyRasterBandPalette / RPFTOCProxyRasterBandRGBA : bands of RPFTOCProxyRasterDataSet
      55                 : */
      56                 : 
      57                 : /************************************************************************/
      58                 : /* ==================================================================== */
      59                 : /*                            RPFTOCDataset                             */
      60                 : /* ==================================================================== */
      61                 : /************************************************************************/
      62                 : 
      63                 : class RPFTOCDataset : public GDALPamDataset
      64                 : {
      65                 :   char      **papszSubDatasets;
      66                 :   char       *pszProjection;
      67                 :   int         bGotGeoTransform;
      68                 :   double      adfGeoTransform[6];
      69                 :   
      70                 :   char      **papszFileList;
      71                 : 
      72                 :   public:
      73               2 :     RPFTOCDataset()
      74               2 :     {
      75               2 :         papszSubDatasets = NULL;
      76               2 :         pszProjection = NULL;
      77               2 :         bGotGeoTransform = FALSE;
      78               2 :         papszFileList = NULL;
      79               2 :     }
      80                 : 
      81               2 :     ~RPFTOCDataset()
      82               2 :     {
      83               2 :         CSLDestroy( papszSubDatasets );
      84               2 :         CPLFree(pszProjection);
      85               2 :         CSLDestroy(papszFileList);
      86               2 :     }
      87                 : 
      88                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
      89                 : 
      90               0 :     virtual char      **GetFileList() { return CSLDuplicate(papszFileList); }
      91                 : 
      92                 :     void                AddSubDataset(const char* pszFilename, RPFTocEntry* tocEntry );
      93                 : 
      94               2 :     void SetSize(int rasterXSize, int rasterYSize)
      95                 :     {
      96               2 :         nRasterXSize = rasterXSize;
      97               2 :         nRasterYSize = rasterYSize;
      98               2 :     }
      99                 : 
     100               0 :     virtual CPLErr GetGeoTransform( double * padfGeoTransform)
     101                 :     {
     102               0 :         if (bGotGeoTransform)
     103                 :         {
     104               0 :             memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
     105               0 :             return CE_None;
     106                 :         }
     107               0 :         return CE_Failure;
     108                 :     }
     109                 :     
     110               2 :     virtual CPLErr SetGeoTransform( double * padfGeoTransform)
     111                 :     {
     112               2 :         bGotGeoTransform = TRUE;
     113               2 :         memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
     114               2 :         return CE_None;
     115                 :     }
     116                 :     
     117               2 :     virtual CPLErr SetProjection( const char * projectionRef )
     118                 :     {
     119               2 :         CPLFree(pszProjection);
     120               2 :         pszProjection = CPLStrdup(projectionRef);
     121               2 :         return CE_None;
     122                 :     }
     123                 :     
     124               0 :     virtual const char *GetProjectionRef(void)
     125                 :     {
     126               0 :         return (pszProjection) ? pszProjection : "";
     127                 :     }
     128                 :     
     129                 :     static int IsNITFFileTOC(NITFFile *psFile);
     130                 :     static int IsNonNITFFileTOC(GDALOpenInfo * poOpenInfo, const char* pszFilename );
     131                 :     static GDALDataset* OpenFileTOC(NITFFile *psFile,
     132                 :                                     const char* pszFilename,
     133                 :                                     const char* entryName,
     134                 :                                     const char* openInformationName);
     135                 :     
     136                 :     static int Identify( GDALOpenInfo * poOpenInfo );
     137                 :     static GDALDataset* Open( GDALOpenInfo * poOpenInfo );
     138                 : };
     139                 : 
     140                 : /************************************************************************/
     141                 : /* ==================================================================== */
     142                 : /*                            RPFTOCSubDataset                          */
     143                 : /* ==================================================================== */
     144                 : /************************************************************************/
     145                 : 
     146                 : class RPFTOCSubDataset : public VRTDataset
     147                 : {
     148                 : 
     149                 :   int          cachedTileBlockXOff;
     150                 :   int          cachedTileBlockYOff;
     151                 :   void*        cachedTileData;
     152                 :   int          cachedTileDataSize;
     153                 :   const char*  cachedTileFileName;
     154                 :   char**       papszFileList;
     155                 : 
     156                 :   public:
     157               8 :     RPFTOCSubDataset(int nXSize, int nYSize) : VRTDataset(nXSize, nYSize)
     158                 :     {
     159                 :         /* Don't try to write a VRT file */
     160               8 :         SetWritable(FALSE);
     161                 : 
     162                 :         /* The driver is set to VRT in VRTDataset constructor. */
     163                 :         /* We have to set it to the expected value ! */
     164               8 :         poDriver = (GDALDriver *) GDALGetDriverByName( "RPFTOC" );
     165                 : 
     166               8 :         cachedTileBlockXOff = cachedTileBlockYOff = -1;
     167               8 :         cachedTileData = NULL;
     168               8 :         cachedTileDataSize = 0;
     169               8 :         cachedTileFileName = NULL;
     170                 : 
     171               8 :         papszFileList = NULL;
     172               8 :     }
     173                 :     
     174               8 :     ~RPFTOCSubDataset()
     175               8 :     {
     176               8 :         CSLDestroy(papszFileList);
     177               8 :         CPLFree(cachedTileData);
     178               8 :     }
     179                 : 
     180               2 :     virtual char      **GetFileList() { return CSLDuplicate(papszFileList); }
     181                 : 
     182             288 :     void* GetCachedTile(const char* tileFileName, int nBlockXOff, int nBlockYOff)
     183                 :     {
     184             288 :         if (cachedTileFileName == tileFileName  &&
     185                 :             cachedTileBlockXOff == nBlockXOff &&
     186                 :             cachedTileBlockYOff == nBlockYOff)
     187                 :         {
     188             216 :             return cachedTileData;
     189                 :         }
     190                 :         else
     191                 :         {
     192              72 :             return NULL;
     193                 :         }
     194                 :     }
     195                 : 
     196              72 :     void SetCachedTile(const char* tileFileName, int nBlockXOff, int nBlockYOff,
     197                 :                        const void* pData, int dataSize)
     198                 :     {
     199              72 :         if (dataSize > cachedTileDataSize)
     200                 :         {
     201               2 :             cachedTileData = CPLRealloc(cachedTileData, dataSize);
     202               2 :             cachedTileDataSize = dataSize;
     203                 :         }
     204              72 :         memcpy(cachedTileData, pData, dataSize);
     205              72 :         cachedTileFileName = tileFileName;
     206              72 :         cachedTileBlockXOff = nBlockXOff;
     207              72 :         cachedTileBlockYOff = nBlockYOff;
     208              72 :     }
     209                 : 
     210                 :     
     211                 :     static GDALDataset* CreateDataSetFromTocEntry(const char* openInformationName,
     212                 :                                                   const char* pszTOCFileName, int nEntry,
     213                 :                                                   const RPFTocEntry* entry, int isRGBA,
     214                 :                                                   char** papszMetadataRPFTOCFile);
     215                 : };
     216                 : 
     217                 : /************************************************************************/
     218                 : /* ==================================================================== */
     219                 : /*                        RPFTOCProxyRasterDataSet                       */
     220                 : /* ==================================================================== */
     221                 : /************************************************************************/
     222                 : 
     223                 : class RPFTOCProxyRasterDataSet : public GDALProxyPoolDataset
     224               8 : {
     225                 :     /* The following parameters are only for sanity checking */
     226                 :     int checkDone;
     227                 :     int checkOK;
     228                 :     double nwLong, nwLat;
     229                 :     GDALColorTable* colorTableRef;
     230                 :     int bHasNoDataValue;
     231                 :     double noDataValue;
     232                 :     RPFTOCSubDataset* subdataset;
     233                 : 
     234                 :     public:
     235                 :         RPFTOCProxyRasterDataSet(RPFTOCSubDataset* subdataset,
     236                 :                                  const char* fileName,
     237                 :                                  int nRasterXSize, int nRasterYSize,
     238                 :                                  int nBlockXSize, int nBlockYSize,
     239                 :                                  const char* projectionRef, double nwLong, double nwLat,
     240                 :                                  int nBands);
     241                 : 
     242               5 :         void SetNoDataValue(double noDataValue) {
     243               5 :             this->noDataValue = noDataValue;
     244               5 :             bHasNoDataValue = TRUE;
     245               5 :         }
     246                 : 
     247               2 :         double GetNoDataValue(int* bHasNoDataValue)
     248                 :         {
     249               2 :             if (bHasNoDataValue)
     250               2 :                 *bHasNoDataValue = this->bHasNoDataValue;
     251               2 :             return noDataValue;
     252                 :         }
     253                 : 
     254             364 :         GDALDataset* RefUnderlyingDataset()
     255                 :         {
     256             364 :             return GDALProxyPoolDataset::RefUnderlyingDataset();
     257                 :         }
     258                 : 
     259             364 :         void UnrefUnderlyingDataset(GDALDataset* poUnderlyingDataset)
     260                 :         {
     261             364 :             GDALProxyPoolDataset::UnrefUnderlyingDataset(poUnderlyingDataset);
     262             364 :         }
     263                 : 
     264               5 :         void SetReferenceColorTable(GDALColorTable* colorTableRef) { this->colorTableRef = colorTableRef;}
     265                 : 
     266               2 :         const GDALColorTable* GetReferenceColorTable() { return colorTableRef; }
     267                 : 
     268                 :         int SanityCheckOK(GDALDataset* sourceDS);
     269                 : 
     270             360 :         RPFTOCSubDataset* GetSubDataset() { return subdataset; }
     271                 : };
     272                 : 
     273                 : /************************************************************************/
     274                 : /* ==================================================================== */
     275                 : /*                     RPFTOCProxyRasterBandRGBA                        */
     276                 : /* ==================================================================== */
     277                 : /************************************************************************/
     278                 : 
     279                 : class RPFTOCProxyRasterBandRGBA : public GDALPamRasterBand
     280              12 : {
     281                 :     int initDone;
     282                 :     unsigned char colorTable[256];
     283                 :     int blockByteSize;
     284                 : 
     285                 :     private:
     286                 :         void Expand(void* pImage, const void* srcImage);
     287                 : 
     288                 :     public:
     289              12 :         RPFTOCProxyRasterBandRGBA(GDALProxyPoolDataset* poDS, int nBand,
     290                 :                                   int nBlockXSize, int nBlockYSize)
     291              12 :         {
     292              12 :             this->poDS = poDS;
     293              12 :             nRasterXSize = poDS->GetRasterXSize();
     294              12 :             nRasterYSize = poDS->GetRasterYSize();
     295              12 :             this->nBlockXSize = nBlockXSize;
     296              12 :             this->nBlockYSize = nBlockYSize;
     297              12 :             eDataType = GDT_Byte;
     298              12 :             this->nBand = nBand;
     299              12 :             blockByteSize = nBlockXSize * nBlockYSize;
     300              12 :             initDone = FALSE;
     301              12 :         }
     302                 : 
     303               0 :         virtual GDALColorInterp GetColorInterpretation()
     304                 :         {
     305               0 :             return (GDALColorInterp)(GCI_RedBand + nBand - 1);
     306                 :         }
     307                 : 
     308                 :     protected:
     309                 :         virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
     310                 :                                    void * pImage );
     311                 : };
     312                 : 
     313                 : /************************************************************************/
     314                 : /*                    Expand()                                          */
     315                 : /************************************************************************/
     316                 : 
     317                 : /* Expand the  array or indexed colors to an array of their corresponding R,G,B or A component */
     318             288 : void  RPFTOCProxyRasterBandRGBA::Expand(void* pImage, const void* srcImage)
     319                 : {
     320                 :     int i;
     321             288 :     if ((blockByteSize & (~3)) != 0)
     322                 :     {
     323        18874656 :         for(i=0;i<blockByteSize;i++)
     324                 :         {
     325        18874368 :             ((unsigned char*)pImage)[i] = colorTable[((unsigned char*)srcImage)[i]];
     326                 :         }
     327                 :     }
     328                 :     else
     329                 :     {
     330               0 :         int nIter = blockByteSize/4;
     331               0 :         for(i=0;i<nIter;i++)
     332                 :         {
     333               0 :             unsigned int four_pixels = ((unsigned int*)srcImage)[i];
     334               0 :             ((unsigned int*)pImage)[i] =
     335               0 :                     (colorTable[four_pixels >> 24] << 24) |
     336               0 :                     (colorTable[(four_pixels >> 16) & 0xFF] << 16) |
     337               0 :                     (colorTable[(four_pixels >> 8) & 0xFF] << 8) |
     338               0 :                     colorTable[four_pixels & 0xFF];
     339                 :         }
     340                 :     }
     341                 : 
     342             288 : }
     343                 : 
     344                 : /************************************************************************/
     345                 : /*                    IReadBlock()                                      */
     346                 : /************************************************************************/
     347                 : 
     348             288 : CPLErr RPFTOCProxyRasterBandRGBA::IReadBlock( int nBlockXOff, int nBlockYOff,
     349                 :                                          void * pImage )
     350                 : {
     351                 :     CPLErr ret;
     352             288 :     RPFTOCProxyRasterDataSet* proxyDS = (RPFTOCProxyRasterDataSet*)poDS;
     353             288 :     GDALDataset* ds = proxyDS->RefUnderlyingDataset();
     354             288 :     if (ds)
     355                 :     {
     356             288 :         if (proxyDS->SanityCheckOK(ds) == FALSE)
     357                 :         {
     358               0 :             proxyDS->UnrefUnderlyingDataset(ds);
     359               0 :             return CE_Failure;
     360                 :         }
     361                 : 
     362             288 :         GDALRasterBand* srcBand = ds->GetRasterBand(1);
     363             288 :         if (initDone == FALSE)
     364                 :         {
     365               8 :             GDALColorTable* srcColorTable = srcBand->GetColorTable();
     366                 :             int i;
     367                 :             int bHasNoDataValue;
     368               8 :             int noDataValue = (int)srcBand->GetNoDataValue(&bHasNoDataValue);
     369               8 :             int nEntries = srcColorTable->GetColorEntryCount();
     370            1744 :             for(i=0;i<nEntries;i++)
     371                 :             {
     372            1736 :                 const GDALColorEntry* entry = srcColorTable->GetColorEntry(i);
     373            1736 :                 if (nBand == 1)
     374             434 :                     colorTable[i] = (unsigned char)entry->c1;
     375            1302 :                 else if (nBand == 2)
     376             434 :                     colorTable[i] = (unsigned char)entry->c2;
     377             868 :                 else if (nBand == 3)
     378             434 :                     colorTable[i] = (unsigned char)entry->c3;
     379                 :                 else
     380                 :                 {
     381             434 :                     colorTable[i] = (bHasNoDataValue && i == noDataValue) ? 0 : (unsigned char)entry->c4;
     382                 :                 }
     383                 :             }
     384               8 :             if (bHasNoDataValue && nEntries == noDataValue)
     385               0 :                 colorTable[nEntries] = 0;
     386               8 :             initDone = TRUE;
     387                 :         }
     388                 : 
     389                 :         /* We use a 1-tile cache as the same source tile will be consecutively asked for */
     390                 :         /* computing the R tile, the G tile, the B tile and the A tile */
     391                 :         void* cachedImage =
     392             288 :                 proxyDS->GetSubDataset()->GetCachedTile(GetDescription(), nBlockXOff, nBlockYOff);
     393             288 :         if (cachedImage == NULL)
     394                 :         {
     395                 :             CPLDebug("RPFTOC", "Read (%d, %d) of band %d, of file %s",
     396              72 :                      nBlockXOff, nBlockYOff, nBand, GetDescription());
     397              72 :             ret = srcBand->ReadBlock(nBlockXOff, nBlockYOff, pImage);
     398              72 :             if (ret == CE_None)
     399                 :             {
     400                 :                 proxyDS->GetSubDataset()->SetCachedTile
     401              72 :                         (GetDescription(), nBlockXOff, nBlockYOff, pImage, blockByteSize);
     402              72 :                 Expand(pImage, pImage);
     403                 :             }
     404                 : 
     405                 :             /* -------------------------------------------------------------------- */
     406                 :             /*      Forceably load the other bands associated with this scanline.   */
     407                 :             /* -------------------------------------------------------------------- */
     408              72 :             if(nBand == 1 )
     409                 :             {
     410                 :                 GDALRasterBlock *poBlock;
     411                 : 
     412                 :                 poBlock = 
     413              72 :                     poDS->GetRasterBand(2)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
     414              72 :                 if (poBlock)
     415              72 :                     poBlock->DropLock();
     416                 : 
     417                 :                 poBlock = 
     418              72 :                     poDS->GetRasterBand(3)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
     419              72 :                 if (poBlock)
     420              72 :                     poBlock->DropLock();
     421                 : 
     422                 :                 poBlock = 
     423              72 :                     poDS->GetRasterBand(4)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
     424              72 :                 if (poBlock)
     425              72 :                     poBlock->DropLock();
     426                 :             }
     427                 :         }
     428                 :         else
     429                 :         {
     430             216 :             Expand(pImage, cachedImage);
     431             216 :             ret = CE_None;
     432                 :         }
     433                 : 
     434                 :     }
     435                 :     else
     436               0 :         ret = CE_Failure;
     437                 : 
     438             288 :     proxyDS->UnrefUnderlyingDataset(ds);
     439                 : 
     440             288 :     return ret;
     441                 : }
     442                 : 
     443                 : /************************************************************************/
     444                 : /* ==================================================================== */
     445                 : /*                 RPFTOCProxyRasterBandPalette                         */
     446                 : /* ==================================================================== */
     447                 : /************************************************************************/
     448                 : 
     449                 : class RPFTOCProxyRasterBandPalette : public GDALPamRasterBand
     450               5 : {
     451                 :     int initDone;
     452                 :     int blockByteSize;
     453                 :     int samePalette;
     454                 :     unsigned char remapLUT[256];
     455                 : 
     456                 :     public:
     457               5 :         RPFTOCProxyRasterBandPalette(GDALProxyPoolDataset* poDS, int nBand,
     458                 :                                      int nBlockXSize, int nBlockYSize)
     459               5 :         {
     460               5 :             this->poDS = poDS;
     461               5 :             nRasterXSize = poDS->GetRasterXSize();
     462               5 :             nRasterYSize = poDS->GetRasterYSize();
     463               5 :             this->nBlockXSize = nBlockXSize;
     464               5 :             this->nBlockYSize = nBlockYSize;
     465               5 :             eDataType = GDT_Byte;
     466               5 :             this->nBand = nBand;
     467               5 :             blockByteSize = nBlockXSize * nBlockYSize;
     468               5 :             initDone = FALSE;
     469               5 :         }
     470                 : 
     471               2 :         virtual GDALColorInterp GetColorInterpretation()
     472                 :         {
     473               2 :             return GCI_PaletteIndex;
     474                 :         }
     475                 : 
     476               2 :         virtual double GetNoDataValue(int* bHasNoDataValue)
     477                 :         {
     478               2 :             return ((RPFTOCProxyRasterDataSet*)poDS)->GetNoDataValue(bHasNoDataValue);
     479                 :         }
     480                 : 
     481               2 :         virtual GDALColorTable *GetColorTable()
     482                 :         {
     483               2 :             return (GDALColorTable *) ((RPFTOCProxyRasterDataSet*)poDS)->GetReferenceColorTable();
     484                 :         }
     485                 : 
     486                 :     protected:
     487                 :         virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
     488                 :                                    void * pImage );
     489                 : };
     490                 : 
     491                 : /************************************************************************/
     492                 : /*                    IReadBlock()                                      */
     493                 : /************************************************************************/
     494                 : 
     495              72 : CPLErr RPFTOCProxyRasterBandPalette::IReadBlock( int nBlockXOff, int nBlockYOff,
     496                 :                                                  void * pImage )
     497                 : {
     498                 :     CPLErr ret;
     499              72 :     RPFTOCProxyRasterDataSet* proxyDS = (RPFTOCProxyRasterDataSet*)poDS;
     500              72 :     GDALDataset* ds = proxyDS->RefUnderlyingDataset();
     501              72 :     if (ds)
     502                 :     {
     503              72 :         if (proxyDS->SanityCheckOK(ds) == FALSE)
     504                 :         {
     505               0 :             proxyDS->UnrefUnderlyingDataset(ds);
     506               0 :             return CE_Failure;
     507                 :         }
     508                 : 
     509              72 :         GDALRasterBand* srcBand = ds->GetRasterBand(1);
     510              72 :         ret = srcBand->ReadBlock(nBlockXOff, nBlockYOff, pImage);
     511                 :         
     512              72 :         if (initDone == FALSE)
     513                 :         {
     514                 :             int approximateMatching;
     515               2 :             if (srcBand->GetIndexColorTranslationTo(this, remapLUT, &approximateMatching ))
     516                 :             {
     517               0 :                 samePalette = FALSE;
     518               0 :                 if (approximateMatching)
     519                 :                 {
     520                 :                     CPLError( CE_Failure, CPLE_AppDefined,
     521                 :                               "Palette for %s is different from reference palette. "
     522               0 :                               "Coudln't remap exactly all colors. Trying to find closest matches.\n", GetDescription());
     523                 :                 }
     524                 :             }
     525                 :             else
     526                 :             {
     527               2 :                 samePalette = TRUE;
     528                 :             }
     529               2 :             initDone = TRUE;
     530                 :         }
     531                 : 
     532                 : 
     533              72 :         if (samePalette == FALSE)
     534                 :         {
     535               0 :             unsigned char* data = (unsigned char*)pImage;
     536                 :             int i;
     537               0 :             for(i=0;i<blockByteSize;i++)
     538                 :             {
     539               0 :                 data[i] = remapLUT[data[i]];
     540                 :             }
     541                 :         }
     542                 : 
     543                 :     }
     544                 :     else
     545               0 :         ret = CE_Failure;
     546                 : 
     547              72 :     proxyDS->UnrefUnderlyingDataset(ds);
     548                 : 
     549              72 :     return ret;
     550                 : }
     551                 : 
     552                 : /************************************************************************/
     553                 : /*                    RPFTOCProxyRasterDataSet()                         */
     554                 : /************************************************************************/
     555                 : 
     556               8 : RPFTOCProxyRasterDataSet::RPFTOCProxyRasterDataSet
     557                 :         (RPFTOCSubDataset* subdataset,
     558                 :          const char* fileName,
     559                 :          int nRasterXSize, int nRasterYSize,
     560                 :          int nBlockXSize, int nBlockYSize,
     561                 :          const char* projectionRef, double nwLong, double nwLat,
     562                 :          int nBands) :
     563                 :             /* Mark as shared since the VRT will take several references if we are in RGBA mode (4 bands for this dataset) */
     564               8 :                 GDALProxyPoolDataset(fileName, nRasterXSize, nRasterYSize, GA_ReadOnly, TRUE, projectionRef)
     565                 : {
     566                 :     int i;
     567               8 :     this->subdataset = subdataset;
     568               8 :     this->nwLong = nwLong;
     569               8 :     this->nwLat = nwLat;
     570               8 :     bHasNoDataValue = FALSE;
     571               8 :     noDataValue = 0;
     572               8 :     colorTableRef = NULL;
     573                 : 
     574               8 :     checkDone = FALSE;
     575               8 :     checkOK = FALSE;
     576               8 :     if (nBands == 4)
     577                 :     {
     578              15 :         for(i=0;i<4;i++)
     579                 :         {
     580              12 :             SetBand(i + 1, new RPFTOCProxyRasterBandRGBA(this, i+1, nBlockXSize, nBlockYSize));
     581                 :         }
     582                 :     }
     583                 :     else
     584               5 :         SetBand(1, new RPFTOCProxyRasterBandPalette(this, 1, nBlockXSize, nBlockYSize));
     585               8 : }
     586                 : 
     587                 : /************************************************************************/
     588                 : /*                    SanityCheckOK()                                   */
     589                 : /************************************************************************/
     590                 : 
     591                 : #define WARN_ON_FAIL(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined, "For %s, assert '" #x "' failed", GetDescription()); } } while(0)
     592                 : #define ERROR_ON_FAIL(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined, "For %s, assert '" #x "' failed", GetDescription()); checkOK = FALSE; } } while(0)
     593                 : 
     594             360 : int RPFTOCProxyRasterDataSet::SanityCheckOK(GDALDataset* sourceDS)
     595                 : {
     596                 :     int src_nBlockXSize, src_nBlockYSize;
     597                 :     int nBlockXSize, nBlockYSize;
     598                 :     double adfGeoTransform[6];
     599             360 :     if (checkDone)
     600             356 :         return checkOK;
     601                 :     
     602               4 :     checkOK = TRUE;
     603               4 :     checkDone = TRUE;
     604                 :     
     605               4 :     sourceDS->GetGeoTransform(adfGeoTransform);
     606               4 :     WARN_ON_FAIL(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_X] - nwLong) < adfGeoTransform[1] );
     607               4 :     WARN_ON_FAIL(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] - nwLat) < fabs(adfGeoTransform[5]) );
     608               4 :     WARN_ON_FAIL(adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
     609                 :                   adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
     610               4 :     ERROR_ON_FAIL(sourceDS->GetRasterCount() == 1); /* Just 1 band */
     611               4 :     ERROR_ON_FAIL(sourceDS->GetRasterXSize() == nRasterXSize);
     612               4 :     ERROR_ON_FAIL(sourceDS->GetRasterYSize() == nRasterYSize);
     613               4 :     WARN_ON_FAIL(EQUAL(sourceDS->GetProjectionRef(), GetProjectionRef()));
     614               4 :     sourceDS->GetRasterBand(1)->GetBlockSize(&src_nBlockXSize, &src_nBlockYSize);
     615               4 :     GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
     616               4 :     ERROR_ON_FAIL(src_nBlockXSize == nBlockXSize);
     617               4 :     ERROR_ON_FAIL(src_nBlockYSize == nBlockYSize);
     618               4 :     WARN_ON_FAIL(sourceDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
     619               4 :     WARN_ON_FAIL(sourceDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
     620                 : 
     621               4 :     return checkOK;
     622                 : }
     623                 : 
     624                 : /************************************************************************/
     625                 : /*                           MakeTOCEntryName()                         */
     626                 : /************************************************************************/
     627                 : 
     628               8 : static const char* MakeTOCEntryName(RPFTocEntry* tocEntry )
     629                 : {
     630                 :     char* str;
     631               8 :     if (tocEntry->seriesAbbreviation)
     632               8 :         str = (char*)CPLSPrintf( "%s_%s_%s_%s_%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
     633                 :     else
     634               0 :         str = (char*)CPLSPrintf( "%s_%s_%s_%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
     635               8 :     char* c = str;
     636             200 :     while(*c)
     637                 :     {
     638             184 :         if (*c == ':' || *c == ' ')
     639               0 :             *c = '_';
     640             184 :         c++;
     641                 :     }
     642               8 :     return str;
     643                 : }
     644                 : 
     645                 : /************************************************************************/
     646                 : /*                           AddSubDataset()                            */
     647                 : /************************************************************************/
     648                 : 
     649               2 : void RPFTOCDataset::AddSubDataset( const char* pszFilename,  RPFTocEntry* tocEntry )
     650                 : 
     651                 : {
     652                 :     char  szName[80];
     653               2 :     int   nCount = CSLCount(papszSubDatasets ) / 2;
     654                 : 
     655               2 :     sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
     656                 :     papszSubDatasets = 
     657                 :         CSLSetNameValue( papszSubDatasets, szName, 
     658               2 :               CPLSPrintf( "NITF_TOC_ENTRY:%s:%s", MakeTOCEntryName(tocEntry), pszFilename ) );
     659                 : 
     660               2 :     sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
     661               4 :     if (tocEntry->seriesName && tocEntry->seriesAbbreviation)
     662                 :         papszSubDatasets = 
     663                 :         CSLSetNameValue( papszSubDatasets, szName,
     664               2 :                CPLSPrintf( "%s:%s:%s:%s:%s:%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->seriesName, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
     665                 :     else
     666                 :         papszSubDatasets = 
     667                 :             CSLSetNameValue( papszSubDatasets, szName,
     668               0 :                 CPLSPrintf( "%s:%s:%s:%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
     669               2 : }
     670                 : 
     671                 : /************************************************************************/
     672                 : /*                            GetMetadata()                             */
     673                 : /************************************************************************/
     674                 : 
     675               3 : char **RPFTOCDataset::GetMetadata( const char *pszDomain )
     676                 : 
     677                 : {
     678               3 :     if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
     679               3 :         return papszSubDatasets;
     680                 : 
     681               0 :     return GDALPamDataset::GetMetadata( pszDomain );
     682                 : }
     683                 : 
     684                 : /************************************************************************/
     685                 : /*                  NITFCreateVRTDataSetFromTocEntry()                  */
     686                 : /************************************************************************/
     687                 : 
     688                 : 
     689                 : #define ASSERT_CREATE_VRT(x) do { if (!(x)) { CPLError(CE_Failure, CPLE_AppDefined, "For %s, assert '" #x "' failed", entry->frameEntries[i].fullFilePath); if (poSrcDS) GDALClose(poSrcDS); CPLFree(projectionRef); return NULL;} } while(0)
     690                 : 
     691                 : /* Builds a RPFTOCSubDataset from the set of files of the toc entry */
     692               8 : GDALDataset* RPFTOCSubDataset::CreateDataSetFromTocEntry(const char* openInformationName,
     693                 :                                                          const char* pszTOCFileName, int nEntry,
     694                 :                                                          const RPFTocEntry* entry, int isRGBA,
     695                 :                                                          char** papszMetadataRPFTOCFile)
     696                 : {
     697                 :     int i, j;
     698                 :     GDALDriver *poDriver;
     699                 :     RPFTOCSubDataset *poVirtualDS;
     700                 :     int sizeX, sizeY;
     701               8 :     int nBlockXSize = 0, nBlockYSize = 0;
     702                 :     double geoTransf[6];
     703               8 :     char* projectionRef = NULL;
     704                 :     int N;
     705               8 :     int index = 0;
     706                 : 
     707               8 :     poDriver = GetGDALDriverManager()->GetDriverByName("VRT");
     708               8 :     if( poDriver == NULL )
     709               0 :         return NULL;
     710                 : 
     711               8 :     N = entry->nVertFrames * entry->nHorizFrames;
     712                 : 
     713                 :     /* This may not be reliable. See below */
     714               8 :     sizeX = (int)((entry->seLong - entry->nwLong) / (entry->nHorizFrames * entry->horizInterval) + 0.5);
     715               8 :     sizeY = (int)((entry->nwLat - entry->seLat) / (entry->nVertFrames * entry->vertInterval) + 0.5);
     716                 : 
     717              16 :     for(i=0;i<N; i++)
     718                 :     {
     719               8 :         if (!entry->frameEntries[i].fileExists)
     720               0 :             continue;
     721                 : 
     722               8 :         if (index == 0)
     723                 :         {
     724                 :             int ds_sizeX, ds_sizeY;
     725                 :             /* Open the first available file to get its geotransform, projection ref and block size */
     726                 :             /* Do a few sanity checks too */
     727                 :             /* Ideally we should make these sanity checks now on ALL files, but it would be too slow */
     728                 :             /* for large datasets. So these sanity checks will be done at the time we really need */
     729                 :             /* to access the file (see SanityCheckOK metho) */
     730               8 :             GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
     731               8 :             ASSERT_CREATE_VRT(poSrcDS);
     732               8 :             poSrcDS->GetGeoTransform(geoTransf);
     733               8 :             projectionRef = CPLStrdup(poSrcDS->GetProjectionRef());
     734               8 :             ASSERT_CREATE_VRT(geoTransf[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
     735                 :                               geoTransf[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
     736               8 :             ASSERT_CREATE_VRT(poSrcDS->GetRasterCount() == 1); /* Just 1 band */
     737                 :             
     738                 :             /* Tolerance of 1%... This is necessary for CADRG_L22/RPF/A.TOC for example */
     739               8 :             ASSERT_CREATE_VRT((entry->horizInterval - geoTransf[GEOTRSFRM_WE_RES]) /
     740                 :                                 entry->horizInterval < 0.01); /* X interval same as in TOC */
     741               8 :             ASSERT_CREATE_VRT((entry->vertInterval - (-geoTransf[GEOTRSFRM_NS_RES])) /
     742                 :                                 entry->horizInterval < 0.01); /* Y interval same as in TOC */
     743                 : 
     744               8 :             ds_sizeX = poSrcDS->GetRasterXSize();
     745               8 :             ds_sizeY = poSrcDS->GetRasterYSize();
     746                 :             /* In the case the east longitude is 180, there's a great chance that it is in fact */
     747                 :             /* truncated in the A.TOC. Thus, the only reliable way to find out the tile width, is to */
     748                 :             /* read it from the tile dataset itself... */
     749                 :             /* This is the case for the GNCJNCN dataset that has world coverage */
     750               8 :             if (entry->seLong == 180.00)
     751               0 :                 sizeX = ds_sizeX;
     752                 :             else
     753               8 :                 ASSERT_CREATE_VRT(sizeX == ds_sizeX);
     754               8 :             ASSERT_CREATE_VRT(sizeY == ds_sizeY);
     755               8 :             poSrcDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
     756               8 :             ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
     757               8 :             ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
     758               8 :             GDALClose(poSrcDS);
     759                 :         }
     760                 : 
     761               8 :         index++;
     762                 :     }
     763                 : 
     764               8 :     if (index == 0)
     765               0 :         return NULL;
     766                 : 
     767                 :     /* ------------------------------------ */
     768                 :     /* Create the VRT with the overall size */
     769                 :     /* ------------------------------------ */
     770                 :     poVirtualDS = new RPFTOCSubDataset( sizeX * entry->nHorizFrames,
     771               8 :                                         sizeY * entry->nVertFrames);
     772                 : 
     773               8 :     if (papszMetadataRPFTOCFile)
     774               0 :         poVirtualDS->SetMetadata(papszMetadataRPFTOCFile);
     775                 : 
     776               8 :     poVirtualDS->SetProjection(projectionRef);
     777                 : 
     778               8 :     geoTransf[GEOTRSFRM_TOPLEFT_X] = entry->nwLong;
     779               8 :     geoTransf[GEOTRSFRM_TOPLEFT_Y] = entry->nwLat;
     780               8 :     poVirtualDS->SetGeoTransform(geoTransf);
     781                 :     
     782                 :     int nBands;
     783                 :     
     784                 :     /* In most cases, all the files inside a TOC entry share the same */
     785                 :     /* palette and we could use it for the VRT. */
     786                 :     /* In other cases like for CADRG801_France_250K (TOC entry CADRG_250K_2_2), */
     787                 :     /* the file for Corsica and the file for Sardegna do not share the same palette */
     788                 :     /* however they contain the same RGB triplets and are just ordered differently */
     789                 :     /* So we can use the same palette */
     790                 :     /* In the unlikely event where palettes would be incompatible, we can use the RGBA */
     791                 :     /* option through the config option RPFTOC_FORCE_RGBA */
     792               8 :     if (isRGBA == FALSE)
     793                 :     {
     794               5 :         poVirtualDS->AddBand(GDT_Byte, NULL);
     795               5 :         GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
     796               5 :         poBand->SetColorInterpretation(GCI_PaletteIndex);
     797               5 :         nBands = 1;
     798                 :         
     799              10 :         for(i=0;i<N; i++)
     800                 :         {
     801               5 :             if (!entry->frameEntries[i].fileExists)
     802               0 :                 continue;
     803                 :             
     804               5 :             int bAllBlack = TRUE;
     805               5 :             GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
     806               5 :             if( poSrcDS != NULL )
     807                 :             {
     808               5 :                 if( poSrcDS->GetRasterCount() == 1 )
     809                 :                 {
     810                 :                     int bHasNoDataValue;
     811               5 :                     double noDataValue = poSrcDS->GetRasterBand(1)->GetNoDataValue(&bHasNoDataValue);
     812               5 :                     if (bHasNoDataValue)
     813               5 :                         poBand->SetNoDataValue(noDataValue);
     814                 : 
     815                 :                     /* Avoid setting a color table that is all black (which might be */
     816                 :                     /* the case of the edge tiles of a RPF subdataset) */
     817               5 :                     GDALColorTable* poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
     818               5 :                     if( poCT != NULL )
     819                 :                     {
     820            1090 :                         for(int iC = 0; iC < poCT->GetColorEntryCount(); iC++)
     821                 :                         {
     822            1085 :                             if( bHasNoDataValue && iC == (int)noDataValue )
     823               5 :                                 continue;
     824                 : 
     825            1080 :                             const GDALColorEntry* entry = poCT->GetColorEntry(i);
     826            1080 :                             if( entry->c1 != 0 || entry->c2 != 0 || entry->c3 != 0)
     827                 :                             {
     828               0 :                                 bAllBlack = FALSE;
     829               0 :                                 break;
     830                 :                             }
     831                 :                         }
     832                 : 
     833                 :                         /* Assign it temporarily, in the hope of a better match */
     834                 :                         /* afterwards */
     835               5 :                         poBand->SetColorTable(poCT);
     836               5 :                         if( bAllBlack )
     837                 :                         {
     838                 :                             CPLDebug("RPFTOC",
     839                 :                                      "Skipping %s. Its palette is all black.",
     840               5 :                                      poSrcDS->GetDescription());
     841                 :                         }
     842                 :                     }
     843                 :                 }
     844               5 :                 GDALClose(poSrcDS);
     845                 :             }
     846               5 :             if( !bAllBlack )
     847               0 :                 break;
     848                 :         }
     849                 :     }
     850                 :     else
     851                 :     {
     852              15 :         for (i=0;i<4;i++)
     853                 :         {
     854              12 :             poVirtualDS->AddBand(GDT_Byte, NULL);
     855              12 :             GDALRasterBand *poBand = poVirtualDS->GetRasterBand( i + 1 );
     856              12 :             poBand->SetColorInterpretation((GDALColorInterp)(GCI_RedBand+i));
     857                 :         }
     858               3 :         nBands = 4;
     859                 :     }
     860                 : 
     861               8 :     CPLFree(projectionRef);
     862               8 :     projectionRef = NULL;
     863                 : 
     864                 :     /* -------------------------------------------------------------------- */
     865                 :     /*      Check for overviews.                                            */
     866                 :     /* -------------------------------------------------------------------- */
     867                 : 
     868                 :     poVirtualDS->oOvManager.Initialize( poVirtualDS,
     869               8 :                                         CPLString().Printf("%s.%d", pszTOCFileName, nEntry + 1));
     870                 : 
     871               8 :     poVirtualDS->SetDescription(pszTOCFileName);
     872               8 :     poVirtualDS->papszFileList = poVirtualDS->GDALDataset::GetFileList();
     873               8 :     poVirtualDS->SetDescription(openInformationName);
     874                 : 
     875               8 :     int iFile = 0;
     876              16 :     for(i=0;i<N; i++)
     877                 :     {
     878               8 :         if (! entry->frameEntries[i].fileExists)
     879               0 :             continue;
     880                 : 
     881               8 :         poVirtualDS->SetMetadataItem(CPLSPrintf("FILENAME_%d", iFile), entry->frameEntries[i].fullFilePath);
     882               8 :         poVirtualDS->papszFileList = CSLAddString(poVirtualDS->papszFileList, entry->frameEntries[i].fullFilePath);
     883               8 :         iFile++;
     884                 : 
     885                 :         /* We create proxy datasets and raster bands */
     886                 :         /* Using real datasets and raster bands is possible in theory */
     887                 :         /* However for large datasets, a TOC entry can include several hundreds of files */
     888                 :         /* and we finally reach the limit of maximum file descriptors open at the same time ! */
     889                 :         /* So the idea is to warp the datasets into a proxy and open the underlying dataset only when it is */
     890                 :         /* needed (IRasterIO operation). To improve a bit efficiency, we have a cache of opened */
     891                 :         /* underlying datasets */
     892                 :         RPFTOCProxyRasterDataSet* ds = new RPFTOCProxyRasterDataSet(
     893                 :                 (RPFTOCSubDataset*)poVirtualDS,
     894               8 :                 entry->frameEntries[i].fullFilePath,
     895                 :                 sizeX, sizeY,
     896                 :                 nBlockXSize, nBlockYSize,
     897               8 :                 poVirtualDS->GetProjectionRef(),
     898               8 :                 entry->nwLong + entry->frameEntries[i].frameCol * entry->horizInterval * sizeX, 
     899               8 :                 entry->nwLat - entry->frameEntries[i].frameRow * entry->vertInterval * sizeY,
     900              40 :                 nBands);
     901               8 :         if (nBands == 1)
     902                 :         {
     903               5 :             GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
     904               5 :             ds->SetReferenceColorTable(poBand->GetColorTable());
     905                 :             int bHasNoDataValue;
     906               5 :             double noDataValue = poBand->GetNoDataValue(&bHasNoDataValue);
     907               5 :             if (bHasNoDataValue)
     908               5 :                 ds->SetNoDataValue(noDataValue);
     909                 :         }
     910                 : 
     911              25 :         for(j=0;j<nBands;j++)
     912                 :         {
     913              17 :             VRTSourcedRasterBand *poBand = (VRTSourcedRasterBand*)poVirtualDS->GetRasterBand( j + 1 );
     914                 :             /* Place the raster band at the right position in the VRT */
     915                 :             poBand->AddSimpleSource(ds->GetRasterBand(j + 1),
     916                 :                                     0, 0, sizeX, sizeY,
     917              17 :                                     entry->frameEntries[i].frameCol * sizeX, 
     918              17 :                                     entry->frameEntries[i].frameRow * sizeY,
     919              34 :                                     sizeX, sizeY);
     920                 :         }
     921                 : 
     922                 :         /* The RPFTOCProxyRasterDataSet will be destroyed when its last raster band will be */
     923                 :         /* destroyed */
     924               8 :         ds->Dereference();
     925                 :     }
     926                 : 
     927               8 :     poVirtualDS->SetMetadataItem("NITF_SCALE", entry->scale);
     928                 :     poVirtualDS->SetMetadataItem("NITF_SERIES_ABBREVIATION",
     929               8 :                         (entry->seriesAbbreviation) ? entry->seriesAbbreviation : "Unknown");
     930                 :     poVirtualDS->SetMetadataItem("NITF_SERIES_NAME",
     931               8 :                         (entry->seriesName) ? entry->seriesName : "Unknown");
     932                 : 
     933               8 :     return poVirtualDS;
     934                 : }
     935                 : 
     936                 : /************************************************************************/
     937                 : /*                          IsNonNITFFileTOC()                          */
     938                 : /************************************************************************/
     939                 : 
     940                 : /* Check whether the file is a TOC file without NITF header */
     941            2632 : int RPFTOCDataset::IsNonNITFFileTOC(GDALOpenInfo * poOpenInfo, const char* pszFilename )
     942                 : {
     943            2632 :     const char pattern[] = { 0, 0, '0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', '.', 'T', 'O', 'C' };
     944            2632 :     if (poOpenInfo)
     945                 :     {
     946            2626 :         if (poOpenInfo->nHeaderBytes < 48 )
     947               0 :             return FALSE;
     948            2626 :         return memcmp(pattern, poOpenInfo->pabyHeader, 15) == 0;
     949                 :     }
     950                 :     else
     951                 :     {
     952                 :         char buffer[48];
     953               6 :         VSILFILE* fp = NULL;
     954               6 :         fp = VSIFOpenL( pszFilename, "rb" );
     955               6 :         if( fp == NULL )
     956                 :         {
     957               0 :             return FALSE;
     958                 :         }
     959                 : 
     960                 :         int ret = (VSIFReadL(buffer, 1, 48, fp) == 48) &&
     961               6 :                    memcmp(pattern, buffer, 15) == 0;
     962               6 :         VSIFCloseL(fp);
     963               6 :         return ret;
     964                 :     }
     965                 : }
     966                 : 
     967                 : /************************************************************************/
     968                 : /*                             IsNITFFileTOC()                          */
     969                 : /************************************************************************/
     970                 : 
     971                 : /* Check whether this NITF file is a TOC file */
     972               0 : int RPFTOCDataset::IsNITFFileTOC(NITFFile *psFile)
     973                 : {
     974               0 :     const char* fileTitle = CSLFetchNameValue(psFile->papszMetadata, "NITF_FTITLE");
     975               0 :     while(fileTitle && *fileTitle)
     976                 :     {
     977               0 :         if (EQUAL(fileTitle, "A.TOC"))
     978                 :         {
     979               0 :             return TRUE;
     980                 :         }
     981               0 :         fileTitle++;
     982                 :     }
     983               0 :     return FALSE;
     984                 : }
     985                 : 
     986                 : /************************************************************************/
     987                 : /*                                OpenFileTOC()                         */
     988                 : /************************************************************************/
     989                 : 
     990                 : /* Create a dataset from a TOC file */
     991                 : /* If psFile == NULL, the TOC file has no NITF header */
     992                 : /* If entryName != NULL, the dataset will be made just of the entry of the TOC file */
     993               8 : GDALDataset* RPFTOCDataset::OpenFileTOC(NITFFile *psFile,
     994                 :                                         const char* pszFilename,
     995                 :                                         const char* entryName,
     996                 :                                         const char* openInformationName)
     997                 : {
     998                 :     char buffer[48];
     999               8 :     VSILFILE* fp = NULL;
    1000               8 :     if (psFile == NULL)
    1001                 :     {
    1002               8 :         fp = VSIFOpenL( pszFilename, "rb" );
    1003                 : 
    1004               8 :         if( fp == NULL )
    1005                 :         {
    1006                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1007                 :                     "Failed to open file %s.", 
    1008               0 :                     pszFilename );
    1009               0 :             return NULL;
    1010                 :         }
    1011               8 :         VSIFReadL(buffer, 1, 48, fp);
    1012                 :     }
    1013               8 :     int isRGBA = CSLTestBoolean(CPLGetConfigOption("RPFTOC_FORCE_RGBA", "NO"));
    1014                 :     RPFToc* toc = (psFile) ? RPFTOCRead( pszFilename, psFile ) :
    1015               8 :                               RPFTOCReadFromBuffer( pszFilename, fp, buffer);
    1016               8 :     if (fp) VSIFCloseL(fp);
    1017               8 :     fp = NULL;
    1018                 : 
    1019               8 :     if (entryName != NULL)
    1020                 :     {
    1021               6 :         if (toc)
    1022                 :         {
    1023                 :             int i;
    1024               6 :             for(i=0;i<toc->nEntries;i++)
    1025                 :             {
    1026               6 :                 if (EQUAL(entryName, MakeTOCEntryName(&toc->entries[i])))
    1027                 :                 {
    1028                 :                     GDALDataset* ds = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
    1029                 :                                                                                   &toc->entries[i], isRGBA,
    1030               6 :                                                                                   (psFile) ? psFile->papszMetadata : NULL);
    1031                 : 
    1032               6 :                     RPFTOCFree(toc);
    1033               6 :                     return ds;
    1034                 :                 }
    1035                 :             }
    1036                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1037               0 :                         "The entry %s does not exist in file %s.", entryName, pszFilename );
    1038                 :         }
    1039               0 :         RPFTOCFree(toc);
    1040               0 :         return NULL;
    1041                 :     }
    1042                 : 
    1043               2 :     if (toc)
    1044                 :     {
    1045               2 :         RPFTOCDataset* ds = new RPFTOCDataset();
    1046               2 :         if (psFile)
    1047               0 :             ds->SetMetadata( psFile->papszMetadata );
    1048                 : 
    1049                 :         int i;
    1050               2 :         int ok = FALSE;
    1051               2 :         char* projectionRef = NULL;
    1052               2 :         double nwLong = 0, nwLat = 0, seLong = 0, seLat = 0;
    1053                 :         double adfGeoTransform[6];
    1054                 : 
    1055               2 :         ds->papszFileList = CSLAddString(ds->papszFileList, pszFilename);
    1056                 : 
    1057               4 :         for(i=0;i<toc->nEntries;i++)
    1058                 :         {
    1059               2 :             if (!toc->entries[i].isOverviewOrLegend)
    1060                 :             {
    1061                 :                 GDALDataset* tmpDS = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
    1062               2 :                                                                                  &toc->entries[i], isRGBA, NULL);
    1063               2 :                 if (tmpDS)
    1064                 :                 {
    1065               2 :                     char** papszSubDatasetFileList = tmpDS->GetFileList();
    1066                 :                     /* Yes, begin at 1, since the first is the a.toc */
    1067               2 :                     ds->papszFileList = CSLInsertStrings(ds->papszFileList, -1, papszSubDatasetFileList + 1);
    1068               2 :                     CSLDestroy(papszSubDatasetFileList);
    1069                 : 
    1070               2 :                     tmpDS->GetGeoTransform(adfGeoTransform);
    1071               2 :                     if (projectionRef == NULL)
    1072                 :                     {
    1073               2 :                         ok = TRUE;
    1074               2 :                         projectionRef = CPLStrdup(tmpDS->GetProjectionRef());
    1075               2 :                         nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
    1076               2 :                         nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
    1077               2 :                         seLong = nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
    1078               2 :                         seLat = nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
    1079                 :                     }
    1080               0 :                     else if (ok)
    1081                 :                     {
    1082               0 :                         double _nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
    1083               0 :                         double _nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
    1084               0 :                         double _seLong = _nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
    1085               0 :                         double _seLat = _nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
    1086               0 :                         if (! EQUAL(projectionRef, tmpDS->GetProjectionRef()) )
    1087               0 :                             ok = FALSE;
    1088               0 :                         if (_nwLong < nwLong)
    1089               0 :                             nwLong = _nwLong;
    1090               0 :                         if (_nwLat > nwLat)
    1091               0 :                             nwLat = _nwLat;
    1092               0 :                         if (_seLong > seLong)
    1093               0 :                             seLong = _seLong;
    1094               0 :                         if (_seLat < seLat)
    1095               0 :                             seLat = _seLat;
    1096                 :                     }
    1097               2 :                     delete tmpDS;
    1098               2 :                     ds->AddSubDataset(pszFilename, &toc->entries[i]);
    1099                 :                 }
    1100                 :             }
    1101                 :         }
    1102               2 :         if (ok)
    1103                 :         {
    1104               2 :             adfGeoTransform[GEOTRSFRM_TOPLEFT_X] = nwLong;
    1105               2 :             adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] = nwLat;
    1106               2 :             ds->SetSize((int)(0.5 + (seLong - nwLong) / adfGeoTransform[GEOTRSFRM_WE_RES]), 
    1107               4 :                         (int)(0.5 + (seLat - nwLat) / adfGeoTransform[GEOTRSFRM_NS_RES]));
    1108               2 :             ds->SetGeoTransform(adfGeoTransform);
    1109               2 :             ds->SetProjection(projectionRef);
    1110                 :         }
    1111               2 :         CPLFree(projectionRef);
    1112               2 :         RPFTOCFree(toc);
    1113                 : 
    1114                 : /* -------------------------------------------------------------------- */
    1115                 : /*      Initialize any PAM information.                                 */
    1116                 : /* -------------------------------------------------------------------- */
    1117               2 :         ds->SetDescription( pszFilename );
    1118               2 :         ds->TryLoadXML();
    1119                 : 
    1120               2 :         return ds;
    1121                 :     }
    1122                 :     else
    1123                 :     {
    1124               0 :         return NULL;
    1125                 :     }
    1126                 : }
    1127                 : 
    1128                 : /************************************************************************/
    1129                 : /*                              Identify()                              */
    1130                 : /************************************************************************/
    1131                 : 
    1132           14720 : int RPFTOCDataset::Identify( GDALOpenInfo * poOpenInfo )
    1133                 : 
    1134                 : {
    1135           14720 :     const char *pszFilename = poOpenInfo->pszFilename;
    1136                 : 
    1137                 : /* -------------------------------------------------------------------- */
    1138                 : /*      Is this a sub-dataset selector? If so, it is obviously RPFTOC.        */
    1139                 : /* -------------------------------------------------------------------- */
    1140                 : 
    1141           14720 :     if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
    1142               6 :         return TRUE;
    1143                 : 
    1144                 : /* -------------------------------------------------------------------- */
    1145                 : /*  First we check to see if the file has the expected header */
    1146                 : /*  bytes.                */    
    1147                 : /* -------------------------------------------------------------------- */
    1148           14714 :     if( poOpenInfo->nHeaderBytes < 48 )
    1149           12090 :         return FALSE;
    1150                 :     
    1151            2624 :     if ( IsNonNITFFileTOC( poOpenInfo, pszFilename) )
    1152               2 :         return TRUE;
    1153                 :         
    1154            2622 :     if( !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) 
    1155                 :         && !EQUALN((char *) poOpenInfo->pabyHeader,"NSIF",4)
    1156                 :         && !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) )
    1157            2622 :         return FALSE;
    1158                 :     
    1159                 :     int i;
    1160                 :     /* If it's a NITF A.TOC file, it must contain A.TOC in it's header */
    1161               0 :     for(i=0;i<(int)poOpenInfo->nHeaderBytes-(int)strlen("A.TOC");i++)
    1162                 :     {
    1163               0 :         if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "A.TOC", strlen("A.TOC")))
    1164               0 :             return TRUE;
    1165                 :     }
    1166                 : 
    1167               0 :     return FALSE;
    1168                 : }
    1169                 : 
    1170                 : /************************************************************************/
    1171                 : /*                                Open()                                */
    1172                 : /************************************************************************/
    1173                 : 
    1174            4501 : GDALDataset *RPFTOCDataset::Open( GDALOpenInfo * poOpenInfo )
    1175                 : 
    1176                 : {
    1177            4501 :     const char *pszFilename = poOpenInfo->pszFilename;
    1178            4501 :     char* entryName = NULL;
    1179                 : 
    1180            4501 :     if( !Identify( poOpenInfo ) )
    1181            4493 :         return NULL;
    1182                 : 
    1183               8 :     if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
    1184                 :     {
    1185               6 :         pszFilename += strlen("NITF_TOC_ENTRY:");
    1186               6 :         entryName = CPLStrdup(pszFilename);
    1187               6 :         char* c = entryName;
    1188             150 :         while( *c != '\0' && *c != ':' )
    1189             138 :             c++;
    1190               6 :         if( *c != ':' )
    1191                 :         {
    1192               0 :             CPLFree(entryName);
    1193               0 :             return NULL;
    1194                 :         }
    1195               6 :         *c = 0;
    1196                 : 
    1197             150 :         while( *pszFilename != '\0' && *pszFilename != ':' )
    1198             138 :             pszFilename++;
    1199               6 :         pszFilename++;
    1200                 :     }
    1201                 :     
    1202               8 :     if (IsNonNITFFileTOC((entryName != NULL) ? NULL : poOpenInfo, pszFilename))
    1203                 :     {
    1204               8 :         GDALDataset* poDS = OpenFileTOC(NULL, pszFilename, entryName, poOpenInfo->pszFilename);
    1205                 :         
    1206               8 :         CPLFree(entryName);
    1207                 : 
    1208               8 :         if (poDS && poOpenInfo->eAccess == GA_Update)
    1209                 :         {
    1210               0 :             CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
    1211               0 :             delete poDS;
    1212               0 :             return NULL;
    1213                 :         }
    1214                 :         
    1215               8 :         return poDS;
    1216                 :     }
    1217                 : 
    1218                 : /* -------------------------------------------------------------------- */
    1219                 : /*      Open the file with library.                                     */
    1220                 : /* -------------------------------------------------------------------- */
    1221                 :     NITFFile *psFile;
    1222                 : 
    1223               0 :     psFile = NITFOpen( pszFilename, FALSE );
    1224               0 :     if( psFile == NULL )
    1225                 :     {
    1226               0 :         CPLFree(entryName);
    1227               0 :         return NULL;
    1228                 :     }
    1229                 : 
    1230                 : /* -------------------------------------------------------------------- */
    1231                 : /*      Check if it is a TOC file .                                     */
    1232                 : /* -------------------------------------------------------------------- */
    1233               0 :     if (IsNITFFileTOC(psFile))
    1234                 :     {
    1235               0 :         GDALDataset* poDS = OpenFileTOC(psFile, pszFilename, entryName, poOpenInfo->pszFilename);
    1236               0 :         NITFClose( psFile );
    1237               0 :         CPLFree(entryName);
    1238                 : 
    1239               0 :         if (poDS && poOpenInfo->eAccess == GA_Update)
    1240                 :         {
    1241               0 :             CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
    1242               0 :             delete poDS;
    1243               0 :             return NULL;
    1244                 :         }
    1245                 :         
    1246               0 :         return poDS;
    1247                 :     }
    1248                 :     else
    1249                 :     {
    1250                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1251               0 :                           "File %s is not a TOC file.", pszFilename );
    1252               0 :         NITFClose( psFile );
    1253               0 :         CPLFree(entryName);
    1254               0 :         return NULL;
    1255                 :     }
    1256                 : 
    1257                 : }
    1258                 : 
    1259                 : /************************************************************************/
    1260                 : /*                          GDALRegister_RPFTOC()                         */
    1261                 : /************************************************************************/
    1262                 : 
    1263             582 : void GDALRegister_RPFTOC()
    1264                 : 
    1265                 : {
    1266                 :     GDALDriver  *poDriver;
    1267                 : 
    1268             582 :     if( GDALGetDriverByName( "RPFTOC" ) == NULL )
    1269                 :     {
    1270             561 :         poDriver = new GDALDriver();
    1271                 :         
    1272             561 :         poDriver->SetDescription( "RPFTOC" );
    1273                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1274             561 :                                    "Raster Product Format TOC format" );
    1275                 :         
    1276             561 :         poDriver->pfnIdentify = RPFTOCDataset::Identify;
    1277             561 :         poDriver->pfnOpen = RPFTOCDataset::Open;
    1278                 : 
    1279                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1280             561 :                                    "frmt_various.html#RPFTOC" );
    1281             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "toc" );
    1282             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1283                 : 
    1284             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1285                 :     }
    1286             582 : }

Generated by: LCOV version 1.7