LCOV - code coverage report
Current view: directory - frmts/nitf - nitfrasterband.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 357 295 82.6 %
Date: 2012-04-28 Functions: 53 31 58.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: nitfrasterband.cpp 22851 2011-08-01 19:01:18Z rouault $
       3                 :  *
       4                 :  * Project:  NITF Read/Write Translator
       5                 :  * Purpose:  NITFRasterBand (and related proxy band) 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: nitfrasterband.cpp 22851 2011-08-01 19:01:18Z rouault $");
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                       NITFMakeColorTable()                           */
      41                 : /************************************************************************/
      42                 : 
      43          421444 : static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
      44                 : {
      45          421444 :     GDALColorTable* poColorTable = NULL;
      46                 : 
      47          421444 :     if( psBandInfo->nSignificantLUTEntries > 0 )
      48                 :     {
      49                 :         int  iColor;
      50                 : 
      51              82 :         poColorTable = new GDALColorTable();
      52                 : 
      53           16528 :         for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
      54                 :         {
      55                 :             GDALColorEntry sEntry;
      56                 : 
      57           16446 :             sEntry.c1 = psBandInfo->pabyLUT[  0 + iColor];
      58           16446 :             sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
      59           16446 :             sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
      60           16446 :             sEntry.c4 = 255;
      61                 : 
      62           16446 :             poColorTable->SetColorEntry( iColor, &sEntry );
      63                 :         }
      64                 : 
      65              82 :         if (psImage->bNoDataSet)
      66                 :         {
      67                 :             GDALColorEntry sEntry;
      68              62 :             sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
      69              62 :             poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
      70                 :         }
      71                 :     }
      72                 : 
      73                 : /* -------------------------------------------------------------------- */
      74                 : /*      We create a color table for 1 bit data too...                   */
      75                 : /* -------------------------------------------------------------------- */
      76          421444 :     if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
      77                 :     {
      78                 :         GDALColorEntry sEntry;
      79                 : 
      80              36 :         poColorTable = new GDALColorTable();
      81                 : 
      82              36 :         sEntry.c1 = 0;
      83              36 :         sEntry.c2 = 0;
      84              36 :         sEntry.c3 = 0;
      85              36 :         sEntry.c4 = 255;
      86              36 :         poColorTable->SetColorEntry( 0, &sEntry );
      87                 : 
      88              36 :         sEntry.c1 = 255;
      89              36 :         sEntry.c2 = 255;
      90              36 :         sEntry.c3 = 255;
      91              36 :         sEntry.c4 = 255;
      92              36 :         poColorTable->SetColorEntry( 1, &sEntry );
      93                 :     }
      94                 :     
      95          421444 :     return poColorTable;
      96                 : }
      97                 : 
      98                 : /************************************************************************/
      99                 : /* ==================================================================== */
     100                 : /*                        NITFProxyPamRasterBand                        */
     101                 : /* ==================================================================== */
     102                 : /************************************************************************/
     103                 : 
     104             112 : NITFProxyPamRasterBand::~NITFProxyPamRasterBand()
     105                 : {
     106             112 :     std::map<CPLString, char**>::iterator oIter = oMDMap.begin();
     107             232 :     while(oIter != oMDMap.end())
     108                 :     {
     109               8 :         CSLDestroy(oIter->second);
     110               8 :         oIter ++;
     111                 :     }
     112             112 : }
     113                 : 
     114                 : 
     115                 : #define RB_PROXY_METHOD_WITH_RET(retType, retErrValue, methodName, argList, argParams) \
     116                 : retType NITFProxyPamRasterBand::methodName argList \
     117                 : { \
     118                 :     retType ret; \
     119                 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
     120                 :     if (_poSrcBand) \
     121                 :     { \
     122                 :         ret = _poSrcBand->methodName argParams; \
     123                 :         UnrefUnderlyingRasterBand(_poSrcBand); \
     124                 :     } \
     125                 :     else \
     126                 :     { \
     127                 :         ret = retErrValue; \
     128                 :     } \
     129                 :     return ret; \
     130                 : }
     131                 : 
     132                 : 
     133                 : #define RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(retType, retErrValue, methodName, underlyingMethodName, argList, argParams) \
     134                 : retType NITFProxyPamRasterBand::methodName argList \
     135                 : { \
     136                 :     retType ret; \
     137                 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
     138                 :     if (_poSrcBand) \
     139                 :     { \
     140                 :         ret = _poSrcBand->underlyingMethodName argParams; \
     141                 :         UnrefUnderlyingRasterBand(_poSrcBand); \
     142                 :     } \
     143                 :     else \
     144                 :     { \
     145                 :         ret = retErrValue; \
     146                 :     } \
     147                 :     return ret; \
     148                 : }
     149                 : 
     150               8 : char      **NITFProxyPamRasterBand::GetMetadata( const char * pszDomain  )
     151                 : {
     152               8 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
     153               8 :     if (_poSrcBand)
     154                 :     {
     155                 :         /* Let's merge metadata of PAM and the underlying band */
     156                 :         /* PAM metadata should override underlying band metadata */
     157               8 :         char** papszMD = CSLDuplicate(_poSrcBand->GetMetadata( pszDomain ));
     158               8 :         papszMD = CSLMerge( papszMD, GDALPamRasterBand::GetMetadata(pszDomain) );
     159                 : 
     160               8 :         if (pszDomain == NULL)
     161               0 :             pszDomain = "";
     162                 : 
     163               8 :         std::map<CPLString, char**>::iterator oIter = oMDMap.find(pszDomain);
     164               8 :         if (oIter != oMDMap.end())
     165               0 :             CSLDestroy(oIter->second);
     166               8 :         oMDMap[pszDomain] = papszMD;
     167               8 :         UnrefUnderlyingRasterBand(_poSrcBand);
     168                 : 
     169               8 :         return papszMD;
     170                 :     }
     171                 : 
     172               0 :     return GDALPamRasterBand::GetMetadata(pszDomain);
     173                 : }
     174                 : 
     175                 : 
     176               8 : const char *NITFProxyPamRasterBand::GetMetadataItem( const char * pszName,
     177                 :                                                      const char * pszDomain )
     178                 : {
     179               8 :     const char* pszRet = GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     180               8 :     if (pszRet)
     181               0 :         return pszRet;
     182                 : 
     183               8 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
     184               8 :     if (_poSrcBand)
     185                 :     {
     186               8 :         pszRet = _poSrcBand->GetMetadataItem( pszName, pszDomain );
     187               8 :         UnrefUnderlyingRasterBand(_poSrcBand);
     188                 :     }
     189                 : 
     190               8 :     return pszRet;
     191                 : }
     192                 : 
     193               4 : CPLErr NITFProxyPamRasterBand::GetStatistics( int bApproxOK, int bForce,
     194                 :                                       double *pdfMin, double *pdfMax,
     195                 :                                       double *pdfMean, double *pdfStdDev )
     196                 : {
     197                 :     CPLErr ret;
     198                 : 
     199                 : /* -------------------------------------------------------------------- */
     200                 : /*      Do we already have metadata items for the requested values?     */
     201                 : /* -------------------------------------------------------------------- */
     202               4 :     if( (pdfMin == NULL || GetMetadataItem("STATISTICS_MINIMUM") != NULL)
     203               0 :      && (pdfMax == NULL || GetMetadataItem("STATISTICS_MAXIMUM") != NULL)
     204               0 :      && (pdfMean == NULL || GetMetadataItem("STATISTICS_MEAN") != NULL)
     205               0 :      && (pdfStdDev == NULL || GetMetadataItem("STATISTICS_STDDEV") != NULL) )
     206                 :     {
     207                 :         return GDALPamRasterBand::GetStatistics( bApproxOK, bForce,
     208                 :                                                  pdfMin, pdfMax,
     209               0 :                                                  pdfMean, pdfStdDev);
     210                 :     }
     211                 : 
     212               4 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
     213               4 :     if (_poSrcBand)
     214                 :     {
     215                 :         ret = _poSrcBand->GetStatistics( bApproxOK, bForce,
     216               4 :                                          pdfMin, pdfMax, pdfMean, pdfStdDev);
     217               4 :         if (ret == CE_None)
     218                 :         {
     219                 :             /* Report underlying statistics at PAM level */
     220                 :             SetMetadataItem("STATISTICS_MINIMUM",
     221               4 :                             _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
     222                 :             SetMetadataItem("STATISTICS_MAXIMUM",
     223               4 :                             _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
     224                 :             SetMetadataItem("STATISTICS_MEAN",
     225               4 :                             _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
     226                 :             SetMetadataItem("STATISTICS_STDDEV",
     227               4 :                             _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
     228                 :         }
     229               4 :         UnrefUnderlyingRasterBand(_poSrcBand);
     230                 :     }
     231                 :     else
     232                 :     {
     233               0 :         ret = CE_Failure;
     234                 :     }
     235               4 :     return ret;
     236                 : }
     237                 : 
     238               0 : CPLErr NITFProxyPamRasterBand::ComputeStatistics( int bApproxOK,
     239                 :                                         double *pdfMin, double *pdfMax,
     240                 :                                         double *pdfMean, double *pdfStdDev,
     241                 :                                         GDALProgressFunc pfn, void *pProgressData )
     242                 : {
     243                 :     CPLErr ret;
     244               0 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
     245               0 :     if (_poSrcBand)
     246                 :     {
     247                 :         ret = _poSrcBand->ComputeStatistics( bApproxOK, pdfMin, pdfMax,
     248                 :                                              pdfMean, pdfStdDev,
     249               0 :                                              pfn, pProgressData);
     250               0 :         if (ret == CE_None)
     251                 :         {
     252                 :             /* Report underlying statistics at PAM level */
     253                 :             SetMetadataItem("STATISTICS_MINIMUM",
     254               0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
     255                 :             SetMetadataItem("STATISTICS_MAXIMUM",
     256               0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
     257                 :             SetMetadataItem("STATISTICS_MEAN",
     258               0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
     259                 :             SetMetadataItem("STATISTICS_STDDEV",
     260               0 :                             _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
     261                 :         }
     262               0 :         UnrefUnderlyingRasterBand(_poSrcBand);
     263                 :     }
     264                 :     else
     265                 :     {
     266               0 :         ret = CE_Failure;
     267                 :     }
     268               0 :     return ret;
     269                 : }
     270                 : 
     271                 : 
     272                 : #define RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(methodName) \
     273                 : double NITFProxyPamRasterBand::methodName( int *pbSuccess ) \
     274                 : { \
     275                 :     int bSuccess = FALSE; \
     276                 :     double dfRet = GDALPamRasterBand::methodName(&bSuccess); \
     277                 :     if (bSuccess) \
     278                 :     { \
     279                 :         if (pbSuccess) \
     280                 :             *pbSuccess = TRUE; \
     281                 :         return dfRet; \
     282                 :     } \
     283                 :     GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
     284                 :     if (_poSrcBand) \
     285                 :     { \
     286                 :         dfRet = _poSrcBand->methodName( pbSuccess ); \
     287                 :         UnrefUnderlyingRasterBand(_poSrcBand); \
     288                 :     } \
     289                 :     else \
     290                 :     { \
     291                 :         dfRet = 0; \
     292                 :     } \
     293                 :     return dfRet; \
     294                 : }
     295                 : 
     296              12 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetNoDataValue)
     297               0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMinimum)
     298               0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMaximum)
     299                 : 
     300               0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IReadBlock, ReadBlock,
     301                 :                                 ( int nXBlockOff, int nYBlockOff, void* pImage),
     302                 :                                 (nXBlockOff, nYBlockOff, pImage) )
     303               0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IWriteBlock, WriteBlock,
     304                 :                                 ( int nXBlockOff, int nYBlockOff, void* pImage),
     305                 :                                 (nXBlockOff, nYBlockOff, pImage) )
     306           21466 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IRasterIO, RasterIO,
     307                 :                         ( GDALRWFlag eRWFlag,
     308                 :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     309                 :                                 void * pData, int nBufXSize, int nBufYSize,
     310                 :                                 GDALDataType eBufType,
     311                 :                                 int nPixelSpace,
     312                 :                                 int nLineSpace ),
     313                 :                         (eRWFlag, nXOff, nYOff, nXSize, nYSize,
     314                 :                                 pData, nBufXSize, nBufYSize, eBufType,
     315                 :                                 nPixelSpace, nLineSpace ) )
     316                 : 
     317             112 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, FlushCache, (), ())
     318                 : 
     319               0 : RB_PROXY_METHOD_WITH_RET(GDALColorInterp, GCI_Undefined, GetColorInterpretation, (), ())
     320               0 : RB_PROXY_METHOD_WITH_RET(GDALColorTable*, NULL, GetColorTable, (), ())
     321               0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, Fill,
     322                 :                         (double dfRealValue, double dfImaginaryValue),
     323                 :                         (dfRealValue, dfImaginaryValue))
     324                 : 
     325               2 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, ComputeRasterMinMax,
     326                 :                         ( int arg1, double* arg2 ), (arg1, arg2))
     327                 : 
     328               0 : RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
     329               8 : RB_PROXY_METHOD_WITH_RET(int, 0,  GetOverviewCount, (), ())
     330               6 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetOverview, (int arg1), (arg1))
     331               0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetRasterSampleOverview,
     332                 :                         (int arg1), (arg1))
     333                 : 
     334               0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
     335                 :                         (const char * arg1, int arg2, int *arg3,
     336                 :                         GDALProgressFunc arg4, void * arg5),
     337                 :                         (arg1, arg2, arg3, arg4, arg5))
     338                 : 
     339               0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, AdviseRead,
     340                 :                         ( int nXOff, int nYOff, int nXSize, int nYSize,
     341                 :                         int nBufXSize, int nBufYSize,
     342                 :                         GDALDataType eDT, char **papszOptions ),
     343                 :                         (nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, papszOptions))
     344                 : 
     345               0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL, GetMaskBand, (), ())
     346              12 : RB_PROXY_METHOD_WITH_RET(int, 0, GetMaskFlags, (), ())
     347               0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, CreateMaskBand, ( int nFlags ), (nFlags))
     348                 : 
     349                 : 
     350                 : /************************************************************************/
     351                 : /*                 UnrefUnderlyingRasterBand()                        */
     352                 : /************************************************************************/
     353                 : 
     354           21638 : void NITFProxyPamRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand* poUnderlyingRasterBand)
     355                 : {
     356           21638 : }
     357                 : 
     358                 : 
     359                 : /************************************************************************/
     360                 : /* ==================================================================== */
     361                 : /*                            NITFRasterBand                             */
     362                 : /* ==================================================================== */
     363                 : /************************************************************************/
     364                 : 
     365                 : /************************************************************************/
     366                 : /*                           NITFRasterBand()                           */
     367                 : /************************************************************************/
     368                 : 
     369          421436 : NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
     370                 : 
     371                 : {
     372          421436 :     NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
     373                 : 
     374          421436 :     this->poDS = poDS;
     375          421436 :     this->nBand = nBand;
     376                 : 
     377          421436 :     this->eAccess = poDS->eAccess;
     378          421436 :     this->psImage = poDS->psImage;
     379                 : 
     380                 : /* -------------------------------------------------------------------- */
     381                 : /*      Translate data type(s).                                         */
     382                 : /* -------------------------------------------------------------------- */
     383          421436 :     if( psImage->nBitsPerSample <= 8 )
     384          421204 :         eDataType = GDT_Byte;
     385             286 :     else if( psImage->nBitsPerSample == 16 
     386                 :              && EQUAL(psImage->szPVType,"SI") )
     387              54 :         eDataType = GDT_Int16;
     388             178 :     else if( psImage->nBitsPerSample == 16 )
     389              24 :         eDataType = GDT_UInt16;
     390             154 :     else if( psImage->nBitsPerSample == 12 )
     391              36 :         eDataType = GDT_UInt16;
     392             142 :     else if( psImage->nBitsPerSample == 32 
     393                 :              && EQUAL(psImage->szPVType,"SI") )
     394              24 :         eDataType = GDT_Int32;
     395             122 :     else if( psImage->nBitsPerSample == 32 
     396                 :              && EQUAL(psImage->szPVType,"R") )
     397              28 :         eDataType = GDT_Float32;
     398              66 :     else if( psImage->nBitsPerSample == 32 )
     399              24 :         eDataType = GDT_UInt32;
     400              66 :     else if( psImage->nBitsPerSample == 64 
     401                 :              && EQUAL(psImage->szPVType,"R") )
     402              24 :         eDataType = GDT_Float64;
     403              36 :     else if( psImage->nBitsPerSample == 64
     404                 :               && EQUAL(psImage->szPVType,"C") )
     405              18 :         eDataType = GDT_CFloat32;
     406                 :     /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2 characters */
     407                 :     else
     408                 :     {
     409                 :         int bOpenUnderlyingDS = CSLTestBoolean(
     410               0 :                 CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
     411               0 :         if (!bOpenUnderlyingDS && psImage->nBitsPerSample > 8 && psImage->nBitsPerSample < 16)
     412                 :         {
     413               0 :             if (EQUAL(psImage->szPVType,"SI"))
     414               0 :                 eDataType = GDT_Int16;
     415                 :             else
     416               0 :                 eDataType = GDT_UInt16;
     417                 :         }
     418                 :         else
     419                 :         {
     420               0 :             eDataType = GDT_Unknown;
     421                 :             CPLError( CE_Warning, CPLE_AppDefined,
     422                 :                     "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
     423               0 :                     psImage->szPVType, psImage->nBitsPerSample );
     424                 :         }
     425                 :     }
     426                 : 
     427                 : /* -------------------------------------------------------------------- */
     428                 : /*      Work out block size. If the image is all one big block we       */
     429                 : /*      handle via the scanline access API.                             */
     430                 : /* -------------------------------------------------------------------- */
     431          842444 :     if( psImage->nBlocksPerRow == 1 
     432                 :         && psImage->nBlocksPerColumn == 1
     433                 :         && psImage->nBitsPerSample >= 8
     434                 :         && EQUAL(psImage->szIC,"NC") )
     435                 :     {
     436          421008 :         bScanlineAccess = TRUE;
     437          421008 :         nBlockXSize = psImage->nBlockWidth;
     438          421008 :         nBlockYSize = 1;
     439                 :     }
     440                 :     else
     441                 :     {
     442             428 :         bScanlineAccess = FALSE;
     443             428 :         nBlockXSize = psImage->nBlockWidth;
     444             428 :         nBlockYSize = psImage->nBlockHeight;
     445                 :     }
     446                 : 
     447                 : /* -------------------------------------------------------------------- */
     448                 : /*      Do we have a color table?                                       */
     449                 : /* -------------------------------------------------------------------- */
     450                 :     poColorTable = NITFMakeColorTable(psImage,
     451          421436 :                                       psBandInfo);
     452                 : 
     453          421436 :     if( psImage->nBitsPerSample == 1 
     454                 :     ||  psImage->nBitsPerSample == 3
     455                 :     ||  psImage->nBitsPerSample == 5
     456                 :     ||  psImage->nBitsPerSample == 6
     457                 :     ||  psImage->nBitsPerSample == 7
     458                 :     ||  psImage->nBitsPerSample == 12 )
     459             204 :         SetMetadataItem( "NBITS", CPLString().Printf("%d", psImage->nBitsPerSample), "IMAGE_STRUCTURE" );
     460                 : 
     461          421436 :     pUnpackData = 0;
     462          421436 :     if (psImage->nBitsPerSample == 3
     463                 :     ||  psImage->nBitsPerSample == 5
     464                 :     ||  psImage->nBitsPerSample == 6
     465                 :     ||  psImage->nBitsPerSample == 7)
     466             128 :       pUnpackData = new GByte[((nBlockXSize*nBlockYSize+7)/8)*8];
     467          421436 : }
     468                 : 
     469                 : /************************************************************************/
     470                 : /*                          ~NITFRasterBand()                           */
     471                 : /************************************************************************/
     472                 : 
     473          421436 : NITFRasterBand::~NITFRasterBand()
     474                 : 
     475                 : {
     476          421436 :     if( poColorTable != NULL )
     477             110 :         delete poColorTable;
     478                 : 
     479          421436 :     delete[] pUnpackData;
     480          421436 : }
     481                 : 
     482                 : /************************************************************************/
     483                 : /*                             IReadBlock()                             */
     484                 : /************************************************************************/
     485                 : 
     486           46254 : CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     487                 :                                    void * pImage )
     488                 : 
     489                 : {
     490                 :     int  nBlockResult;
     491           46254 :     NITFDataset *poGDS = (NITFDataset *) poDS;
     492                 : 
     493                 : /* -------------------------------------------------------------------- */
     494                 : /*      Special case for JPEG blocks.                                   */
     495                 : /* -------------------------------------------------------------------- */
     496           46254 :     if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
     497                 :     {
     498             110 :         CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
     499                 :         int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
     500             110 :                              (GDALGetDataTypeSize(eDataType)/8);
     501                 : 
     502             110 :         if( eErr != CE_None )
     503               0 :             return eErr;
     504                 : 
     505                 :         memcpy( pImage, 
     506                 :                 poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize, 
     507             110 :                 nBlockBandSize );
     508                 : 
     509             110 :         return eErr;
     510                 :     }
     511                 : 
     512                 : /* -------------------------------------------------------------------- */
     513                 : /*      Read the line/block                                             */
     514                 : /* -------------------------------------------------------------------- */
     515           46144 :     if( bScanlineAccess )
     516                 :     {
     517                 :         nBlockResult = 
     518           42094 :             NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
     519                 :     }
     520                 :     else
     521                 :     {
     522                 :         nBlockResult = 
     523            4050 :             NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
     524                 :     }
     525                 : 
     526           46144 :     if( nBlockResult == BLKREAD_OK )
     527                 :     {
     528           45706 :         if( psImage->nBitsPerSample % 8 )
     529             144 :             Unpack((GByte*)pImage);
     530                 : 
     531           45706 :         return CE_None;
     532                 :     }
     533                 : 
     534             438 :     if( nBlockResult == BLKREAD_FAIL )
     535               0 :         return CE_Failure;
     536                 : 
     537                 : /* -------------------------------------------------------------------- */
     538                 : /*      If we got a null/missing block, try to fill it in with the      */
     539                 : /*      nodata value.  It seems this only really works properly for     */
     540                 : /*      8bit.                                                           */
     541                 : /* -------------------------------------------------------------------- */
     542             438 :     if( psImage->bNoDataSet )
     543                 :         memset( pImage, psImage->nNoDataValue, 
     544             438 :                 psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
     545                 :     else
     546                 :         memset( pImage, 0, 
     547               0 :                 psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
     548                 : 
     549             438 :     return CE_None;
     550                 : }
     551                 : 
     552                 : /************************************************************************/
     553                 : /*                            IWriteBlock()                             */
     554                 : /************************************************************************/
     555                 : 
     556           13308 : CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     557                 :                                     void * pImage )
     558                 :     
     559                 : {
     560                 :     int  nBlockResult;
     561                 : 
     562                 : /* -------------------------------------------------------------------- */
     563                 : /*      Write the line/block                                            */
     564                 : /* -------------------------------------------------------------------- */
     565           13308 :     if( bScanlineAccess )
     566                 :     {
     567                 :         nBlockResult = 
     568           12018 :             NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
     569                 :     }
     570                 :     else
     571                 :     {
     572                 :         nBlockResult = 
     573            1290 :             NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
     574                 :     }
     575                 : 
     576           13308 :     if( nBlockResult == BLKREAD_OK )
     577           13308 :         return CE_None;
     578                 :     else
     579               0 :         return CE_Failure;
     580                 : }
     581                 : 
     582                 : /************************************************************************/
     583                 : /*                           GetNoDataValue()                           */
     584                 : /************************************************************************/
     585                 : 
     586             152 : double NITFRasterBand::GetNoDataValue( int *pbSuccess )
     587                 : 
     588                 : {
     589             152 :     if( pbSuccess != NULL )
     590             150 :         *pbSuccess = psImage->bNoDataSet;
     591                 : 
     592             152 :     if( psImage->bNoDataSet )
     593              38 :         return psImage->nNoDataValue;
     594                 :     else
     595             114 :         return GDALPamRasterBand::GetNoDataValue( pbSuccess );
     596                 : }
     597                 : 
     598                 : /************************************************************************/
     599                 : /*                       GetColorInterpretation()                       */
     600                 : /************************************************************************/
     601                 : 
     602             246 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
     603                 : 
     604                 : {
     605             246 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     606                 : 
     607             246 :     if( poColorTable != NULL )
     608              34 :         return GCI_PaletteIndex;
     609                 :     
     610             212 :     if( EQUAL(psBandInfo->szIREPBAND,"R") )
     611              32 :         return GCI_RedBand;
     612             180 :     if( EQUAL(psBandInfo->szIREPBAND,"G") )
     613              32 :         return GCI_GreenBand;
     614             148 :     if( EQUAL(psBandInfo->szIREPBAND,"B") )
     615              32 :         return GCI_BlueBand;
     616             116 :     if( EQUAL(psBandInfo->szIREPBAND,"M") )
     617              80 :         return GCI_GrayIndex;
     618              36 :     if( EQUAL(psBandInfo->szIREPBAND,"Y") )
     619               4 :         return GCI_YCbCr_YBand;
     620              32 :     if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
     621               4 :         return GCI_YCbCr_CbBand;
     622              28 :     if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
     623               4 :         return GCI_YCbCr_CrBand;
     624                 : 
     625              24 :     return GCI_Undefined;
     626                 : }
     627                 : 
     628                 : /************************************************************************/
     629                 : /*                     NITFSetColorInterpretation()                     */
     630                 : /************************************************************************/
     631                 : 
     632              48 : CPLErr NITFSetColorInterpretation( NITFImage *psImage, 
     633                 :                                    int nBand,
     634                 :                                    GDALColorInterp eInterp )
     635                 :     
     636                 : {
     637              48 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     638              48 :     const char *pszREP = NULL;
     639                 :     GUIntBig nOffset;
     640                 : 
     641              48 :     if( eInterp == GCI_RedBand )
     642              16 :         pszREP = "R";
     643              32 :     else if( eInterp == GCI_GreenBand )
     644              16 :         pszREP = "G";
     645              16 :     else if( eInterp == GCI_BlueBand )
     646              16 :         pszREP = "B";
     647               0 :     else if( eInterp == GCI_GrayIndex )
     648               0 :         pszREP = "M";
     649               0 :     else if( eInterp == GCI_YCbCr_YBand )
     650               0 :         pszREP = "Y";
     651               0 :     else if( eInterp == GCI_YCbCr_CbBand )
     652               0 :         pszREP = "Cb";
     653               0 :     else if( eInterp == GCI_YCbCr_CrBand )
     654               0 :         pszREP = "Cr";
     655               0 :     else if( eInterp == GCI_Undefined )
     656               0 :         return CE_None;
     657                 : 
     658              48 :     if( pszREP == NULL )
     659                 :     {
     660                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     661                 :                   "Requested color interpretation (%s) not supported in NITF.",
     662               0 :                   GDALGetColorInterpretationName( eInterp ) );
     663               0 :         return CE_Failure;
     664                 :     }
     665                 : 
     666                 : /* -------------------------------------------------------------------- */
     667                 : /*      Where does this go in the file?                                 */
     668                 : /* -------------------------------------------------------------------- */
     669              48 :     strcpy( psBandInfo->szIREPBAND, pszREP );
     670              48 :     nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
     671                 : 
     672              48 :     if( nOffset != 0 )
     673              48 :         nOffset += (nBand - 1) * 13;
     674                 :     
     675                 : /* -------------------------------------------------------------------- */
     676                 : /*      write it (space padded).                                        */
     677                 : /* -------------------------------------------------------------------- */
     678                 :     char szPadded[4];
     679              48 :     strcpy( szPadded, pszREP );
     680              48 :     strcat( szPadded, " " );
     681                 :     
     682              48 :     if( nOffset != 0 )
     683                 :     {
     684              48 :         if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0 
     685                 :             || VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
     686                 :         {
     687                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     688               0 :                       "IO failure writing new IREPBAND value to NITF file." );
     689               0 :             return CE_Failure;
     690                 :         }
     691                 :     }
     692                 :     
     693              48 :     return CE_None;
     694                 : }
     695                 : 
     696                 : /************************************************************************/
     697                 : /*                       SetColorInterpretation()                       */
     698                 : /************************************************************************/
     699                 : 
     700              42 : CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
     701                 : 
     702                 : {
     703              42 :     return NITFSetColorInterpretation( psImage, nBand, eInterp );
     704                 : }
     705                 : 
     706                 : /************************************************************************/
     707                 : /*                           GetColorTable()                            */
     708                 : /************************************************************************/
     709                 : 
     710              72 : GDALColorTable *NITFRasterBand::GetColorTable()
     711                 : 
     712                 : {
     713              72 :     return poColorTable;
     714                 : }
     715                 : 
     716                 : /************************************************************************/
     717                 : /*                           SetColorTable()                            */
     718                 : /************************************************************************/
     719                 : 
     720               4 : CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
     721                 : 
     722                 : {
     723               4 :     NITFDataset *poGDS = (NITFDataset *) poDS;
     724               4 :     if( poGDS->bInLoadXML )
     725               0 :         return GDALPamRasterBand::SetColorTable(poNewCT);
     726                 :         
     727               4 :     if( poNewCT == NULL )
     728               0 :         return CE_Failure;
     729                 : 
     730                 :     GByte abyNITFLUT[768];
     731                 :     int   i;
     732               4 :     int   nCount = MIN(256,poNewCT->GetColorEntryCount());
     733                 : 
     734               4 :     memset( abyNITFLUT, 0, 768 );
     735             270 :     for( i = 0; i < nCount; i++ )
     736                 :     {
     737                 :         GDALColorEntry sEntry;
     738                 : 
     739             266 :         poNewCT->GetColorEntryAsRGB( i, &sEntry );
     740             266 :         abyNITFLUT[i    ] = (GByte) sEntry.c1;
     741             266 :         abyNITFLUT[i+256] = (GByte) sEntry.c2;
     742             266 :         abyNITFLUT[i+512] = (GByte) sEntry.c3;
     743                 :     }
     744                 : 
     745               4 :     if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
     746               4 :         return CE_None;
     747                 :     else
     748               0 :         return CE_Failure;
     749                 : }
     750                 : 
     751                 : /************************************************************************/
     752                 : /*                           Unpack()                                   */
     753                 : /************************************************************************/
     754                 : 
     755             144 : void NITFRasterBand::Unpack( GByte* pData )
     756                 : {
     757             144 :   long n = nBlockXSize*nBlockYSize;
     758                 :   long i;
     759                 :   long k;
     760                 : 
     761             144 :   GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
     762             144 :   const GByte* pDataSrc = pData;
     763             144 :   if (n < psImage->nBitsPerSample &&
     764                 :       psImage->nBitsPerSample < 8)
     765                 :   {
     766              42 :       memcpy(abyTempData, pData, n);
     767              42 :       pDataSrc = abyTempData;
     768                 :   }
     769                 : 
     770             144 :   switch (psImage->nBitsPerSample)
     771                 :   {
     772                 :     case 1:
     773                 :     {
     774                 :       // unpack 1-bit in-place in reverse
     775         2101052 :       for (i = n; --i >= 0; )
     776         2101004 :         pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
     777                 :        
     778              24 :       break;
     779                 :     }
     780                 :     case 2:
     781                 :     {
     782                 :       static const int s_Shift2[] = {6, 4, 2, 0};
     783                 :       // unpack 2-bit in-place in reverse
     784             104 :       for (i = n; --i >= 0; )
     785              72 :         pData[i] = (pData[i>>2] >> (GByte)s_Shift2[i&3]) & 0x03;
     786                 :        
     787              16 :       break;
     788                 :     }
     789                 :     case 4:
     790                 :     {
     791                 :       static const int s_Shift4[] = {4, 0};
     792                 :       // unpack 4-bit in-place in reverse
     793             104 :       for (i = n; --i >= 0; )
     794              72 :         pData[i] = (pData[i>>1] >> (GByte)s_Shift4[i&1]) & 0x0f;
     795                 :        
     796              16 :       break;
     797                 :     }
     798                 :     case 3:
     799                 :     {
     800                 :       // unpacks 8 pixels (3 bytes) at time
     801              32 :       for (i = 0, k = 0; i < n; i += 8, k += 3)
     802                 :       {
     803              16 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 5));
     804              16 :         pUnpackData[i+1] = ((pDataSrc[k+0] >> 2) & 0x07);
     805              16 :         pUnpackData[i+2] = ((pDataSrc[k+0] << 1) & 0x07) | (pDataSrc[k+1] >> 7);
     806              16 :         pUnpackData[i+3] = ((pDataSrc[k+1] >> 4) & 0x07);
     807              16 :         pUnpackData[i+4] = ((pDataSrc[k+1] >> 1) & 0x07);
     808              16 :         pUnpackData[i+5] = ((pDataSrc[k+1] << 2) & 0x07) | (pDataSrc[k+2] >> 6);
     809              16 :         pUnpackData[i+6] = ((pDataSrc[k+2] >> 3) & 0x07);
     810              16 :         pUnpackData[i+7] = ((pDataSrc[k+2]) & 0x7);
     811                 :       }
     812                 : 
     813              16 :       memcpy(pData, pUnpackData, n);
     814              16 :       break;
     815                 :     }
     816                 :     case 5:
     817                 :     {
     818                 :       // unpacks 8 pixels (5 bytes) at time
     819              32 :       for (i = 0, k = 0; i < n; i += 8, k += 5)
     820                 :       {
     821              16 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 3));
     822              16 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 2) & 0x1f) | (pDataSrc[k+1] >> 6);
     823              16 :         pUnpackData[i+2] = ((pDataSrc[k+1] >> 1) & 0x1f);
     824              16 :         pUnpackData[i+3] = ((pDataSrc[k+1] << 4) & 0x1f) | (pDataSrc[k+2] >> 4);
     825              16 :         pUnpackData[i+4] = ((pDataSrc[k+2] << 1) & 0x1f) | (pDataSrc[k+3] >> 7);
     826              16 :         pUnpackData[i+5] = ((pDataSrc[k+3] >> 2) & 0x1f);
     827              16 :         pUnpackData[i+6] = ((pDataSrc[k+3] << 3) & 0x1f) | (pDataSrc[k+4] >> 5);
     828              16 :         pUnpackData[i+7] = ((pDataSrc[k+4]) & 0x1f);
     829                 :       }
     830                 : 
     831              16 :       memcpy(pData, pUnpackData, n);
     832              16 :       break;
     833                 :     }
     834                 :     case 6:
     835                 :     {
     836                 :       // unpacks 4 pixels (3 bytes) at time
     837              40 :       for (i = 0, k = 0; i < n; i += 4, k += 3)
     838                 :       {
     839              24 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 2));
     840              24 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 4) & 0x3f) | (pDataSrc[k+1] >> 4);
     841              24 :         pUnpackData[i+2] = ((pDataSrc[k+1] << 2) & 0x3f) | (pDataSrc[k+2] >> 6);
     842              24 :         pUnpackData[i+3] = ((pDataSrc[k+2]) & 0x3f);
     843                 :       }
     844                 : 
     845              16 :       memcpy(pData, pUnpackData, n);
     846              16 :       break;
     847                 :     }
     848                 :     case 7:
     849                 :     {
     850                 :       // unpacks 8 pixels (7 bytes) at time
     851              32 :       for (i = 0, k = 0; i < n; i += 8, k += 7)
     852                 :       {
     853              16 :         pUnpackData[i+0] = ((pDataSrc[k+0] >> 1));
     854              16 :         pUnpackData[i+1] = ((pDataSrc[k+0] << 6) & 0x7f) | (pDataSrc[k+1] >> 2);
     855              16 :         pUnpackData[i+2] = ((pDataSrc[k+1] << 5) & 0x7f) | (pDataSrc[k+2] >> 3) ;
     856              16 :         pUnpackData[i+3] = ((pDataSrc[k+2] << 4) & 0x7f) | (pDataSrc[k+3] >> 4);
     857              16 :         pUnpackData[i+4] = ((pDataSrc[k+3] << 3) & 0x7f) | (pDataSrc[k+4] >> 5);
     858              16 :         pUnpackData[i+5] = ((pDataSrc[k+4] << 2) & 0x7f) | (pDataSrc[k+5] >> 6);
     859              16 :         pUnpackData[i+6] = ((pDataSrc[k+5] << 1) & 0x7f) | (pDataSrc[k+6] >> 7);
     860              16 :         pUnpackData[i+7] = ((pDataSrc[k+6]) & 0x7f);
     861                 :       }
     862                 : 
     863              16 :       memcpy(pData, pUnpackData, n);
     864              16 :       break;
     865                 :     }
     866                 :     case 12:
     867                 :     {
     868              24 :       GByte*   pabyImage = (GByte  *)pData;
     869              24 :       GUInt16* panImage  = (GUInt16*)pData;
     870         2097272 :       for (i = n; --i >= 0; )
     871                 :       {
     872         2097224 :         long iOffset = i*3 / 2;
     873         2097224 :         if (i % 2 == 0)
     874         1048616 :           panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
     875                 :         else
     876         1048608 :           panImage[i] = (pabyImage[iOffset]   & 0x0f) * 16
     877         1048608 :                       + (pabyImage[iOffset+1] & 0xf0) / 16
     878         2097216 :                       + (pabyImage[iOffset+1] & 0x0f) * 256;
     879                 :       }
     880                 : 
     881                 :       break;
     882                 :     }
     883                 :   }
     884             144 : }
     885                 : 
     886                 : /************************************************************************/
     887                 : /* ==================================================================== */
     888                 : /*                       NITFWrapperRasterBand                          */
     889                 : /* ==================================================================== */
     890                 : /************************************************************************/
     891                 : 
     892                 : /************************************************************************/
     893                 : /*                      NITFWrapperRasterBand()                         */
     894                 : /************************************************************************/
     895                 : 
     896             112 : NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
     897                 :                                               GDALRasterBand* poBaseBand,
     898             112 :                                               int nBand)
     899                 : {
     900             112 :     this->poDS = poDS;
     901             112 :     this->nBand = nBand;
     902             112 :     this->poBaseBand = poBaseBand;
     903             112 :     eDataType = poBaseBand->GetRasterDataType();
     904             112 :     poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     905             112 :     poColorTable = NULL;
     906             112 :     eInterp = poBaseBand->GetColorInterpretation();
     907             112 : }
     908                 : 
     909                 : /************************************************************************/
     910                 : /*                      ~NITFWrapperRasterBand()                        */
     911                 : /************************************************************************/
     912                 : 
     913             112 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
     914                 : {
     915             112 :     if( poColorTable != NULL )
     916               8 :         delete poColorTable;
     917             112 : }
     918                 : 
     919                 : /************************************************************************/
     920                 : /*                     RefUnderlyingRasterBand()                        */
     921                 : /************************************************************************/
     922                 : 
     923                 : /* We don't need ref-counting. Just return the base band */
     924           21638 : GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
     925                 : {
     926           21638 :     return poBaseBand;
     927                 : }
     928                 : 
     929                 : /************************************************************************/
     930                 : /*                            GetColorTable()                           */
     931                 : /************************************************************************/
     932                 : 
     933              26 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
     934                 : {
     935              26 :     return poColorTable;
     936                 : }
     937                 : 
     938                 : /************************************************************************/
     939                 : /*                 SetColorTableFromNITFBandInfo()                      */
     940                 : /************************************************************************/
     941                 : 
     942               8 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
     943                 : {
     944               8 :     NITFDataset* poGDS = (NITFDataset* )poDS;
     945                 :     poColorTable = NITFMakeColorTable(poGDS->psImage,
     946               8 :                                       poGDS->psImage->pasBandInfo + nBand - 1);
     947               8 : }
     948                 : 
     949                 : /************************************************************************/
     950                 : /*                        GetColorInterpretation()                      */
     951                 : /************************************************************************/
     952                 : 
     953              64 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
     954                 : {
     955              64 :     return eInterp;
     956                 : }
     957                 : 
     958                 : /************************************************************************/
     959                 : /*                        SetColorInterpretation()                      */
     960                 : /************************************************************************/
     961                 : 
     962             100 : CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
     963                 : {
     964             100 :     this->eInterp = eInterp;
     965             100 :     return CE_None;
     966                 : }
     967                 : 

Generated by: LCOV version 1.7