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

Generated by: LCOV version 1.14