LCOV - code coverage report
Current view: top level - frmts/openjpeg - opjdatasetbase.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 381 479 79.5 %
Date: 2026-06-19 21:24:00 Functions: 36 45 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Author:   Aaron Boxer, <boxerab at protonmail dot com>
       4             :  *
       5             :  ******************************************************************************
       6             :  * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys dot com>
       7             :  * Copyright (c) 2015, European Union (European Environment Agency)
       8             :  * Copyright (c) 2023, Grok Image Compression Inc.
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : #pragma once
      13             : 
      14             : #include <limits>
      15             : #include <algorithm>
      16             : 
      17             : /* This file is to be used with openjpeg 2.1 or later */
      18             : #ifdef __clang__
      19             : #pragma clang diagnostic push
      20             : #pragma clang diagnostic ignored "-Wunknown-pragmas"
      21             : #pragma clang diagnostic ignored "-Wdocumentation"
      22             : #endif
      23             : 
      24             : #include <openjpeg.h>
      25             : #include <opj_config.h>
      26             : 
      27             : #ifdef __clang__
      28             : #pragma clang diagnostic pop
      29             : #endif
      30             : 
      31             : #define IS_OPENJPEG_OR_LATER(major, minor, patch)                              \
      32             :     ((OPJ_VERSION_MAJOR * 10000 + OPJ_VERSION_MINOR * 100 +                    \
      33             :       OPJ_VERSION_BUILD) >= ((major) * 10000 + (minor) * 100 + (patch)))
      34             : 
      35             : /************************************************************************/
      36             : /*                    JP2OpenJPEG_WarningCallback()                     */
      37             : /************************************************************************/
      38             : 
      39           0 : static void JP2OpenJPEG_WarningCallback(const char *pszMsg,
      40             :                                         CPL_UNUSED void *unused)
      41             : {
      42           0 :     if (strcmp(pszMsg, "No incltree created.\n") == 0 ||
      43           0 :         strcmp(pszMsg, "No imsbtree created.\n") == 0 ||
      44           0 :         strcmp(pszMsg, "tgt_create tree->numnodes == 0, no tree created.\n") ==
      45             :             0)
      46             :     {
      47             :         // Ignore warnings related to empty tag-trees. There's nothing wrong
      48             :         // about that.
      49             :         // Fixed submitted upstream with
      50             :         // https://github.com/uclouvain/openjpeg/pull/893
      51           0 :         return;
      52             :     }
      53           0 :     if (strcmp(pszMsg, "Empty SOT marker detected: Psot=12.\n") == 0)
      54             :     {
      55             :         static int bWarningEmitted = FALSE;
      56           0 :         if (bWarningEmitted)
      57           0 :             return;
      58           0 :         bWarningEmitted = TRUE;
      59             :     }
      60           0 :     if (strcmp(pszMsg, "JP2 box which are after the codestream will not be "
      61             :                        "read by this function.\n") == 0)
      62             :     {
      63           0 :         return;
      64             :     }
      65             : 
      66           0 :     std::string osMsg(pszMsg);
      67           0 :     if (!osMsg.empty() && osMsg.back() == '\n')
      68           0 :         osMsg.resize(osMsg.size() - 1);
      69           0 :     CPLError(CE_Warning, CPLE_AppDefined, "%s", osMsg.c_str());
      70             : }
      71             : 
      72             : /************************************************************************/
      73             : /*                      JP2OpenJPEG_InfoCallback()                      */
      74             : /************************************************************************/
      75             : 
      76       10756 : static void JP2OpenJPEG_InfoCallback(const char *pszMsg,
      77             :                                      CPL_UNUSED void *unused)
      78             : {
      79       21512 :     std::string osMsg(pszMsg);
      80       10756 :     if (!osMsg.empty() && osMsg.back() == '\n')
      81       10756 :         osMsg.resize(osMsg.size() - 1);
      82       10756 :     CPLDebug("JP2OpenJPEG", "info: %s", osMsg.c_str());
      83       10756 : }
      84             : 
      85             : /************************************************************************/
      86             : /*                     JP2OpenJPEG_ErrorCallback()                      */
      87             : /************************************************************************/
      88             : 
      89           6 : static void JP2OpenJPEG_ErrorCallback(const char *pszMsg,
      90             :                                       CPL_UNUSED void *unused)
      91             : {
      92           6 :     CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
      93           6 : }
      94             : 
      95             : /************************************************************************/
      96             : /*                          JP2Dataset_Read()                           */
      97             : /************************************************************************/
      98             : 
      99        3758 : static size_t JP2Dataset_Read(void *pBuffer, size_t nBytes, void *pUserData)
     100             : {
     101        3758 :     JP2File *psJP2File = static_cast<JP2File *>(pUserData);
     102             :     size_t nRet =
     103        3758 :         static_cast<size_t>(VSIFReadL(pBuffer, 1, nBytes, psJP2File->fp_));
     104             : #ifdef DEBUG_IO
     105             :     CPLDebug(OPJCodecWrapper::debugId(),
     106             :              "JP2Dataset_Read(" CPL_FRMT_GUIB ") = " CPL_FRMT_GUIB,
     107             :              static_cast<GUIntBig>(nBytes), static_cast<GUIntBig>(nRet));
     108             : #endif
     109        3758 :     if (nRet == 0)
     110           2 :         nRet = static_cast<size_t>(-1);
     111             : 
     112        3758 :     return nRet;
     113             : }
     114             : 
     115             : /************************************************************************/
     116             : /*                          JP2Dataset_Write()                          */
     117             : /************************************************************************/
     118             : 
     119         251 : static size_t JP2Dataset_Write(void *pBuffer, size_t nBytes, void *pUserData)
     120             : {
     121         251 :     JP2File *psJP2File = static_cast<JP2File *>(pUserData);
     122             :     size_t nRet =
     123         251 :         static_cast<size_t>(VSIFWriteL(pBuffer, 1, nBytes, psJP2File->fp_));
     124             : #ifdef DEBUG_IO
     125             :     CPLDebug(OPJCodecWrapper::debugId(),
     126             :              "JP2Dataset_Write(" CPL_FRMT_GUIB ") = " CPL_FRMT_GUIB,
     127             :              static_cast<GUIntBig>(nBytes), static_cast<GUIntBig>(nRet));
     128             : #endif
     129         251 :     if (nRet != nBytes)
     130          10 :         return static_cast<size_t>(-1);
     131         241 :     return nRet;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                          JP2Dataset_Seek()                           */
     136             : /************************************************************************/
     137             : 
     138         581 : static OPJ_BOOL JP2Dataset_Seek(int64_t nBytes, void *pUserData)
     139             : {
     140         581 :     JP2File *psJP2File = static_cast<JP2File *>(pUserData);
     141             : #ifdef DEBUG_IO
     142             :     CPLDebug(OPJCodecWrapper::debugId(), "JP2Dataset_Seek(" CPL_FRMT_GUIB ")",
     143             :              static_cast<GUIntBig>(nBytes));
     144             : #endif
     145         581 :     return VSIFSeekL(psJP2File->fp_, psJP2File->nBaseOffset + nBytes,
     146         581 :                      SEEK_SET) == 0;
     147             : }
     148             : 
     149             : /************************************************************************/
     150             : /*                          JP2Dataset_Skip()                           */
     151             : /************************************************************************/
     152             : 
     153        1919 : static int64_t JP2Dataset_Skip(int64_t nBytes, void *pUserData)
     154             : {
     155        1919 :     JP2File *psJP2File = static_cast<JP2File *>(pUserData);
     156        1919 :     vsi_l_offset nOffset = VSIFTellL(psJP2File->fp_);
     157        1919 :     nOffset += nBytes;
     158             : #ifdef DEBUG_IO
     159             :     CPLDebug(OPJCodecWrapper::debugId(),
     160             :              "JP2Dataset_Skip(" CPL_FRMT_GUIB " -> " CPL_FRMT_GUIB ")",
     161             :              static_cast<GUIntBig>(nBytes), static_cast<GUIntBig>(nOffset));
     162             : #endif
     163        1919 :     VSIFSeekL(psJP2File->fp_, nOffset, SEEK_SET);
     164        1919 :     return nBytes;
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /* ==================================================================== */
     169             : /*                           OPJCodecWrapper                            */
     170             : /* ==================================================================== */
     171             : /************************************************************************/
     172             : 
     173             : struct OPJCodecWrapper
     174             : {
     175             :     typedef opj_codec_t jp2_codec;
     176             :     typedef opj_image_t jp2_image;
     177             :     typedef opj_stream_t jp2_stream;
     178             : 
     179             :     typedef opj_image_cmptparm_t jp2_image_comp_param;
     180             :     typedef opj_image_comp_t jp2_image_comp;
     181             : 
     182             :     OPJCodecWrapper() = default;
     183             : 
     184           0 :     explicit OPJCodecWrapper(OPJCodecWrapper *rhs)
     185           0 :         : pCodec(rhs->pCodec), pStream(rhs->pStream), psImage(rhs->psImage),
     186           0 :           pasBandParams(rhs->pasBandParams), psJP2File(rhs->psJP2File)
     187             :     {
     188           0 :         rhs->pCodec = nullptr;
     189           0 :         rhs->pStream = nullptr;
     190           0 :         rhs->psImage = nullptr;
     191           0 :         rhs->pasBandParams = nullptr;
     192           0 :         rhs->psJP2File = nullptr;
     193           0 :     }
     194             : 
     195        2185 :     ~OPJCodecWrapper(void)
     196        2185 :     {
     197        2185 :         free();
     198        2185 :     }
     199             : 
     200        1157 :     void open(VSILFILE *fp, vsi_l_offset offset)
     201             :     {
     202        1157 :         psJP2File = static_cast<JP2File *>(CPLMalloc(sizeof(JP2File)));
     203        1157 :         psJP2File->fp_ = fp;
     204        1157 :         psJP2File->nBaseOffset = offset;
     205        1157 :     }
     206             : 
     207         252 :     void open(VSILFILE *fp)
     208             :     {
     209         252 :         psJP2File = static_cast<JP2File *>(CPLMalloc(sizeof(JP2File)));
     210         252 :         psJP2File->fp_ = fp;
     211         252 :         psJP2File->nBaseOffset = VSIFTellL(fp);
     212         252 :     }
     213             : 
     214           0 :     void transfer(OPJCodecWrapper *rhs)
     215             :     {
     216           0 :         pCodec = rhs->pCodec;
     217           0 :         rhs->pCodec = nullptr;
     218           0 :         psImage = rhs->psImage;
     219           0 :         rhs->psImage = nullptr;
     220           0 :         psJP2File = rhs->psJP2File;
     221           0 :         rhs->psJP2File = nullptr;
     222           0 :     }
     223             : 
     224       12770 :     static int cvtenum(JP2_ENUM enumeration)
     225             :     {
     226       12770 :         switch (enumeration)
     227             :         {
     228        1909 :             case JP2_CLRSPC_UNKNOWN:
     229        1909 :                 return OPJ_CLRSPC_UNKNOWN;
     230             :                 break;
     231        1252 :             case JP2_CLRSPC_SRGB:
     232        1252 :                 return OPJ_CLRSPC_SRGB;
     233             :                 break;
     234        2202 :             case JP2_CLRSPC_GRAY:
     235        2202 :                 return OPJ_CLRSPC_GRAY;
     236             :                 break;
     237         112 :             case JP2_CLRSPC_SYCC:
     238         112 :                 return OPJ_CLRSPC_SYCC;
     239             :                 break;
     240        1774 :             case JP2_CODEC_J2K:
     241        1774 :                 return OPJ_CODEC_J2K;
     242             :                 break;
     243        5521 :             case JP2_CODEC_JP2:
     244        5521 :                 return OPJ_CODEC_JP2;
     245             :                 break;
     246           0 :             default:
     247           0 :                 return INT_MAX;
     248             :                 break;
     249             :         }
     250             :     }
     251             : 
     252          35 :     std::string getComment(void)
     253             :     {
     254             :         (void)this;
     255          70 :         std::string osComment = "Created by OpenJPEG version ";
     256             : 
     257          70 :         return osComment + opj_version();
     258             :     }
     259             : 
     260         760 :     void updateStrict(CPL_UNUSED bool strict)
     261             :     {
     262             :         // prevent linter from treating this as potential static method
     263             :         (void)this;
     264             : #if IS_OPENJPEG_OR_LATER(2, 5, 0)
     265             :         if (!strict)
     266             :             opj_decoder_set_strict_mode(pCodec, false);
     267             : #endif
     268         760 :     }
     269             : 
     270       20587 :     static const char *debugId(void)
     271             :     {
     272       20587 :         return "OPENJPEG";
     273             :     }
     274             : 
     275         262 :     void allocComponentParams(int nBands)
     276             :     {
     277         262 :         pasBandParams = static_cast<jp2_image_comp_param *>(
     278         262 :             CPLMalloc(nBands * sizeof(jp2_image_comp_param)));
     279         262 :     }
     280             : 
     281        3265 :     void free(void)
     282             :     {
     283        3265 :         if (pStream)
     284        1409 :             opj_stream_destroy(pStream);
     285        3265 :         pStream = nullptr;
     286        3265 :         if (pCodec)
     287        1409 :             opj_destroy_codec(pCodec);
     288        3265 :         pCodec = nullptr;
     289        3265 :         if (psImage)
     290        1405 :             opj_image_destroy(psImage);
     291        3265 :         psImage = nullptr;
     292             : 
     293        3265 :         ::free(pasBandParams);
     294        3265 :         pasBandParams = nullptr;
     295             : 
     296        3265 :         CPLFree(psJP2File);
     297        3265 :         psJP2File = nullptr;
     298        3265 :     }
     299             : 
     300         760 :     static bool preferPerBlockDeCompress(void)
     301             :     {
     302         760 :         return true;
     303             :     }
     304             : 
     305         611 :     static uint32_t stride(jp2_image_comp *comp)
     306             :     {
     307         611 :         return comp->w;
     308             :     }
     309             : 
     310         449 :     static GDALDataType getDataType(CPL_UNUSED jp2_image_comp *comp)
     311             :     {
     312         449 :         return GDT_Int32;
     313             :     }
     314             : 
     315         766 :     bool setUpDecompress(CPL_UNUSED int numThreads,
     316             :                          CPL_UNUSED char *pszFilename,
     317             :                          vsi_l_offset nCodeStreamLength, uint32_t *nTileW,
     318             :                          uint32_t *nTileH, int *numResolutions)
     319             :     {
     320             : 
     321         766 :         OPJCodecWrapper codec;
     322         766 :         pCodec = opj_create_decompress(static_cast<OPJ_CODEC_FORMAT>(
     323         766 :             OPJCodecWrapper::cvtenum(JP2_CODEC_J2K)));
     324         766 :         if (pCodec == nullptr)
     325           0 :             return false;
     326             : 
     327         766 :         opj_set_info_handler(pCodec, JP2OpenJPEG_InfoCallback, nullptr);
     328         766 :         opj_set_warning_handler(pCodec, JP2OpenJPEG_WarningCallback, nullptr);
     329         766 :         opj_set_error_handler(pCodec, JP2OpenJPEG_ErrorCallback, nullptr);
     330             : 
     331             :         opj_dparameters_t decompressParams;
     332         766 :         opj_set_default_decoder_parameters(&decompressParams);
     333         766 :         if (!opj_setup_decoder(pCodec, &decompressParams))
     334             :         {
     335           0 :             opj_destroy_codec(pCodec);
     336           0 :             return false;
     337             :         }
     338             : 
     339         766 :         if (getenv("OPJ_NUM_THREADS") == nullptr)
     340             :         {
     341         766 :             opj_codec_set_threads(pCodec, numThreads);
     342             :         }
     343             : 
     344         766 :         pStream = CreateReadStream(psJP2File, nCodeStreamLength);
     345         766 :         if (pStream == nullptr)
     346             :         {
     347           0 :             CPLError(CE_Failure, CPLE_AppDefined, "CreateReadStream() failed");
     348           0 :             free();
     349           0 :             CPLFree(psJP2File);
     350           0 :             return false;
     351             :         }
     352        1532 :         if (VSIFSeekL(psJP2File->fp_, psJP2File->nBaseOffset, SEEK_SET) == -1 ||
     353         766 :             !opj_read_header(pStream, pCodec, &psImage))
     354             :         {
     355           4 :             CPLError(CE_Failure, CPLE_AppDefined, "opj_read_header() failed");
     356           4 :             free();
     357           4 :             CPLFree(psJP2File);
     358           4 :             return false;
     359             :         }
     360             : 
     361         762 :         auto pCodeStreamInfo = opj_get_cstr_info(pCodec);
     362         762 :         *nTileW = pCodeStreamInfo->tdx;
     363         762 :         *nTileH = pCodeStreamInfo->tdy;
     364             : #ifdef DEBUG
     365             :         uint32_t nX0, nY0;
     366             :         uint32_t nTilesX, nTilesY;
     367         762 :         nX0 = pCodeStreamInfo->tx0;
     368         762 :         nY0 = pCodeStreamInfo->ty0;
     369         762 :         nTilesX = pCodeStreamInfo->tw;
     370         762 :         nTilesY = pCodeStreamInfo->th;
     371         762 :         int mct = pCodeStreamInfo->m_default_tile_info.mct;
     372             : #endif
     373         762 :         *numResolutions =
     374         762 :             pCodeStreamInfo->m_default_tile_info.tccp_info[0].numresolutions;
     375         762 :         opj_destroy_cstr_info(&pCodeStreamInfo);
     376         762 :         if (psImage == nullptr)
     377             :         {
     378           0 :             free();
     379           0 :             CPLFree(psJP2File);
     380           0 :             return false;
     381             :         }
     382             : #ifdef DEBUG
     383         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nX0 = %u", nX0);
     384         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nY0 = %u", nY0);
     385         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nTileW = %u", *nTileW);
     386         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nTileH = %u", *nTileH);
     387         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nTilesX = %u", nTilesX);
     388         762 :         CPLDebug(OPJCodecWrapper::debugId(), "nTilesY = %u", nTilesY);
     389         762 :         CPLDebug(OPJCodecWrapper::debugId(), "mct = %d", mct);
     390         762 :         CPLDebug(OPJCodecWrapper::debugId(), "psImage->x0 = %u", psImage->x0);
     391         762 :         CPLDebug(OPJCodecWrapper::debugId(), "psImage->y0 = %u", psImage->y0);
     392         762 :         CPLDebug(OPJCodecWrapper::debugId(), "psImage->x1 = %u", psImage->x1);
     393         762 :         CPLDebug(OPJCodecWrapper::debugId(), "psImage->y1 = %u", psImage->y1);
     394         762 :         CPLDebug(OPJCodecWrapper::debugId(), "psImage->numcomps = %d",
     395         762 :                  psImage->numcomps);
     396             :         // CPLDebug(OPJCodecWrapper::debugId(), "psImage->color_space = %d", psImage->color_space);
     397         762 :         CPLDebug(OPJCodecWrapper::debugId(), "numResolutions = %d",
     398             :                  *numResolutions);
     399        1700 :         for (int i = 0; i < static_cast<int>(psImage->numcomps); i++)
     400             :         {
     401         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].dx = %u",
     402         938 :                      i, psImage->comps[i].dx);
     403         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].dy = %u",
     404         938 :                      i, psImage->comps[i].dy);
     405         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].x0 = %u",
     406         938 :                      i, psImage->comps[i].x0);
     407         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].y0 = %u",
     408         938 :                      i, psImage->comps[i].y0);
     409         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].w = %u", i,
     410         938 :                      psImage->comps[i].w);
     411         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].h = %u", i,
     412         938 :                      psImage->comps[i].h);
     413         938 :             CPLDebug(OPJCodecWrapper::debugId(),
     414             :                      "psImage->comps[%d].resno_decoded = %d", i,
     415         938 :                      psImage->comps[i].resno_decoded);
     416         938 :             CPLDebug(OPJCodecWrapper::debugId(),
     417             :                      "psImage->comps[%d].factor = %d", i,
     418         938 :                      psImage->comps[i].factor);
     419         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].prec = %d",
     420         938 :                      i, psImage->comps[i].prec);
     421         938 :             CPLDebug(OPJCodecWrapper::debugId(), "psImage->comps[%d].sgnd = %d",
     422         938 :                      i, psImage->comps[i].sgnd);
     423             :         }
     424             : #endif
     425         762 :         if (psImage->x1 <= psImage->x0 || psImage->y1 <= psImage->y0 ||
     426         762 :             psImage->numcomps == 0 || (psImage->comps[0].w >> 31) != 0 ||
     427         761 :             (psImage->comps[0].h >> 31) != 0 || (*nTileW >> 31) != 0 ||
     428         760 :             (*nTileH >> 31) != 0 ||
     429         760 :             psImage->comps[0].w != psImage->x1 - psImage->x0 ||
     430         760 :             psImage->comps[0].h != psImage->y1 - psImage->y0)
     431             :         {
     432           2 :             CPLDebug(OPJCodecWrapper::debugId(),
     433             :                      "Unable to handle that image (1)");
     434           2 :             free();
     435           2 :             CPLFree(psJP2File);
     436           2 :             return false;
     437             :         }
     438         760 :         return true;
     439             :     }
     440             : 
     441         252 :     static bool preferPerTileCompress(void)
     442             :     {
     443         252 :         return true;
     444             :     }
     445             : 
     446         252 :     bool initCompress(CSLConstList papszOptions,
     447             :                       const std::vector<double> &adfRates, int nBlockXSize,
     448             :                       int nBlockYSize, bool bIsIrreversible,
     449             :                       int nNumResolutions, JP2_PROG_ORDER eProgOrder, int bYCC,
     450             :                       int nCblockW, int nCblockH, int bYCBCR420, int bProfile1,
     451             :                       int nBands, int nXSize, int nYSize,
     452             :                       JP2_COLOR_SPACE eColorSpace,
     453             :                       [[maybe_unused]] int numThreads)
     454             :     {
     455             :         int bSOP =
     456         252 :             CPLTestBool(CSLFetchNameValueDef(papszOptions, "SOP", "FALSE"));
     457             :         int bEPH =
     458         252 :             CPLTestBool(CSLFetchNameValueDef(papszOptions, "EPH", "FALSE"));
     459             : 
     460             :         opj_cparameters_t compressParams;
     461         252 :         opj_set_default_encoder_parameters(&compressParams);
     462         252 :         if (bSOP)
     463           0 :             compressParams.csty |= 0x02;
     464         252 :         if (bEPH)
     465           0 :             compressParams.csty |= 0x04;
     466         252 :         compressParams.cp_disto_alloc = 1;
     467         252 :         compressParams.tcp_numlayers = static_cast<int>(adfRates.size());
     468         580 :         for (size_t i = 0; i < adfRates.size(); i++)
     469         328 :             compressParams.tcp_rates[i] = static_cast<float>(adfRates[i]);
     470         252 :         compressParams.cp_tx0 = 0;
     471         252 :         compressParams.cp_ty0 = 0;
     472         252 :         compressParams.tile_size_on = TRUE;
     473         252 :         compressParams.cp_tdx = nBlockXSize;
     474         252 :         compressParams.cp_tdy = nBlockYSize;
     475         252 :         compressParams.irreversible = bIsIrreversible;
     476         252 :         compressParams.numresolution = nNumResolutions;
     477         252 :         compressParams.prog_order = static_cast<OPJ_PROG_ORDER>(eProgOrder);
     478         252 :         compressParams.tcp_mct = static_cast<char>(bYCC);
     479         252 :         compressParams.cblockw_init = nCblockW;
     480         252 :         compressParams.cblockh_init = nCblockH;
     481         252 :         compressParams.mode = 0;
     482             : 
     483         504 :         std::string osComment;
     484         252 :         const char *pszCOM = CSLFetchNameValue(papszOptions, "COMMENT");
     485         252 :         if (pszCOM)
     486             :         {
     487           1 :             osComment = pszCOM;
     488           1 :             compressParams.cp_comment = &osComment[0];
     489             :         }
     490         251 :         else if (!bIsIrreversible)
     491             :         {
     492          35 :             osComment = getComment();
     493          35 :             if (adfRates.back() == 1.0 && !bYCBCR420)
     494             :             {
     495          33 :                 osComment += ". LOSSLESS settings used";
     496             :             }
     497             :             else
     498             :             {
     499           2 :                 osComment += ". LOSSY settings used";
     500             :             }
     501          35 :             compressParams.cp_comment = &osComment[0];
     502             :         }
     503             : 
     504             :         const char *pszCodeBlockStyle =
     505         252 :             CSLFetchNameValue(papszOptions, "CODEBLOCK_STYLE");
     506         252 :         if (pszCodeBlockStyle)
     507             :         {
     508           4 :             if (CPLGetValueType(pszCodeBlockStyle) == CPL_VALUE_INTEGER)
     509             :             {
     510           2 :                 int nVal = atoi(pszCodeBlockStyle);
     511           2 :                 if (nVal >= 0 && nVal <= 63)
     512             :                 {
     513           1 :                     compressParams.mode = nVal;
     514             :                 }
     515             :                 else
     516             :                 {
     517           1 :                     CPLError(CE_Warning, CPLE_NotSupported,
     518             :                              "Invalid value for CODEBLOCK_STYLE: %s. "
     519             :                              "Should be >= 0 and <= 63",
     520             :                              pszCodeBlockStyle);
     521             :                 }
     522             :             }
     523             :             else
     524             :             {
     525             :                 char **papszTokens =
     526           2 :                     CSLTokenizeString2(pszCodeBlockStyle, ", ", 0);
     527           9 :                 for (char **papszIter = papszTokens; papszIter && *papszIter;
     528             :                      ++papszIter)
     529             :                 {
     530           7 :                     if (EQUAL(*papszIter, "BYPASS"))
     531             :                     {
     532           1 :                         compressParams.mode |= (1 << 0);
     533             :                     }
     534           6 :                     else if (EQUAL(*papszIter, "RESET"))
     535             :                     {
     536           1 :                         compressParams.mode |= (1 << 1);
     537             :                     }
     538           5 :                     else if (EQUAL(*papszIter, "TERMALL"))
     539             :                     {
     540           1 :                         compressParams.mode |= (1 << 2);
     541             :                     }
     542           4 :                     else if (EQUAL(*papszIter, "VSC"))
     543             :                     {
     544           1 :                         compressParams.mode |= (1 << 3);
     545             :                     }
     546           3 :                     else if (EQUAL(*papszIter, "PREDICTABLE"))
     547             :                     {
     548           1 :                         compressParams.mode |= (1 << 4);
     549             :                     }
     550           2 :                     else if (EQUAL(*papszIter, "SEGSYM"))
     551             :                     {
     552           1 :                         compressParams.mode |= (1 << 5);
     553             :                     }
     554             :                     else
     555             :                     {
     556           1 :                         CPLError(CE_Warning, CPLE_NotSupported,
     557             :                                  "Unrecognized option for CODEBLOCK_STYLE: %s",
     558             :                                  *papszIter);
     559             :                     }
     560             :                 }
     561           2 :                 CSLDestroy(papszTokens);
     562             :             }
     563             :         }
     564             : 
     565             :         /* Add precincts */
     566         252 :         const char *pszPrecincts = CSLFetchNameValueDef(
     567             :             papszOptions, "PRECINCTS",
     568             :             "{512,512},{256,512},{128,512},{64,512},{32,512},{"
     569             :             "16,512},{8,512},{4,512},{2,512}");
     570             :         char **papszTokens =
     571         252 :             CSLTokenizeStringComplex(pszPrecincts, "{},", FALSE, FALSE);
     572         252 :         int nPrecincts = CSLCount(papszTokens) / 2;
     573        2484 :         for (int i = 0; i < nPrecincts && i < OPJ_J2K_MAXRLVLS; i++)
     574             :         {
     575        2232 :             int nPCRW = atoi(papszTokens[2 * i]);
     576        2232 :             int nPCRH = atoi(papszTokens[2 * i + 1]);
     577        2232 :             if (nPCRW < 1 || nPCRH < 1)
     578             :                 break;
     579        2232 :             compressParams.csty |= 0x01;
     580        2232 :             compressParams.res_spec++;
     581        2232 :             compressParams.prcw_init[i] = nPCRW;
     582        2232 :             compressParams.prch_init[i] = nPCRH;
     583             :         }
     584         252 :         CSLDestroy(papszTokens);
     585             : 
     586             :         /* Add tileparts setting */
     587             :         const char *pszTileParts =
     588         252 :             CSLFetchNameValueDef(papszOptions, "TILEPARTS", "DISABLED");
     589         252 :         if (EQUAL(pszTileParts, "RESOLUTIONS"))
     590             :         {
     591           1 :             compressParams.tp_on = 1;
     592           1 :             compressParams.tp_flag = 'R';
     593             :         }
     594         251 :         else if (EQUAL(pszTileParts, "LAYERS"))
     595             :         {
     596           2 :             if (compressParams.tcp_numlayers == 1)
     597             :             {
     598           1 :                 CPLError(
     599             :                     CE_Warning, CPLE_AppDefined,
     600             :                     "TILEPARTS=LAYERS has no real interest with single-layer "
     601             :                     "codestream");
     602             :             }
     603           2 :             compressParams.tp_on = 1;
     604           2 :             compressParams.tp_flag = 'L';
     605             :         }
     606         249 :         else if (EQUAL(pszTileParts, "COMPONENTS"))
     607             :         {
     608           1 :             compressParams.tp_on = 1;
     609           1 :             compressParams.tp_flag = 'C';
     610             :         }
     611         248 :         else if (!EQUAL(pszTileParts, "DISABLED"))
     612             :         {
     613           1 :             CPLError(CE_Warning, CPLE_NotSupported,
     614             :                      "Invalid value for TILEPARTS");
     615             :         }
     616             : 
     617         252 :         if (bProfile1)
     618             :         {
     619         247 :             compressParams.rsiz = OPJ_PROFILE_1;
     620             :         }
     621             : 
     622             :         /* Always ask OpenJPEG to do codestream only. We will take care */
     623             :         /* of JP2 boxes */
     624         252 :         pCodec = opj_create_compress(static_cast<OPJ_CODEC_FORMAT>(
     625         252 :             OPJCodecWrapper::cvtenum(JP2_CODEC_J2K)));
     626         252 :         if (pCodec == nullptr)
     627             :         {
     628           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     629             :                      "opj_create_compress() failed");
     630           0 :             return false;
     631             :         }
     632             : 
     633         252 :         opj_set_info_handler(pCodec, JP2OpenJPEG_InfoCallback, nullptr);
     634         252 :         opj_set_warning_handler(pCodec, JP2OpenJPEG_WarningCallback, nullptr);
     635         252 :         opj_set_error_handler(pCodec, JP2OpenJPEG_ErrorCallback, nullptr);
     636             : 
     637         252 :         psImage = opj_image_tile_create(
     638             :             nBands, pasBandParams, static_cast<OPJ_COLOR_SPACE>(eColorSpace));
     639             : 
     640         252 :         if (psImage == nullptr)
     641             :         {
     642           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     643             :                      "opj_image_tile_create() failed");
     644           0 :             free();
     645           0 :             return false;
     646             :         }
     647             : 
     648         252 :         psImage->x0 = 0;
     649         252 :         psImage->y0 = 0;
     650         252 :         psImage->x1 = nXSize;
     651         252 :         psImage->y1 = nYSize;
     652         252 :         psImage->color_space = static_cast<OPJ_COLOR_SPACE>(eColorSpace);
     653         252 :         psImage->numcomps = nBands;
     654             : 
     655         252 :         if (!opj_setup_encoder(pCodec, &compressParams, psImage))
     656             :         {
     657           0 :             CPLError(CE_Failure, CPLE_AppDefined, "opj_setup_encoder() failed");
     658           0 :             free();
     659           0 :             return false;
     660             :         }
     661             : 
     662             : #if IS_OPENJPEG_OR_LATER(2, 4, 0)
     663             :         if (getenv("OPJ_NUM_THREADS") == nullptr)
     664             :             opj_codec_set_threads(pCodec, numThreads);
     665             :         CPLStringList aosOptions;
     666             :         if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "PLT", "FALSE")))
     667             :         {
     668             :             aosOptions.AddString("PLT=YES");
     669             :         }
     670             : 
     671             : #if IS_OPENJPEG_OR_LATER(2, 5, 0)
     672             :         if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "TLM", "FALSE")))
     673             :         {
     674             :             aosOptions.AddString("TLM=YES");
     675             :         }
     676             : #endif
     677             : 
     678             :         if (!opj_encoder_set_extra_options(pCodec, aosOptions.List()))
     679             :         {
     680             :             CPLError(CE_Failure, CPLE_AppDefined,
     681             :                      "opj_encoder_set_extra_options() failed");
     682             :             free();
     683             :             return false;
     684             :         }
     685             : #endif
     686         252 :         pStream = opj_stream_create(1024 * 1024, FALSE);
     687         252 :         opj_stream_set_write_function(pStream, JP2Dataset_Write);
     688         252 :         opj_stream_set_seek_function(pStream, JP2Dataset_Seek);
     689         252 :         opj_stream_set_skip_function(pStream, JP2Dataset_Skip);
     690         252 :         opj_stream_set_user_data(pStream, psJP2File, nullptr);
     691             : 
     692         252 :         return CPL_TO_BOOL(opj_start_compress(pCodec, psImage, pStream));
     693             :     }
     694             : 
     695             :     /* No-ops: OpenJPEG JP2 boxes are handled by GDAL's GDALJP2Box I/O */
     696             :     static bool ownsFile()
     697             :     {
     698             :         return false;
     699             :     }
     700             : 
     701         252 :     static bool initCodec([[maybe_unused]] const char *pszFilename,
     702             :                           [[maybe_unused]] VSIVirtualHandleUniquePtr &fpOwner)
     703             :     {
     704         252 :         return true;
     705             :     }
     706             : 
     707           0 :     static void setupJP2Metadata(bool, int, bool, GDALJP2Metadata *,
     708             :                                  GDALJP2Box *, int, int, int, int,
     709             :                                  JP2_COLOR_SPACE, int, GDALColorTable *,
     710             :                                  GDALDataset *, CSLConstList)
     711             :     {
     712           0 :     }
     713             : 
     714           0 :     static void extractJP2BoxInfo(int, int &, int &, int &, int &,
     715             :                                   GDALColorTable **)
     716             :     {
     717           0 :     }
     718             : 
     719           0 :     static bool rewriteBoxes(const char *, GDALDataset *)
     720             :     {
     721           0 :         return false;
     722             :     }
     723             : 
     724           0 :     static bool transcode(const char *, const char *, GDALDataset *,
     725             :                           CSLConstList)
     726             :     {
     727           0 :         return false;
     728             :     }
     729             : 
     730         407 :     bool compressTile(int tileIndex, GByte *buff, uint32_t buffLen)
     731             :     {
     732         407 :         if (!pCodec || !pStream)
     733           0 :             return false;
     734         407 :         return CPL_TO_BOOL(
     735         407 :             opj_write_tile(pCodec, tileIndex, buff, buffLen, pStream));
     736             :     }
     737             : 
     738         251 :     bool finishCompress(void)
     739             :     {
     740         251 :         bool rc = false;
     741         251 :         if (pCodec && pStream)
     742         251 :             rc = CPL_TO_BOOL(opj_end_compress(pCodec, pStream));
     743         251 :         if (!rc)
     744          10 :             CPLError(CE_Failure, CPLE_AppDefined, "opj_end_compress() failed");
     745         251 :         free();
     746         251 :         return rc;
     747             :     }
     748             : 
     749         391 :     void cleanUpDecompress(void)
     750             :     {
     751         391 :         if (pCodec && pStream)
     752         391 :             opj_end_decompress(pCodec, pStream);
     753         391 :         free();
     754         391 :     }
     755             : 
     756             :     /************************************************************************/
     757             :     /*                    CreateReadStream()                                */
     758             :     /************************************************************************/
     759        1157 :     static jp2_stream *CreateReadStream(JP2File *psJP2File, vsi_l_offset nSize)
     760             :     {
     761        1157 :         if (!psJP2File)
     762           0 :             return nullptr;
     763        1157 :         auto pStream = opj_stream_create(
     764             :             1024, TRUE);  // Default 1MB is way too big for some datasets
     765        1157 :         if (pStream == nullptr)
     766           0 :             return nullptr;
     767             : 
     768        1157 :         VSIFSeekL(psJP2File->fp_, psJP2File->nBaseOffset, SEEK_SET);
     769        1157 :         opj_stream_set_user_data_length(pStream, nSize);
     770             : 
     771        1157 :         opj_stream_set_read_function(pStream, JP2Dataset_Read);
     772        1157 :         opj_stream_set_seek_function(pStream, JP2Dataset_Seek);
     773        1157 :         opj_stream_set_skip_function(pStream, JP2Dataset_Skip);
     774        1157 :         opj_stream_set_user_data(pStream, psJP2File, nullptr);
     775             : 
     776        1157 :         return pStream;
     777             :     }
     778             : 
     779             :     jp2_codec *pCodec = nullptr;
     780             :     jp2_stream *pStream = nullptr;
     781             :     jp2_image *psImage = nullptr;
     782             :     jp2_image_comp_param *pasBandParams = nullptr;
     783             :     JP2File *psJP2File = nullptr;
     784             : 
     785             :     OPJCodecWrapper(const OPJCodecWrapper &) = delete;
     786             :     OPJCodecWrapper &operator=(const OPJCodecWrapper &) = delete;
     787             : };
     788             : 
     789             : /************************************************************************/
     790             : /* ==================================================================== */
     791             : /*                           JP2OPJDatasetBase                          */
     792             : /* ==================================================================== */
     793             : /************************************************************************/
     794             : 
     795        1905 : struct JP2OPJDatasetBase : public JP2DatasetBase
     796             : {
     797             :     typedef opj_codec_t jp2_codec;
     798             :     typedef opj_image_t jp2_image;
     799             :     typedef opj_stream_t jp2_stream;
     800             : 
     801             :     typedef opj_image_cmptparm_t jp2_image_comp_param;
     802             :     typedef opj_image_comp_t jp2_image_comp;
     803             : 
     804             :     int eColorSpace = OPJCodecWrapper::cvtenum(JP2_CLRSPC_UNKNOWN);
     805             :     OPJCodecWrapper *m_codec = nullptr;
     806             :     int *m_pnLastLevel = nullptr;
     807             :     bool m_bStrict = true;
     808             : 
     809             :     virtual ~JP2OPJDatasetBase();
     810             : 
     811        1905 :     void init(void)
     812             :     {
     813             :         (void)this;
     814        1905 :     }
     815             : 
     816             :     virtual CPLErr
     817          18 :     AdviseRead([[maybe_unused]] int nXOff, [[maybe_unused]] int nYOff,
     818             :                [[maybe_unused]] int nXSize, [[maybe_unused]] int nYSize,
     819             :                [[maybe_unused]] int nBufXSize, [[maybe_unused]] int nBufYSize,
     820             :                [[maybe_unused]] GDALDataType eDT,
     821             :                [[maybe_unused]] int nBandCount,
     822             :                [[maybe_unused]] int *panBandList,
     823             :                [[maybe_unused]] CSLConstList papszOptions)
     824             :     {
     825          18 :         return CE_None;
     826             :     }
     827             : 
     828           0 :     virtual CPLErr DirectRasterIO(
     829             :         [[maybe_unused]] GDALRWFlag /* eRWFlag */, [[maybe_unused]] int nXOff,
     830             :         [[maybe_unused]] int nYOff, [[maybe_unused]] int nXSize,
     831             :         [[maybe_unused]] int nYSize, [[maybe_unused]] void *pData,
     832             :         [[maybe_unused]] int nBufXSize, [[maybe_unused]] int nBufYSize,
     833             :         [[maybe_unused]] GDALDataType eBufType, [[maybe_unused]] int nBandCount,
     834             :         [[maybe_unused]] const int *panBandMap,
     835             :         [[maybe_unused]] GSpacing nPixelSpace,
     836             :         [[maybe_unused]] GSpacing nLineSpace,
     837             :         [[maybe_unused]] GSpacing nBandSpace,
     838             :         [[maybe_unused]] GDALRasterIOExtraArg *psExtraArg)
     839             : 
     840             :     {
     841           0 :         return CE_None;
     842             :     }
     843             : 
     844        2880 :     static bool canPerformDirectIO(void)
     845             :     {
     846        2880 :         return false;
     847             :     }
     848             : 
     849         391 :     CPLErr readBlockInit(VSILFILE *fpIn, OPJCodecWrapper *codec, int nBlockXOff,
     850             :                          int nBlockYOff, int nRasterXSize, int nRasterYSize,
     851             :                          int nBlockXSize, int nBlockYSize, int nTileNumber)
     852             :     {
     853             :         const int nWidthToRead =
     854         391 :             std::min(nBlockXSize, nRasterXSize - nBlockXOff * nBlockXSize);
     855             :         const int nHeightToRead =
     856         391 :             std::min(nBlockYSize, nRasterYSize - nBlockYOff * nBlockYSize);
     857             : 
     858         391 :         if (!codec)
     859             :         {
     860           0 :             CPLError(CE_Failure, CPLE_AppDefined, "null codec");
     861           0 :             return CE_Failure;
     862             :         }
     863             : 
     864         391 :         if (m_codec && CPLTestBool(CPLGetConfigOption(
     865             :                            "USE_OPENJPEG_SINGLE_TILE_OPTIM", "YES")))
     866             :         {
     867           0 :             if ((*m_pnLastLevel == -1 || *m_pnLastLevel == iLevel) &&
     868           0 :                 codec->pCodec != nullptr && *codec->pStream != nullptr &&
     869           0 :                 m_codec->psImage != nullptr)
     870             :             {
     871           0 :                 codec->transfer(m_codec);
     872             :             }
     873             :             else
     874             :             {
     875             :                 // For some reason, we need to "reboot" all the machinery if
     876             :                 // changing of overview level. Should be fixed in openjpeg
     877           0 :                 m_codec->free();
     878             :             }
     879             :         }
     880         391 :         *m_pnLastLevel = iLevel;
     881             : 
     882         391 :         if (codec->pCodec == nullptr)
     883             :         {
     884         391 :             codec->pCodec = opj_create_decompress(static_cast<OPJ_CODEC_FORMAT>(
     885         391 :                 OPJCodecWrapper::cvtenum(JP2_CODEC_J2K)));
     886         391 :             if (codec->pCodec == nullptr)
     887             :             {
     888           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     889             :                          "opj_create_decompress() failed");
     890           0 :                 return CE_Failure;
     891             :             }
     892             : 
     893         391 :             opj_set_info_handler(codec->pCodec, JP2OpenJPEG_InfoCallback,
     894             :                                  nullptr);
     895         391 :             opj_set_warning_handler(codec->pCodec, JP2OpenJPEG_WarningCallback,
     896             :                                     nullptr);
     897         391 :             opj_set_error_handler(codec->pCodec, JP2OpenJPEG_ErrorCallback,
     898             :                                   nullptr);
     899             : 
     900             :             opj_dparameters_t parameters;
     901         391 :             opj_set_default_decoder_parameters(&parameters);
     902         391 :             if (!opj_setup_decoder(codec->pCodec, &parameters))
     903             :             {
     904           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     905             :                          "opj_setup_decoder() failed");
     906           0 :                 return CE_Failure;
     907             :             }
     908             : #if IS_OPENJPEG_OR_LATER(2, 5, 0)
     909             :             if (!m_bStrict)
     910             :             {
     911             :                 opj_decoder_set_strict_mode(codec->pCodec, false);
     912             :             }
     913             : #endif
     914         391 :             if (m_codec && m_codec->psJP2File)
     915             :             {
     916           0 :                 codec->pStream = OPJCodecWrapper::CreateReadStream(
     917           0 :                     m_codec->psJP2File, nCodeStreamLength);
     918             :             }
     919             :             else
     920             :             {
     921         391 :                 codec->open(fpIn, nCodeStreamStart);
     922         391 :                 codec->pStream = OPJCodecWrapper::CreateReadStream(
     923             :                     codec->psJP2File, nCodeStreamLength);
     924             :             }
     925         391 :             if (!codec->pStream)
     926             :             {
     927           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     928             :                          "OPJCodecWrapper::CreateReadStream() failed");
     929           0 :                 return CE_Failure;
     930             :             }
     931             : 
     932         391 :             if (getenv("OPJ_NUM_THREADS") == nullptr)
     933             :             {
     934         391 :                 if (m_nBlocksToLoad <= 1)
     935         254 :                     opj_codec_set_threads(codec->pCodec, GetNumThreads());
     936             :                 else
     937         137 :                     opj_codec_set_threads(codec->pCodec,
     938         137 :                                           GetNumThreads() / m_nBlocksToLoad);
     939             :             }
     940             : 
     941         391 :             if (!opj_read_header(codec->pStream, codec->pCodec,
     942             :                                  &codec->psImage))
     943             :             {
     944           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     945             :                          "opj_read_header() failed (psImage=%p)",
     946             :                          codec->psImage);
     947             :                 // Hopefully the situation is better on openjpeg 2.2 regarding
     948             :                 // cleanup
     949             :                 // We may leak objects, but the cleanup of openjpeg can cause
     950             :                 // double frees sometimes...
     951           0 :                 return CE_Failure;
     952             :             }
     953             :         }
     954         391 :         if (!opj_set_decoded_resolution_factor(codec->pCodec, iLevel))
     955             :         {
     956           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     957             :                      "opj_set_decoded_resolution_factor() failed");
     958           0 :             return CE_Failure;
     959             :         }
     960         391 :         if (bUseSetDecodeArea)
     961             :         {
     962             :             /* We need to explicitly set the resolution factor on the image */
     963             :             /* otherwise opj_set_decode_area() will assume we decode at full */
     964             :             /* resolution. */
     965             :             /* If using parameters.cp_reduce instead of
     966             :           * opj_set_decoded_resolution_factor() */
     967             :             /* we wouldn't need to do that, as opj_read_header() would automatically
     968             :           */
     969             :             /* assign the comps[].factor to the appropriate value */
     970         396 :             for (unsigned int iBand = 0; iBand < codec->psImage->numcomps;
     971             :                  iBand++)
     972             :             {
     973         199 :                 codec->psImage->comps[iBand].factor = iLevel;
     974             :             }
     975             :             /* The decode area must be expressed in grid reference, ie at full*/
     976             :             /* scale */
     977         197 :             if (!opj_set_decode_area(
     978             :                     codec->pCodec, codec->psImage,
     979         197 :                     m_nX0 + static_cast<int>(
     980         197 :                                 static_cast<GIntBig>(nBlockXOff * nBlockXSize) *
     981         197 :                                 nParentXSize / nRasterXSize),
     982         197 :                     m_nY0 + static_cast<int>(
     983         197 :                                 static_cast<GIntBig>(nBlockYOff * nBlockYSize) *
     984         197 :                                 nParentYSize / nRasterYSize),
     985         197 :                     m_nX0 + static_cast<int>(
     986         197 :                                 static_cast<GIntBig>(nBlockXOff * nBlockXSize +
     987         197 :                                                      nWidthToRead) *
     988         197 :                                 nParentXSize / nRasterXSize),
     989         197 :                     m_nY0 + static_cast<int>(
     990         197 :                                 static_cast<GIntBig>(nBlockYOff * nBlockYSize +
     991         197 :                                                      nHeightToRead) *
     992         197 :                                 nParentYSize / nRasterYSize)))
     993             :             {
     994           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     995             :                          "opj_set_decode_area() failed");
     996           0 :                 return CE_Failure;
     997             :             }
     998         197 :             if (!opj_decode(codec->pCodec, codec->pStream, codec->psImage))
     999             :             {
    1000           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "opj_decode() failed");
    1001           0 :                 return CE_Failure;
    1002             :             }
    1003             :         }
    1004             :         else
    1005             :         {
    1006         194 :             if (!opj_get_decoded_tile(codec->pCodec, codec->pStream,
    1007             :                                       codec->psImage, nTileNumber))
    1008             :             {
    1009           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1010             :                          "opj_get_decoded_tile() failed");
    1011           0 :                 return CE_Failure;
    1012             :             }
    1013             :         }
    1014             : 
    1015         391 :         return CE_None;
    1016             :     }
    1017             : 
    1018          32 :     void cache(CPL_UNUSED JP2OPJDatasetBase *rhs)
    1019             :     {
    1020             :         // prevent linter from treating this as potential static method
    1021             :         (void)this;
    1022          32 :         if (m_codec && rhs)
    1023           0 :             m_codec->transfer(rhs->m_codec);
    1024          32 :     }
    1025             : 
    1026         580 :     void cacheNew(CPL_UNUSED OPJCodecWrapper *codec)
    1027             :     {
    1028             :         // prevent linter from treating this as potential static method
    1029             :         (void)this;
    1030         580 :         if (!codec)
    1031           0 :             return;
    1032         580 :         if (m_codec)
    1033           0 :             m_codec = new OPJCodecWrapper(codec);
    1034             :     }
    1035             : 
    1036         391 :     void cache(CPL_UNUSED OPJCodecWrapper *codec)
    1037             :     {
    1038             :         // prevent linter from treating this as potential static method
    1039             :         (void)this;
    1040         391 :         if (!codec)
    1041           0 :             return;
    1042             : 
    1043         391 :         if (m_codec && CPLTestBool(CPLGetConfigOption(
    1044             :                            "USE_OPENJPEG_SINGLE_TILE_OPTIM", "YES")))
    1045             :         {
    1046           0 :             codec->transfer(m_codec);
    1047             :         }
    1048             :         else
    1049             :         {
    1050         391 :             codec->cleanUpDecompress();
    1051             :         }
    1052             :     }
    1053             : 
    1054         760 :     void openCompleteJP2(OPJCodecWrapper *codec)
    1055             :     {
    1056             :         // prevent linter from treating this as potential static method
    1057             :         (void)this;
    1058         760 :         if (bSingleTiled && bUseSetDecodeArea)
    1059             :         {
    1060             :             // nothing
    1061             :         }
    1062             :         else
    1063             :         {
    1064         180 :             if (codec)
    1065         180 :                 codec->free();
    1066             :         }
    1067         760 :     }
    1068             : 
    1069        1905 :     void closeJP2(void)
    1070             :     {
    1071             :         // prevent linter from treating this as potential static method
    1072             :         (void)this;
    1073        1905 :         if (iLevel == 0)
    1074             :         {
    1075        1788 :             if (m_codec)
    1076           0 :                 m_codec->free();
    1077        1788 :             delete m_pnLastLevel;
    1078        1788 :             m_pnLastLevel = nullptr;
    1079             :         }
    1080        1905 :     }
    1081             : };

Generated by: LCOV version 1.14