LCOV - code coverage report
Current view: top level - frmts/nitf - nitfrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 463 565 81.9 %
Date: 2026-07-08 22:10:34 Functions: 38 54 70.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NITF Read/Write Translator
       4             :  * Purpose:  NITFRasterBand (and related proxy band) implementations.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12             :  * represented by the Minister of National Defence, 2006, 2020
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************/
      16             : 
      17             : #include "cpl_port.h"
      18             : #include "nitfdataset.h"
      19             : 
      20             : #include <climits>
      21             : #include <cstring>
      22             : #include <algorithm>
      23             : #include <map>
      24             : #include <utility>
      25             : 
      26             : #include "cpl_conv.h"
      27             : #include "cpl_csv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_progress.h"
      30             : #include "cpl_string.h"
      31             : #include "cpl_vsi.h"
      32             : #include "gdal.h"
      33             : #include "gdal_pam.h"
      34             : #include "gdal_priv.h"
      35             : #include "nitflib.h"
      36             : 
      37             : /************************************************************************/
      38             : /*                         NITFMakeColorTable()                         */
      39             : /************************************************************************/
      40             : 
      41      140943 : static GDALColorTable *NITFMakeColorTable(NITFImage *psImage,
      42             :                                           NITFBandInfo *psBandInfo)
      43             : {
      44      140943 :     GDALColorTable *poColorTable = nullptr;
      45             : 
      46      140943 :     if (psBandInfo->nSignificantLUTEntries > 0)
      47             :     {
      48         162 :         poColorTable = new GDALColorTable();
      49             : 
      50       34050 :         for (int iColor = 0; iColor < psBandInfo->nSignificantLUTEntries;
      51             :              iColor++)
      52             :         {
      53             :             GDALColorEntry sEntry;
      54       33888 :             sEntry.c1 = psBandInfo->pabyLUT[0 + iColor];
      55       33888 :             sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
      56       33888 :             sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
      57       33888 :             sEntry.c4 = 255;
      58             : 
      59       33888 :             poColorTable->SetColorEntry(iColor, &sEntry);
      60             :         }
      61             : 
      62         162 :         if (psImage->bNoDataSet)
      63             :         {
      64         138 :             GDALColorEntry sEntry = {0, 0, 0, 0};
      65         138 :             poColorTable->SetColorEntry(psImage->nNoDataValue, &sEntry);
      66             :         }
      67             :     }
      68             : 
      69             :     /* -------------------------------------------------------------------- */
      70             :     /*      We create a color table for 1 bit data too...                   */
      71             :     /* -------------------------------------------------------------------- */
      72      140943 :     if (poColorTable == nullptr && psImage->nBitsPerSample == 1)
      73             :     {
      74          11 :         poColorTable = new GDALColorTable();
      75             : 
      76             :         GDALColorEntry sEntry;
      77          11 :         sEntry.c1 = 0;
      78          11 :         sEntry.c2 = 0;
      79          11 :         sEntry.c3 = 0;
      80          11 :         sEntry.c4 = 255;
      81          11 :         poColorTable->SetColorEntry(0, &sEntry);
      82             : 
      83          11 :         sEntry.c1 = 255;
      84          11 :         sEntry.c2 = 255;
      85          11 :         sEntry.c3 = 255;
      86          11 :         sEntry.c4 = 255;
      87          11 :         poColorTable->SetColorEntry(1, &sEntry);
      88             :     }
      89             : 
      90      140943 :     return poColorTable;
      91             : }
      92             : 
      93             : /************************************************************************/
      94             : /* ==================================================================== */
      95             : /*                        NITFProxyPamRasterBand                        */
      96             : /* ==================================================================== */
      97             : /************************************************************************/
      98             : 
      99          99 : NITFProxyPamRasterBand::~NITFProxyPamRasterBand()
     100             : {
     101          99 :     std::map<CPLString, char **>::iterator oIter = oMDMap.begin();
     102         104 :     while (oIter != oMDMap.end())
     103             :     {
     104           5 :         CSLDestroy(oIter->second);
     105           5 :         ++oIter;
     106             :     }
     107          99 : }
     108             : 
     109           6 : CSLConstList NITFProxyPamRasterBand::GetMetadata(const char *pszDomain)
     110             : {
     111           6 :     GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
     112           6 :     if (_poSrcBand)
     113             :     {
     114             :         /* Let's merge metadata of PAM and the underlying band */
     115             :         /* PAM metadata should override underlying band metadata */
     116           6 :         char **papszMD = CSLDuplicate(_poSrcBand->GetMetadata(pszDomain));
     117           6 :         papszMD = CSLMerge(papszMD, GDALPamRasterBand::GetMetadata(pszDomain));
     118             : 
     119           6 :         if (pszDomain == nullptr)
     120           0 :             pszDomain = "";
     121             : 
     122           6 :         std::map<CPLString, char **>::iterator oIter = oMDMap.find(pszDomain);
     123           6 :         if (oIter != oMDMap.end())
     124           1 :             CSLDestroy(oIter->second);
     125           6 :         oMDMap[pszDomain] = papszMD;
     126           6 :         UnrefUnderlyingRasterBand(_poSrcBand);
     127             : 
     128           6 :         return papszMD;
     129             :     }
     130             : 
     131           0 :     return GDALPamRasterBand::GetMetadata(pszDomain);
     132             : }
     133             : 
     134          11 : const char *NITFProxyPamRasterBand::GetMetadataItem(const char *pszName,
     135             :                                                     const char *pszDomain)
     136             : {
     137          11 :     const char *pszRet = GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     138          11 :     if (pszRet)
     139           0 :         return pszRet;
     140             : 
     141          11 :     GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
     142          11 :     if (_poSrcBand)
     143             :     {
     144          11 :         if (!m_bEnablePixelTypeSignedByteWarning)
     145           0 :             _poSrcBand->EnablePixelTypeSignedByteWarning(false);
     146          11 :         pszRet = _poSrcBand->GetMetadataItem(pszName, pszDomain);
     147          11 :         _poSrcBand->EnablePixelTypeSignedByteWarning(true);
     148          11 :         UnrefUnderlyingRasterBand(_poSrcBand);
     149             :     }
     150             : 
     151          11 :     return pszRet;
     152             : }
     153             : 
     154           2 : CPLErr NITFProxyPamRasterBand::GetStatistics(int bApproxOK, int bForce,
     155             :                                              double *pdfMin, double *pdfMax,
     156             :                                              double *pdfMean, double *pdfStdDev)
     157             : {
     158             :     /* -------------------------------------------------------------------- */
     159             :     /*      Do we already have metadata items for the requested values?     */
     160             :     /* -------------------------------------------------------------------- */
     161           4 :     if ((pdfMin == nullptr ||
     162           2 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
     163           0 :         (pdfMax == nullptr ||
     164           0 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
     165           4 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
     166           0 :         (pdfStdDev == nullptr ||
     167           0 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
     168             :     {
     169           0 :         return GDALPamRasterBand::GetStatistics(bApproxOK, bForce, pdfMin,
     170           0 :                                                 pdfMax, pdfMean, pdfStdDev);
     171             :     }
     172             : 
     173           2 :     GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
     174           2 :     if (_poSrcBand)
     175             :     {
     176           4 :         CPLErr ret = _poSrcBand->GetStatistics(bApproxOK, bForce, pdfMin,
     177           2 :                                                pdfMax, pdfMean, pdfStdDev);
     178           2 :         if (ret == CE_None)
     179             :         {
     180             :             /* Report underlying statistics at PAM level */
     181           2 :             SetMetadataItem("STATISTICS_MINIMUM",
     182           2 :                             _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
     183           2 :             SetMetadataItem("STATISTICS_MAXIMUM",
     184           2 :                             _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
     185           2 :             SetMetadataItem("STATISTICS_MEAN",
     186           2 :                             _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
     187           2 :             SetMetadataItem("STATISTICS_STDDEV",
     188           2 :                             _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
     189             :         }
     190           2 :         UnrefUnderlyingRasterBand(_poSrcBand);
     191           2 :         return ret;
     192             :     }
     193             : 
     194           0 :     return CE_Failure;
     195             : }
     196             : 
     197           0 : CPLErr NITFProxyPamRasterBand::ComputeStatistics(
     198             :     int bApproxOK, double *pdfMin, double *pdfMax, double *pdfMean,
     199             :     double *pdfStdDev, GDALProgressFunc pfn, void *pProgressData,
     200             :     CSLConstList papszOptions)
     201             : {
     202           0 :     GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
     203           0 :     if (_poSrcBand)
     204             :     {
     205             :         const bool bSetStatistics =
     206           0 :             CPLFetchBool(papszOptions, "SET_STATISTICS", true);
     207           0 :         CPLErr ret = _poSrcBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax,
     208             :                                                    pdfMean, pdfStdDev, pfn,
     209           0 :                                                    pProgressData, papszOptions);
     210           0 :         if (ret == CE_None && bSetStatistics)
     211             :         {
     212             :             /* Report underlying statistics at PAM level */
     213           0 :             SetMetadataItem("STATISTICS_MINIMUM",
     214           0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
     215           0 :             SetMetadataItem("STATISTICS_MAXIMUM",
     216           0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
     217           0 :             SetMetadataItem("STATISTICS_MEAN",
     218           0 :                             _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
     219           0 :             SetMetadataItem("STATISTICS_STDDEV",
     220           0 :                             _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
     221             :         }
     222           0 :         UnrefUnderlyingRasterBand(_poSrcBand);
     223           0 :         return ret;
     224             :     }
     225             : 
     226           0 :     return CE_Failure;
     227             : }
     228             : 
     229             : #define RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(methodName)                       \
     230             :     double NITFProxyPamRasterBand::methodName(int *pbSuccess)                  \
     231             :     {                                                                          \
     232             :         int bSuccess = FALSE;                                                  \
     233             :         double dfRet = GDALPamRasterBand::methodName(&bSuccess);               \
     234             :         if (bSuccess)                                                          \
     235             :         {                                                                      \
     236             :             if (pbSuccess)                                                     \
     237             :                 *pbSuccess = TRUE;                                             \
     238             :             return dfRet;                                                      \
     239             :         }                                                                      \
     240             :         GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();                \
     241             :         if (_poSrcBand)                                                        \
     242             :         {                                                                      \
     243             :             dfRet = _poSrcBand->methodName(pbSuccess);                         \
     244             :             UnrefUnderlyingRasterBand(_poSrcBand);                             \
     245             :         }                                                                      \
     246             :         else                                                                   \
     247             :         {                                                                      \
     248             :             dfRet = 0;                                                         \
     249             :         }                                                                      \
     250             :         return dfRet;                                                          \
     251             :     }
     252             : 
     253          15 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetNoDataValue)
     254           0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMinimum)
     255           0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMaximum)
     256             : 
     257             : #define RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(                        \
     258             :     retType, retErrValue, methodName, underlyingMethodName, argList,           \
     259             :     argParams)                                                                 \
     260             :     retType NITFProxyPamRasterBand::methodName argList                         \
     261             :     {                                                                          \
     262             :         retType ret;                                                           \
     263             :         GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();                \
     264             :         if (_poSrcBand)                                                        \
     265             :         {                                                                      \
     266             :             ret = _poSrcBand->underlyingMethodName argParams;                  \
     267             :             UnrefUnderlyingRasterBand(_poSrcBand);                             \
     268             :         }                                                                      \
     269             :         else                                                                   \
     270             :         {                                                                      \
     271             :             ret = retErrValue;                                                 \
     272             :         }                                                                      \
     273             :         return ret;                                                            \
     274             :     }
     275             : 
     276           0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IReadBlock,
     277             :                                                ReadBlock,
     278             :                                                (int nXBlockOff, int nYBlockOff,
     279             :                                                 void *pImage),
     280             :                                                (nXBlockOff, nYBlockOff, pImage))
     281           0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IWriteBlock,
     282             :                                                WriteBlock,
     283             :                                                (int nXBlockOff, int nYBlockOff,
     284             :                                                 void *pImage),
     285             :                                                (nXBlockOff, nYBlockOff, pImage))
     286         403 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(
     287             :     CPLErr, CE_Failure, IRasterIO, RasterIO,
     288             :     (GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     289             :      void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     290             :      GSpacing nPixelSpace, GSpacing nLineSpace,
     291             :      GDALRasterIOExtraArg *psExtraArg),
     292             :     (eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     293             :      eBufType, nPixelSpace, nLineSpace, psExtraArg))
     294             : 
     295             : #define RB_PROXY_METHOD_WITH_RET(retType, retErrValue, methodName, argList,    \
     296             :                                  argParams)                                    \
     297             :     retType NITFProxyPamRasterBand::methodName argList                         \
     298             :     {                                                                          \
     299             :         retType ret;                                                           \
     300             :         GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();                \
     301             :         if (_poSrcBand)                                                        \
     302             :         {                                                                      \
     303             :             ret = _poSrcBand->methodName argParams;                            \
     304             :             UnrefUnderlyingRasterBand(_poSrcBand);                             \
     305             :         }                                                                      \
     306             :         else                                                                   \
     307             :         {                                                                      \
     308             :             ret = retErrValue;                                                 \
     309             :         }                                                                      \
     310             :         return ret;                                                            \
     311             :     }
     312             : 
     313         102 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, FlushCache, (bool bAtClosing),
     314             :                          (bAtClosing))
     315             : 
     316           0 : RB_PROXY_METHOD_WITH_RET(GDALColorInterp, GCI_Undefined, GetColorInterpretation,
     317             :                          (), ())
     318           0 : RB_PROXY_METHOD_WITH_RET(GDALColorTable *, nullptr, GetColorTable, (), ())
     319           0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, Fill,
     320             :                          (double dfRealValue, double dfImaginaryValue),
     321             :                          (dfRealValue, dfImaginaryValue))
     322             : 
     323           1 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, ComputeRasterMinMax,
     324             :                          (int arg1, double *arg2), (arg1, arg2))
     325             : 
     326           0 : RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
     327           4 : RB_PROXY_METHOD_WITH_RET(int, 0, GetOverviewCount, (), ())
     328           2 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetOverview, (int arg1),
     329             :                          (arg1))
     330           0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetRasterSampleOverview,
     331             :                          (GUIntBig arg1), (arg1))
     332             : 
     333           0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
     334             :                          (const char *arg1, int arg2, const int *arg3,
     335             :                           GDALProgressFunc arg4, void *arg5,
     336             :                           CSLConstList papszOptions),
     337             :                          (arg1, arg2, arg3, arg4, arg5, papszOptions))
     338             : 
     339           4 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, AdviseRead,
     340             :                          (int nXOff, int nYOff, int nXSize, int nYSize,
     341             :                           int nBufXSize, int nBufYSize, GDALDataType eDT,
     342             :                           CSLConstList papszOptions),
     343             :                          (nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
     344             :                           eDT, papszOptions))
     345             : 
     346           0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetMaskBand, (), ())
     347          22 : RB_PROXY_METHOD_WITH_RET(int, 0, GetMaskFlags, (), ())
     348           0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, CreateMaskBand, (int nFlagsIn),
     349             :                          (nFlagsIn))
     350             : 
     351             : /************************************************************************/
     352             : /*                     UnrefUnderlyingRasterBand()                      */
     353             : /************************************************************************/
     354             : 
     355         572 : void NITFProxyPamRasterBand::UnrefUnderlyingRasterBand(
     356             :     CPL_UNUSED GDALRasterBand *poUnderlyingRasterBand)
     357             : {
     358         572 : }
     359             : 
     360             : /************************************************************************/
     361             : /* ==================================================================== */
     362             : /*                            NITFRasterBand                             */
     363             : /* ==================================================================== */
     364             : /************************************************************************/
     365             : 
     366             : /************************************************************************/
     367             : /*                           NITFRasterBand()                           */
     368             : /************************************************************************/
     369             : 
     370      140943 : NITFRasterBand::NITFRasterBand(NITFDataset *poDSIn, int nBandIn)
     371      140943 :     : psImage(poDSIn->psImage)
     372             : {
     373      140943 :     NITFBandInfo *psBandInfo = poDSIn->psImage->pasBandInfo + nBandIn - 1;
     374             : 
     375      140943 :     poDS = poDSIn;
     376      140943 :     nBand = nBandIn;
     377      140943 :     eAccess = poDSIn->eAccess;
     378             : 
     379             :     /* -------------------------------------------------------------------- */
     380             :     /*      Translate data type(s).                                         */
     381             :     /* -------------------------------------------------------------------- */
     382      140943 :     if (psImage->nBitsPerSample <= 8)
     383      140816 :         eDataType = GDT_UInt8;
     384         127 :     else if (psImage->nBitsPerSample == 16 && EQUAL(psImage->szPVType, "SI"))
     385          24 :         eDataType = GDT_Int16;
     386         103 :     else if (psImage->nBitsPerSample == 16)
     387          20 :         eDataType = GDT_UInt16;
     388          83 :     else if (psImage->nBitsPerSample == 12)
     389           7 :         eDataType = GDT_UInt16;
     390          76 :     else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "SI"))
     391          12 :         eDataType = GDT_Int32;
     392          64 :     else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "R"))
     393          31 :         eDataType = GDT_Float32;
     394          33 :     else if (psImage->nBitsPerSample == 32)
     395          12 :         eDataType = GDT_UInt32;
     396          21 :     else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "R"))
     397          12 :         eDataType = GDT_Float64;
     398           9 :     else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "C"))
     399           9 :         eDataType = GDT_CFloat32;
     400             :     /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2
     401             :      * characters */
     402             :     else
     403             :     {
     404             :         int bOpenUnderlyingDS =
     405           0 :             CPLTestBool(CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
     406           0 :         if (!bOpenUnderlyingDS && psImage->nBitsPerSample > 8 &&
     407           0 :             psImage->nBitsPerSample < 16)
     408             :         {
     409           0 :             if (EQUAL(psImage->szPVType, "SI"))
     410           0 :                 eDataType = GDT_Int16;
     411             :             else
     412           0 :                 eDataType = GDT_UInt16;
     413             :         }
     414             :         else
     415             :         {
     416           0 :             eDataType = GDT_Unknown;
     417           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     418             :                      "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
     419           0 :                      psImage->szPVType, psImage->nBitsPerSample);
     420             :         }
     421             :     }
     422             : 
     423             :     /* -------------------------------------------------------------------- */
     424             :     /*      Work out block size. If the image is all one big block we       */
     425             :     /*      handle via the scanline access API.                             */
     426             :     /* -------------------------------------------------------------------- */
     427      140943 :     if (psImage->nBlocksPerRow == 1 && psImage->nBlocksPerColumn == 1 &&
     428      140733 :         psImage->nBitsPerSample >= 8 && EQUAL(psImage->szIC, "NC"))
     429             :     {
     430      140676 :         bScanlineAccess = TRUE;
     431      140676 :         nBlockXSize = psImage->nBlockWidth;
     432      140676 :         nBlockYSize = 1;
     433             :     }
     434             :     else
     435             :     {
     436         267 :         bScanlineAccess = FALSE;
     437         267 :         nBlockXSize = psImage->nBlockWidth;
     438         267 :         nBlockYSize = psImage->nBlockHeight;
     439             :     }
     440             : 
     441             :     /* -------------------------------------------------------------------- */
     442             :     /*      Do we have a color table?                                       */
     443             :     /* -------------------------------------------------------------------- */
     444      140943 :     poColorTable = NITFMakeColorTable(psImage, psBandInfo);
     445             : 
     446      140943 :     if (psImage->nABPP != 8 && psImage->nABPP != 16 && psImage->nABPP != 32 &&
     447          31 :         psImage->nABPP != 64)
     448             :     {
     449          10 :         SetMetadataItem(GDALMD_NBITS, CPLString().Printf("%d", psImage->nABPP),
     450             :                         GDAL_MDD_IMAGE_STRUCTURE);
     451             :     }
     452             : 
     453      140943 :     if (psImage->nBitsPerSample == 3 || psImage->nBitsPerSample == 5 ||
     454      140929 :         psImage->nBitsPerSample == 6 || psImage->nBitsPerSample == 7)
     455             :     {
     456          28 :         if (nBlockXSize > (INT_MAX - 7) / nBlockYSize)
     457             :         {
     458           0 :             eDataType = GDT_Unknown;
     459             :         }
     460             :         else
     461             :         {
     462          28 :             pUnpackData = static_cast<GByte *>(
     463          28 :                 VSI_MALLOC_VERBOSE(((nBlockXSize * nBlockYSize + 7) / 8) * 8));
     464          28 :             if (pUnpackData == nullptr)
     465           0 :                 eDataType = GDT_Unknown;
     466             :         }
     467             :     }
     468      140943 : }
     469             : 
     470             : /************************************************************************/
     471             : /*                          ~NITFRasterBand()                           */
     472             : /************************************************************************/
     473             : 
     474      281881 : NITFRasterBand::~NITFRasterBand()
     475             : 
     476             : {
     477      140943 :     if (poColorTable != nullptr)
     478         173 :         delete poColorTable;
     479             : 
     480      140943 :     VSIFree(pUnpackData);
     481      281881 : }
     482             : 
     483             : /************************************************************************/
     484             : /*                             IReadBlock()                             */
     485             : /************************************************************************/
     486             : 
     487       20124 : CPLErr NITFRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     488             : 
     489             : {
     490       20124 :     NITFDataset *poGDS = cpl::down_cast<NITFDataset *>(poDS);
     491             : 
     492             :     /* -------------------------------------------------------------------- */
     493             :     /*      Special case for JPEG blocks.                                   */
     494             :     /* -------------------------------------------------------------------- */
     495       20124 :     if (EQUAL(psImage->szIC, "C3") || EQUAL(psImage->szIC, "M3"))
     496             :     {
     497         128 :         CPLErr eErr = poGDS->ReadJPEGBlock(nBlockXOff, nBlockYOff);
     498         128 :         const int nBlockBandSize = psImage->nBlockWidth *
     499         128 :                                    psImage->nBlockHeight *
     500         128 :                                    GDALGetDataTypeSizeBytes(eDataType);
     501             : 
     502         128 :         if (eErr != CE_None)
     503           0 :             return eErr;
     504             : 
     505         128 :         memcpy(pImage, poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
     506             :                nBlockBandSize);
     507             : 
     508         128 :         return eErr;
     509             :     }
     510             : 
     511             :     /* -------------------------------------------------------------------- */
     512             :     /*      Read the line/block                                             */
     513             :     /* -------------------------------------------------------------------- */
     514             :     int nBlockResult;
     515             : 
     516       19996 :     if (bScanlineAccess)
     517             :     {
     518       16551 :         nBlockResult = NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
     519             :     }
     520             :     else
     521             :     {
     522             :         nBlockResult =
     523        3445 :             NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
     524             :     }
     525             : 
     526       19996 :     if (nBlockResult == BLKREAD_OK)
     527             :     {
     528       19420 :         if (psImage->nBitsPerSample % 8)
     529          60 :             Unpack(reinterpret_cast<GByte *>(pImage));
     530             : 
     531       19420 :         return CE_None;
     532             :     }
     533             : 
     534         576 :     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         576 :     if (psImage->bNoDataSet)
     543         576 :         memset(pImage, psImage->nNoDataValue,
     544         576 :                static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
     545         576 :                    psImage->nBlockHeight);
     546             :     else
     547           0 :         memset(pImage, 0,
     548           0 :                static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
     549           0 :                    psImage->nBlockHeight);
     550             : 
     551         576 :     return CE_None;
     552             : }
     553             : 
     554             : /************************************************************************/
     555             : /*                            IWriteBlock()                             */
     556             : /************************************************************************/
     557             : 
     558       17525 : CPLErr NITFRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     559             : 
     560             : {
     561             :     /* -------------------------------------------------------------------- */
     562             :     /*      Write the line/block                                            */
     563             :     /* -------------------------------------------------------------------- */
     564             :     int nBlockResult;
     565             : 
     566       17525 :     if (bScanlineAccess)
     567             :     {
     568       16881 :         nBlockResult = NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
     569             :     }
     570             :     else
     571             :     {
     572             :         nBlockResult =
     573         644 :             NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
     574             :     }
     575             : 
     576       17525 :     if (nBlockResult == BLKREAD_OK)
     577       17525 :         return CE_None;
     578             : 
     579           0 :     return CE_Failure;
     580             : }
     581             : 
     582             : /************************************************************************/
     583             : /*                           GetNoDataValue()                           */
     584             : /************************************************************************/
     585             : 
     586         184 : double NITFRasterBand::GetNoDataValue(int *pbSuccess)
     587             : 
     588             : {
     589         184 :     if (pbSuccess != nullptr)
     590         183 :         *pbSuccess = psImage->bNoDataSet;
     591             : 
     592         184 :     if (psImage->bNoDataSet)
     593          64 :         return psImage->nNoDataValue;
     594             : 
     595         120 :     return GDALPamRasterBand::GetNoDataValue(pbSuccess);
     596             : }
     597             : 
     598             : /************************************************************************/
     599             : /*                       GetColorInterpretation()                       */
     600             : /************************************************************************/
     601             : 
     602         211 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
     603             : 
     604             : {
     605         211 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     606             : 
     607         211 :     if (poColorTable != nullptr)
     608          71 :         return GCI_PaletteIndex;
     609             : 
     610         140 :     if (EQUAL(psBandInfo->szIREPBAND, "R"))
     611          21 :         return GCI_RedBand;
     612         119 :     if (EQUAL(psBandInfo->szIREPBAND, "G"))
     613          21 :         return GCI_GreenBand;
     614          98 :     if (EQUAL(psBandInfo->szIREPBAND, "B"))
     615          21 :         return GCI_BlueBand;
     616          77 :     if (EQUAL(psBandInfo->szIREPBAND, "M"))
     617          71 :         return GCI_GrayIndex;
     618           6 :     if (EQUAL(psBandInfo->szIREPBAND, "Y"))
     619           2 :         return GCI_YCbCr_YBand;
     620           4 :     if (EQUAL(psBandInfo->szIREPBAND, "Cb"))
     621           2 :         return GCI_YCbCr_CbBand;
     622           2 :     if (EQUAL(psBandInfo->szIREPBAND, "Cr"))
     623           2 :         return GCI_YCbCr_CrBand;
     624             : 
     625           0 :     return GCI_Undefined;
     626             : }
     627             : 
     628             : /************************************************************************/
     629             : /*                     NITFSetColorInterpretation()                     */
     630             : /************************************************************************/
     631             : 
     632          33 : CPLErr NITFSetColorInterpretation(NITFImage *psImage, int nBand,
     633             :                                   GDALColorInterp eInterp)
     634             : 
     635             : {
     636          33 :     const char *pszREP = nullptr;
     637             : 
     638          33 :     if (eInterp == GCI_RedBand)
     639          11 :         pszREP = "R";
     640          22 :     else if (eInterp == GCI_GreenBand)
     641          11 :         pszREP = "G";
     642          11 :     else if (eInterp == GCI_BlueBand)
     643          11 :         pszREP = "B";
     644           0 :     else if (eInterp == GCI_GrayIndex)
     645           0 :         pszREP = "M";
     646           0 :     else if (eInterp == GCI_YCbCr_YBand)
     647           0 :         pszREP = "Y";
     648           0 :     else if (eInterp == GCI_YCbCr_CbBand)
     649           0 :         pszREP = "Cb";
     650           0 :     else if (eInterp == GCI_YCbCr_CrBand)
     651           0 :         pszREP = "Cr";
     652           0 :     else if (eInterp == GCI_Undefined)
     653           0 :         return CE_None;
     654             : 
     655          33 :     if (pszREP == nullptr)
     656             :     {
     657           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     658             :                  "Requested color interpretation (%s) not supported in NITF.",
     659             :                  GDALGetColorInterpretationName(eInterp));
     660           0 :         return CE_Failure;
     661             :     }
     662             : 
     663             :     /* -------------------------------------------------------------------- */
     664             :     /*      Where does this go in the file?                                 */
     665             :     /* -------------------------------------------------------------------- */
     666          33 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
     667          33 :     strcpy(psBandInfo->szIREPBAND, pszREP);
     668          33 :     GUIntBig nOffset = NITFIHFieldOffset(psImage, "IREPBAND");
     669             : 
     670          33 :     if (nOffset != 0)
     671          33 :         nOffset += (nBand - 1) * 13;
     672             : 
     673             :     /* -------------------------------------------------------------------- */
     674             :     /*      write it (space padded).                                        */
     675             :     /* -------------------------------------------------------------------- */
     676             :     char szPadded[4];
     677          33 :     strcpy(szPadded, pszREP);
     678          33 :     strcat(szPadded, " ");
     679             : 
     680          33 :     if (nOffset != 0)
     681             :     {
     682          66 :         if (VSIFSeekL(psImage->psFile->fp, nOffset, SEEK_SET) != 0 ||
     683          33 :             VSIFWriteL(reinterpret_cast<void *>(szPadded), 1, 2,
     684          33 :                        psImage->psFile->fp) != 2)
     685             :         {
     686           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     687             :                      "IO failure writing new IREPBAND value to NITF file.");
     688           0 :             return CE_Failure;
     689             :         }
     690             :     }
     691             : 
     692          33 :     return CE_None;
     693             : }
     694             : 
     695             : /************************************************************************/
     696             : /*                       SetColorInterpretation()                       */
     697             : /************************************************************************/
     698             : 
     699          30 : CPLErr NITFRasterBand::SetColorInterpretation(GDALColorInterp eInterp)
     700             : 
     701             : {
     702          30 :     return NITFSetColorInterpretation(psImage, nBand, eInterp);
     703             : }
     704             : 
     705             : /************************************************************************/
     706             : /*                           GetColorTable()                            */
     707             : /************************************************************************/
     708             : 
     709        4976 : GDALColorTable *NITFRasterBand::GetColorTable()
     710             : 
     711             : {
     712        4976 :     return poColorTable;
     713             : }
     714             : 
     715             : /************************************************************************/
     716             : /*                           SetColorTable()                            */
     717             : /************************************************************************/
     718             : 
     719          34 : CPLErr NITFRasterBand::SetColorTable(GDALColorTable *poNewCT)
     720             : 
     721             : {
     722          34 :     NITFDataset *poGDS = cpl::down_cast<NITFDataset *>(poDS);
     723          34 :     if (poGDS->bInLoadXML)
     724           0 :         return GDALPamRasterBand::SetColorTable(poNewCT);
     725             : 
     726          34 :     if (poNewCT == nullptr)
     727           0 :         return CE_Failure;
     728             : 
     729          68 :     std::vector<GByte> abyNITFLUT(768);
     730             : 
     731          34 :     const int nCount = std::min(256, poNewCT->GetColorEntryCount());
     732        7106 :     for (int i = 0; i < nCount; i++)
     733             :     {
     734             :         GDALColorEntry sEntry;
     735             : 
     736        7072 :         poNewCT->GetColorEntryAsRGB(i, &sEntry);
     737        7072 :         abyNITFLUT[i + 256 * 0] = static_cast<GByte>(sEntry.c1);
     738        7072 :         abyNITFLUT[i + 256 * 1] = static_cast<GByte>(sEntry.c2);
     739        7072 :         abyNITFLUT[i + 256 * 2] = static_cast<GByte>(sEntry.c3);
     740             :     }
     741             : 
     742          34 :     if (NITFWriteLUT(psImage, nBand, nCount, abyNITFLUT.data()))
     743          34 :         return CE_None;
     744             : 
     745           0 :     return CE_Failure;
     746             : }
     747             : 
     748             : /************************************************************************/
     749             : /*                               Unpack()                               */
     750             : /************************************************************************/
     751             : 
     752          60 : void NITFRasterBand::Unpack(GByte *pData)
     753             : {
     754          60 :     const int n = nBlockXSize * nBlockYSize;
     755             : 
     756          60 :     GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
     757          60 :     const GByte *pDataSrc = pData;
     758          60 :     if (n < psImage->nBitsPerSample && psImage->nBitsPerSample < 8)
     759             :     {
     760          20 :         memcpy(abyTempData, pData, n);
     761          20 :         pDataSrc = abyTempData;
     762             :     }
     763             : 
     764          60 :     switch (psImage->nBitsPerSample)
     765             :     {
     766          11 :         case 1:
     767             :         {
     768             :             // unpack 1-bit in-place in reverse
     769             :             // DANGER: Non-standard decrement of counter in the test section of
     770             :             // for.
     771     1050510 :             for (int i = n; --i >= 0;)
     772     1050500 :                 pData[i] = (pData[i >> 3] & (0x80 >> (i & 7))) != 0;
     773             : 
     774          11 :             break;
     775             :         }
     776           7 :         case 2:
     777             :         {
     778           7 :             constexpr int s_Shift2[] = {6, 4, 2, 0};
     779             :             // unpack 2-bit in-place in reverse
     780             :             // DANGER: Non-standard decrement of counter in the test section of
     781             :             // for.
     782          37 :             for (int i = n; --i >= 0;)
     783          30 :                 pData[i] =
     784          30 :                     (pData[i >> 2] >> static_cast<GByte>(s_Shift2[i & 3])) &
     785             :                     0x03;
     786             : 
     787           7 :             break;
     788             :         }
     789           7 :         case 4:
     790             :         {
     791           7 :             constexpr int s_Shift4[] = {4, 0};
     792             :             // unpack 4-bit in-place in reverse
     793             :             // DANGER: Non-standard decrement of counter in the test section of
     794             :             // for.
     795          37 :             for (int i = n; --i >= 0;)
     796          30 :                 pData[i] =
     797          30 :                     (pData[i >> 1] >> static_cast<GByte>(s_Shift4[i & 1])) &
     798             :                     0x0f;
     799             : 
     800           7 :             break;
     801             :         }
     802           7 :         case 3:
     803             :         {
     804             :             // unpacks 8 pixels (3 bytes) at time
     805           7 :             int i = 0;
     806           7 :             int k = 0;
     807           8 :             for (; i + 7 < n; i += 8, k += 3)
     808             :             {
     809           1 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
     810           1 :                 pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
     811           1 :                 pUnpackData[i + 2] =
     812           1 :                     ((pDataSrc[k + 0] << 1) & 0x07) | (pDataSrc[k + 1] >> 7);
     813           1 :                 pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
     814           1 :                 pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
     815           1 :                 pUnpackData[i + 5] =
     816           1 :                     ((pDataSrc[k + 1] << 2) & 0x07) | (pDataSrc[k + 2] >> 6);
     817           1 :                 pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
     818           1 :                 pUnpackData[i + 7] = ((pDataSrc[k + 2]) & 0x7);
     819             :             }
     820           7 :             if (i < n)
     821             :             {
     822           6 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
     823           6 :                 if (i + 1 < n)
     824           5 :                     pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
     825           6 :                 if (i + 2 < n)
     826           4 :                     pUnpackData[i + 2] = ((pDataSrc[k + 0] << 1) & 0x07) |
     827           4 :                                          (pDataSrc[k + 1] >> 7);
     828           6 :                 if (i + 3 < n)
     829           3 :                     pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
     830           6 :                 if (i + 4 < n)
     831           2 :                     pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
     832           6 :                 if (i + 5 < n)
     833           1 :                     pUnpackData[i + 5] = ((pDataSrc[k + 1] << 2) & 0x07) |
     834           1 :                                          (pDataSrc[k + 2] >> 6);
     835           6 :                 if (i + 6 < n)
     836           1 :                     pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
     837             :             }
     838             : 
     839           7 :             memcpy(pData, pUnpackData, n);
     840           7 :             break;
     841             :         }
     842           7 :         case 5:
     843             :         {
     844             :             // unpacks 8 pixels (5 bytes) at time
     845           7 :             int i = 0;
     846           7 :             int k = 0;
     847           8 :             for (; i + 7 < n; i += 8, k += 5)
     848             :             {
     849           1 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
     850           1 :                 pUnpackData[i + 1] =
     851           1 :                     ((pDataSrc[k + 0] << 2) & 0x1f) | (pDataSrc[k + 1] >> 6);
     852           1 :                 pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
     853           1 :                 pUnpackData[i + 3] =
     854           1 :                     ((pDataSrc[k + 1] << 4) & 0x1f) | (pDataSrc[k + 2] >> 4);
     855           1 :                 pUnpackData[i + 4] =
     856           1 :                     ((pDataSrc[k + 2] << 1) & 0x1f) | (pDataSrc[k + 3] >> 7);
     857           1 :                 pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
     858           1 :                 pUnpackData[i + 6] =
     859           1 :                     ((pDataSrc[k + 3] << 3) & 0x1f) | (pDataSrc[k + 4] >> 5);
     860           1 :                 pUnpackData[i + 7] = ((pDataSrc[k + 4]) & 0x1f);
     861             :             }
     862           7 :             if (i < n)
     863             :             {
     864           6 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
     865           6 :                 if (i + 1 < n)
     866           5 :                     pUnpackData[i + 1] = ((pDataSrc[k + 0] << 2) & 0x1f) |
     867           5 :                                          (pDataSrc[k + 1] >> 6);
     868           6 :                 if (i + 2 < n)
     869           4 :                     pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
     870           6 :                 if (i + 3 < n)
     871           3 :                     pUnpackData[i + 3] = ((pDataSrc[k + 1] << 4) & 0x1f) |
     872           3 :                                          (pDataSrc[k + 2] >> 4);
     873           6 :                 if (i + 4 < n)
     874           2 :                     pUnpackData[i + 4] = ((pDataSrc[k + 2] << 1) & 0x1f) |
     875           2 :                                          (pDataSrc[k + 3] >> 7);
     876           6 :                 if (i + 5 < n)
     877           1 :                     pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
     878           6 :                 if (i + 6 < n)
     879           1 :                     pUnpackData[i + 6] = ((pDataSrc[k + 3] << 3) & 0x1f) |
     880           1 :                                          (pDataSrc[k + 4] >> 5);
     881             :             }
     882             : 
     883           7 :             memcpy(pData, pUnpackData, n);
     884           7 :             break;
     885             :         }
     886           7 :         case 6:
     887             :         {
     888             :             // unpacks 4 pixels (3 bytes) at time
     889           7 :             int i = 0;
     890           7 :             int k = 0;
     891          12 :             for (; i + 3 < n; i += 4, k += 3)
     892             :             {
     893           5 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
     894           5 :                 pUnpackData[i + 1] =
     895           5 :                     ((pDataSrc[k + 0] << 4) & 0x3f) | (pDataSrc[k + 1] >> 4);
     896           5 :                 pUnpackData[i + 2] =
     897           5 :                     ((pDataSrc[k + 1] << 2) & 0x3f) | (pDataSrc[k + 2] >> 6);
     898           5 :                 pUnpackData[i + 3] = ((pDataSrc[k + 2]) & 0x3f);
     899             :             }
     900           7 :             if (i < n)
     901             :             {
     902           5 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
     903           5 :                 if (i + 1 < n)
     904           3 :                     pUnpackData[i + 1] = ((pDataSrc[k + 0] << 4) & 0x3f) |
     905           3 :                                          (pDataSrc[k + 1] >> 4);
     906           5 :                 if (i + 2 < n)
     907           2 :                     pUnpackData[i + 2] = ((pDataSrc[k + 1] << 2) & 0x3f) |
     908           2 :                                          (pDataSrc[k + 2] >> 6);
     909             :             }
     910             : 
     911           7 :             memcpy(pData, pUnpackData, n);
     912           7 :             break;
     913             :         }
     914           7 :         case 7:
     915             :         {
     916             :             // unpacks 8 pixels (7 bytes) at time
     917           7 :             int i = 0;
     918           7 :             int k = 0;
     919           8 :             for (; i + 7 < n; i += 8, k += 7)
     920             :             {
     921           1 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
     922           1 :                 pUnpackData[i + 1] =
     923           1 :                     ((pDataSrc[k + 0] << 6) & 0x7f) | (pDataSrc[k + 1] >> 2);
     924           1 :                 pUnpackData[i + 2] =
     925           1 :                     ((pDataSrc[k + 1] << 5) & 0x7f) | (pDataSrc[k + 2] >> 3);
     926           1 :                 pUnpackData[i + 3] =
     927           1 :                     ((pDataSrc[k + 2] << 4) & 0x7f) | (pDataSrc[k + 3] >> 4);
     928           1 :                 pUnpackData[i + 4] =
     929           1 :                     ((pDataSrc[k + 3] << 3) & 0x7f) | (pDataSrc[k + 4] >> 5);
     930           1 :                 pUnpackData[i + 5] =
     931           1 :                     ((pDataSrc[k + 4] << 2) & 0x7f) | (pDataSrc[k + 5] >> 6);
     932           1 :                 pUnpackData[i + 6] =
     933           1 :                     ((pDataSrc[k + 5] << 1) & 0x7f) | (pDataSrc[k + 6] >> 7);
     934           1 :                 pUnpackData[i + 7] = ((pDataSrc[k + 6]) & 0x7f);
     935             :             }
     936           7 :             if (i < n)
     937             :             {
     938           6 :                 pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
     939           6 :                 if (i + 1 < n)
     940           5 :                     pUnpackData[i + 1] = ((pDataSrc[k + 0] << 6) & 0x7f) |
     941           5 :                                          (pDataSrc[k + 1] >> 2);
     942           6 :                 if (i + 2 < n)
     943           4 :                     pUnpackData[i + 2] = ((pDataSrc[k + 1] << 5) & 0x7f) |
     944           4 :                                          (pDataSrc[k + 2] >> 3);
     945           6 :                 if (i + 3 < n)
     946           3 :                     pUnpackData[i + 3] = ((pDataSrc[k + 2] << 4) & 0x7f) |
     947           3 :                                          (pDataSrc[k + 3] >> 4);
     948           6 :                 if (i + 4 < n)
     949           2 :                     pUnpackData[i + 4] = ((pDataSrc[k + 3] << 3) & 0x7f) |
     950           2 :                                          (pDataSrc[k + 4] >> 5);
     951           6 :                 if (i + 5 < n)
     952           1 :                     pUnpackData[i + 5] = ((pDataSrc[k + 4] << 2) & 0x7f) |
     953           1 :                                          (pDataSrc[k + 5] >> 6);
     954           6 :                 if (i + 6 < n)
     955           1 :                     pUnpackData[i + 6] = ((pDataSrc[k + 5] << 1) & 0x7f) |
     956           1 :                                          (pDataSrc[k + 6] >> 7);
     957             :             }
     958             : 
     959           7 :             memcpy(pData, pUnpackData, n);
     960           7 :             break;
     961             :         }
     962           7 :         case 12:
     963             :         {
     964           7 :             GByte *pabyImage = reinterpret_cast<GByte *>(pData);
     965           7 :             GUInt16 *panImage = reinterpret_cast<GUInt16 *>(pData);
     966             :             // DANGER: Non-standard decrement of counter in the test section of
     967             :             // for.
     968          37 :             for (int i = n; --i >= 0;)
     969             :             {
     970          30 :                 const long iOffset = i * 3 / 2;
     971          30 :                 if (i % 2 == 0)
     972          17 :                     panImage[i] = pabyImage[iOffset] +
     973          17 :                                   (pabyImage[iOffset + 1] & 0xf0) * 16;
     974             :                 else
     975          13 :                     panImage[i] = (pabyImage[iOffset] & 0x0f) * 16 +
     976          13 :                                   (pabyImage[iOffset + 1] & 0xf0) / 16 +
     977          13 :                                   (pabyImage[iOffset + 1] & 0x0f) * 256;
     978             :             }
     979             : 
     980           7 :             break;
     981             :         }
     982             :     }
     983          60 : }
     984             : 
     985             : /************************************************************************/
     986             : /* ==================================================================== */
     987             : /*                       NITFWrapperRasterBand                          */
     988             : /* ==================================================================== */
     989             : /************************************************************************/
     990             : 
     991             : /************************************************************************/
     992             : /*                       NITFWrapperRasterBand()                        */
     993             : /************************************************************************/
     994             : 
     995          99 : NITFWrapperRasterBand::NITFWrapperRasterBand(NITFDataset *poDSIn,
     996             :                                              GDALRasterBand *poBaseBandIn,
     997          99 :                                              int nBandIn)
     998         198 :     : poBaseBand(poBaseBandIn), eInterp(poBaseBandIn->GetColorInterpretation()),
     999         297 :       bIsJPEG(poBaseBandIn->GetDataset() != nullptr &&
    1000         198 :               poBaseBandIn->GetDataset()->GetDriver() != nullptr &&
    1001          99 :               EQUAL(poBaseBandIn->GetDataset()->GetDriver()->GetDescription(),
    1002          99 :                     "JPEG"))
    1003             : {
    1004          99 :     poDS = poDSIn;
    1005          99 :     nBand = nBandIn;
    1006          99 :     poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    1007          99 :     eDataType = poBaseBandIn->GetRasterDataType();
    1008          99 : }
    1009             : 
    1010             : /************************************************************************/
    1011             : /*                       ~NITFWrapperRasterBand()                       */
    1012             : /************************************************************************/
    1013             : 
    1014         198 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
    1015             : {
    1016          99 :     if (poColorTable != nullptr)
    1017           0 :         delete poColorTable;
    1018         198 : }
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                      RefUnderlyingRasterBand()                       */
    1022             : /************************************************************************/
    1023             : 
    1024             : /* We don't need ref-counting. Just return the base band */
    1025         572 : GDALRasterBand *NITFWrapperRasterBand::RefUnderlyingRasterBand()
    1026             : {
    1027         572 :     return poBaseBand;
    1028             : }
    1029             : 
    1030             : /************************************************************************/
    1031             : /*                           GetColorTable()                            */
    1032             : /************************************************************************/
    1033             : 
    1034          16 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
    1035             : {
    1036          16 :     return poColorTable;
    1037             : }
    1038             : 
    1039             : /************************************************************************/
    1040             : /*                   SetColorTableFromNITFBandInfo()                    */
    1041             : /************************************************************************/
    1042             : 
    1043           0 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
    1044             : {
    1045           0 :     NITFDataset *poGDS = cpl::down_cast<NITFDataset *>(poDS);
    1046           0 :     poColorTable = NITFMakeColorTable(poGDS->psImage,
    1047           0 :                                       poGDS->psImage->pasBandInfo + nBand - 1);
    1048           0 : }
    1049             : 
    1050             : /************************************************************************/
    1051             : /*                       GetColorInterpretation()                       */
    1052             : /************************************************************************/
    1053             : 
    1054          60 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
    1055             : {
    1056          60 :     return eInterp;
    1057             : }
    1058             : 
    1059             : /************************************************************************/
    1060             : /*                       SetColorInterpretation()                       */
    1061             : /************************************************************************/
    1062             : 
    1063         100 : CPLErr NITFWrapperRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
    1064             : {
    1065         100 :     this->eInterp = eInterpIn;
    1066         100 :     if (poBaseBand->GetDataset() != nullptr &&
    1067         200 :         poBaseBand->GetDataset()->GetDriver() != nullptr &&
    1068         100 :         EQUAL(poBaseBand->GetDataset()->GetDriver()->GetDescription(),
    1069             :               "JP2ECW"))
    1070          19 :         poBaseBand->SetColorInterpretation(eInterp);
    1071         100 :     return CE_None;
    1072             : }
    1073             : 
    1074             : /************************************************************************/
    1075             : /*                          GetOverviewCount()                          */
    1076             : /************************************************************************/
    1077             : 
    1078           6 : int NITFWrapperRasterBand::GetOverviewCount()
    1079             : {
    1080           6 :     if (bIsJPEG)
    1081             :     {
    1082           2 :         if ((cpl::down_cast<NITFDataset *>(poDS))
    1083           2 :                 ->ExposeUnderlyingJPEGDatasetOverviews())
    1084           0 :             return NITFProxyPamRasterBand::GetOverviewCount();
    1085             : 
    1086           2 :         return GDALPamRasterBand::GetOverviewCount();
    1087             :     }
    1088             : 
    1089           4 :     return NITFProxyPamRasterBand::GetOverviewCount();
    1090             : }
    1091             : 
    1092             : /************************************************************************/
    1093             : /*                            GetOverview()                             */
    1094             : /************************************************************************/
    1095             : 
    1096           3 : GDALRasterBand *NITFWrapperRasterBand::GetOverview(int iOverview)
    1097             : {
    1098           3 :     if (bIsJPEG)
    1099             :     {
    1100           1 :         if ((cpl::down_cast<NITFDataset *>(poDS))
    1101           1 :                 ->ExposeUnderlyingJPEGDatasetOverviews())
    1102           0 :             return NITFProxyPamRasterBand::GetOverview(iOverview);
    1103             : 
    1104           1 :         return GDALPamRasterBand::GetOverview(iOverview);
    1105             :     }
    1106             : 
    1107           2 :     return NITFProxyPamRasterBand::GetOverview(iOverview);
    1108             : }
    1109             : 
    1110             : /************************************************************************/
    1111             : /*                       NITFComplexRasterBand()                        */
    1112             : /************************************************************************/
    1113             : 
    1114           5 : NITFComplexRasterBand::NITFComplexRasterBand(NITFDataset *poDSIn,
    1115             :                                              GDALRasterBand *poBandI,
    1116             :                                              GDALRasterBand *poBandQ,
    1117           5 :                                              int nIBand, int nQBand)
    1118           5 :     : NITFRasterBand(poDSIn, nIBand)
    1119             : {
    1120             : 
    1121           5 :     CPLAssert(poBandI->GetRasterDataType() == poBandQ->GetRasterDataType());
    1122           5 :     underlyingDataType = poBandI->GetRasterDataType();
    1123             : 
    1124             :     //add the I and Q bands to an intermediate dataset
    1125           5 :     poIntermediateDS = std::make_unique<NITFDataset>();
    1126           5 :     poIntermediateDS->nRasterXSize = poDSIn->nRasterXSize;
    1127           5 :     poIntermediateDS->nRasterYSize = poDSIn->nRasterYSize;
    1128           5 :     poIntermediateDS->eAccess = poDSIn->eAccess;
    1129             : 
    1130           5 :     poIntermediateDS->SetBand(nIBand, poBandI);
    1131           5 :     poIntermediateDS->SetBand(nQBand, poBandQ);
    1132             : 
    1133           5 :     anBandMap[0] = nIBand;
    1134           5 :     anBandMap[1] = nQBand;
    1135             : 
    1136             :     //set the new datatype
    1137           5 :     switch (underlyingDataType)
    1138             :     {
    1139           0 :         case GDT_Int16:
    1140           0 :             eDataType = GDT_CInt16;
    1141           0 :             break;
    1142           0 :         case GDT_Int32:
    1143           0 :             eDataType = GDT_CInt32;
    1144           0 :             break;
    1145           5 :         case GDT_Float32:
    1146           5 :             eDataType = GDT_CFloat32;
    1147           5 :             break;
    1148           0 :         case GDT_Float64:
    1149           0 :             eDataType = GDT_CFloat64;
    1150           0 :             break;
    1151           0 :         default:
    1152           0 :             eDataType = GDT_Unknown;
    1153           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1154             :                      "Unsupported complex datatype");
    1155           0 :             break;
    1156             :     }
    1157             : 
    1158           5 :     complexDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1159           5 :     underlyingDataTypeSize = GDALGetDataTypeSizeBytes(underlyingDataType);
    1160           5 :     CPLAssert(underlyingDataTypeSize * 2 == complexDataTypeSize);
    1161             : 
    1162           5 :     poBandI->GetBlockSize(&nBlockXSize, &nBlockYSize);
    1163           5 : }
    1164             : 
    1165             : /************************************************************************/
    1166             : /*                             IReadBlock()                             */
    1167             : /************************************************************************/
    1168             : 
    1169          40 : CPLErr NITFComplexRasterBand::IBlockIO(int nBlockXOff, int nBlockYOff,
    1170             :                                        void *pImage, GDALRWFlag rwFlag)
    1171             : 
    1172             : {
    1173             :     /* -------------------------------------------------------------------- */
    1174             :     /*      If the last strip is partial, we need to avoid                  */
    1175             :     /*      over-requesting.  We also need to initialize the extra part     */
    1176             :     /*      of the block to zero.                                           */
    1177             :     /* -------------------------------------------------------------------- */
    1178          40 :     const int nYOff = nBlockYOff * nBlockYSize;
    1179          40 :     const int nRequestYSize = std::min(nBlockYSize, nRasterYSize - nYOff);
    1180             : 
    1181             :     /*-------------------------------------------------------------------- */
    1182             :     /*      If the input imagery is tiled, also need to avoid over-        */
    1183             :     /*      requesting in the X-direction.                                 */
    1184             :     /* ------------------------------------------------------------------- */
    1185          40 :     const int nXOff = nBlockXOff * nBlockXSize;
    1186          40 :     const int nRequestXSize = std::min(nBlockXSize, nRasterXSize - nXOff);
    1187             : 
    1188          40 :     if (rwFlag == GF_Read &&
    1189          40 :         (nRequestXSize < nBlockXSize || nRequestYSize < nBlockYSize))
    1190             :     {
    1191           0 :         memset(pImage, 0,
    1192           0 :                static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
    1193           0 :                    nBlockXSize * nBlockYSize);
    1194             :     }
    1195             : 
    1196             :     //read/write both bands with interleaved pixels
    1197          40 :     return poIntermediateDS->RasterIO(
    1198          40 :         rwFlag, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
    1199             :         nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
    1200          40 :         underlyingDataType, 2, &anBandMap[0], complexDataTypeSize,
    1201          40 :         static_cast<GSpacing>(complexDataTypeSize) * nBlockXSize,
    1202          80 :         underlyingDataTypeSize, nullptr);
    1203             : }
    1204             : 
    1205             : /************************************************************************/
    1206             : /*                             IReadBlock()                             */
    1207             : /************************************************************************/
    1208             : 
    1209          40 : CPLErr NITFComplexRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
    1210             :                                          void *pImage)
    1211             : 
    1212             : {
    1213          40 :     return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Read);
    1214             : }
    1215             : 
    1216             : /************************************************************************/
    1217             : /*                            IWriteBlock()                             */
    1218             : /************************************************************************/
    1219             : 
    1220           0 : CPLErr NITFComplexRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
    1221             :                                           void *pImage)
    1222             : 
    1223             : {
    1224           0 :     return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Write);
    1225             : }

Generated by: LCOV version 1.14