LCOV - code coverage report
Current view: top level - frmts/ecw - ecwcreatecopy.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 518 671 77.2 %
Date: 2026-06-19 21:24:00 Functions: 32 38 84.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL ECW Driver
       4             :  * Purpose:  ECW CreateCopy method implementation.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2001, 2004, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : // ncsjpcbuffer.h needs the min and max macros.
      15             : #undef NOMINMAX
      16             : 
      17             : #include "gdal_ecw.h"
      18             : #include "gdaljp2metadata.h"
      19             : #include "ogr_spatialref.h"
      20             : 
      21             : #if defined(HAVE_COMPRESS)
      22             : 
      23             : #define OPTIMIZED_FOR_GDALWARP
      24             : 
      25             : #if ECWSDK_VERSION >= 50
      26             : static CPLString GetCompressionSoftwareName()
      27             : {
      28             :     CPLString osRet;
      29             :     char szProcessName[2048];
      30             : 
      31             :     /* For privacy reason, allow the user to not write the software name in the
      32             :      * ECW */
      33             :     if (!CPLTestBool(
      34             :             CPLGetConfigOption("GDAL_ECW_WRITE_COMPRESSION_SOFTWARE", "YES")))
      35             :         return osRet;
      36             : 
      37             :     if (CPLGetExecPath(szProcessName, sizeof(szProcessName) - 1))
      38             :     {
      39             :         szProcessName[sizeof(szProcessName) - 1] = 0;
      40             : #ifdef _WIN32
      41             :         char *szLastSlash = strrchr(szProcessName, '\\');
      42             : #else
      43             :         char *szLastSlash = strrchr(szProcessName, '/');
      44             : #endif
      45             :         if (szLastSlash != nullptr)
      46             :             memmove(szProcessName, szLastSlash + 1,
      47             :                     strlen(szLastSlash + 1) + 1);
      48             :     }
      49             :     else
      50             :         strcpy(szProcessName, "Unknown");
      51             : 
      52             :     osRet.Printf("%s/GDAL v%d.%d.%d.%d/ECWJP2 SDK v%s", szProcessName,
      53             :                  GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR, GDAL_VERSION_REV,
      54             :                  GDAL_VERSION_BUILD, NCS_ECWJP2_FULL_VERSION_STRING_DOT_DEL);
      55             :     return osRet;
      56             : }
      57             : #endif
      58             : 
      59             : class GDALECWCompressor final : public CNCSFile
      60             : {
      61             : 
      62             :   public:
      63             :     GDALECWCompressor();
      64             :     ~GDALECWCompressor() override;
      65             :     virtual CNCSError WriteReadLine(UINT32 nNextLine,
      66             :                                     void **ppInputArray) override;
      67             : #if ECWSDK_VERSION >= 50
      68             :     virtual void WriteStatus(IEEE4 fPercentComplete,
      69             :                              const NCS::CString &sStatusText,
      70             :                              const CompressionCounters &Counters) override;
      71             : #else
      72             :     void WriteStatus(UINT32 nCurrentLine) override;
      73             : #endif
      74             : 
      75             :     bool WriteCancel() override;
      76             : 
      77             :     CPLErr Initialize(const char *pszFilename, CSLConstList papszOptions,
      78             :                       int nXSize, int nYSize, int nBands,
      79             :                       const char *const *papszBandDescriptions,
      80             :                       int bRGBColorSpace, GDALDataType eType,
      81             :                       const OGRSpatialReference *poSRS,
      82             :                       const GDALGeoTransform &gt, int nGCPCount,
      83             :                       const GDAL_GCP *pasGCPList, int bIsJPEG2000,
      84             :                       int bPixelIsPoint, CSLConstList papszRPCMD,
      85             :                       GDALDataset *poSrcDS = nullptr);
      86             :     CPLErr CloseDown();
      87             : 
      88             :     CPLErr WriteJP2Box(GDALJP2Box *);
      89             :     void WriteXMLBoxes();
      90             :     CPLErr ourWriteLineBIL(UINT16 nBands, void **ppOutputLine,
      91             :                            UINT32 *pLineSteps = nullptr);
      92             : #if ECWSDK_VERSION >= 50
      93             :     NCSEcwCellType WriteReadLineGetCellType() override
      94             :     {
      95             :         return sFileInfo.eCellType;
      96             :     }
      97             : #endif
      98             : #ifdef ECW_FW
      99             :     CNCSJP2File::CNCSJPXAssocBox m_oGMLAssoc;
     100             : #endif
     101             : 
     102             :     // Data
     103             : 
     104             :     GDALDataset *m_poSrcDS;
     105             : 
     106             :     std::shared_ptr<VSIIOStream> m_OStream;
     107             :     int m_nPercentComplete;
     108             : 
     109             :     int m_bCanceled;
     110             : 
     111             :     GDALProgressFunc pfnProgress;
     112             :     void *pProgressData;
     113             : 
     114             :     GDALDataType eWorkDT;
     115             :     int m_nSwathLines;
     116             :     UINT32 m_nSwathOffset;
     117             :     GByte *m_pabySwathBuf;
     118             :     JP2UserBox **papoJP2UserBox;
     119             :     int nJP2UserBox;
     120             :     std::vector<int> m_anBandMap{};
     121             : 
     122             :   private:
     123             :     NCSFileViewFileInfoEx sFileInfo;
     124             : 
     125             :     /* To fix 'warning: ‘virtual NCS::CView& NCS::CView::operator=(const
     126             :      * NCS::CView&)’ was hidden ' with SDK 5 */
     127             : #if ECWSDK_VERSION >= 50
     128             :     using CNCSFile::operator=;
     129             : #endif
     130             :     CPL_DISALLOW_COPY_ASSIGN(GDALECWCompressor)
     131             : };
     132             : 
     133             : /************************************************************************/
     134             : /*                         GDALECWCompressor()                          */
     135             : /************************************************************************/
     136             : 
     137          69 : GDALECWCompressor::GDALECWCompressor()
     138             :     : m_OStream(std::make_shared<VSIIOStream>()), eWorkDT(GDT_Unknown),
     139          69 :       m_nSwathLines(0), m_nSwathOffset(0), m_pabySwathBuf(nullptr)
     140             : {
     141          69 :     m_poSrcDS = nullptr;
     142          69 :     m_nPercentComplete = -1;
     143          69 :     m_bCanceled = FALSE;
     144          69 :     pfnProgress = GDALDummyProgress;
     145          69 :     pProgressData = nullptr;
     146          69 :     papoJP2UserBox = nullptr;
     147          69 :     nJP2UserBox = 0;
     148             : #if ECWSDK_VERSION >= 50
     149             :     NCSInitFileInfo(&sFileInfo);
     150             : #else
     151          69 :     NCSInitFileInfoEx(&sFileInfo);
     152             : #endif
     153          69 :     m_anBandMap.resize(sFileInfo.nBands);
     154          69 :     for (int iBand = 0; iBand < sFileInfo.nBands; iBand++)
     155           0 :         m_anBandMap[iBand] = iBand + 1;
     156          69 : }
     157             : 
     158             : /************************************************************************/
     159             : /*                         ~GDALECWCompressor()                         */
     160             : /************************************************************************/
     161             : 
     162          69 : GDALECWCompressor::~GDALECWCompressor()
     163             : 
     164             : {
     165             :     int i;
     166         131 :     for (i = 0; i < nJP2UserBox; i++)
     167          62 :         delete papoJP2UserBox[i];
     168          69 :     CPLFree(papoJP2UserBox);
     169             : 
     170             : #if ECWSDK_VERSION >= 50
     171             :     NCSFreeFileInfo(&sFileInfo);
     172             : #else
     173          69 :     NCSFreeFileInfoEx(&sFileInfo);
     174             : #endif
     175          69 :     CPLFree(m_pabySwathBuf);
     176          69 : }
     177             : 
     178             : /************************************************************************/
     179             : /*                             CloseDown()                              */
     180             : /************************************************************************/
     181             : 
     182          34 : CPLErr GDALECWCompressor::CloseDown()
     183             : 
     184             : {
     185          34 :     Close(true);
     186          34 :     m_OStream->Close();
     187             : 
     188          34 :     return CE_None;
     189             : }
     190             : 
     191             : /************************************************************************/
     192             : /*                           WriteReadLine()                            */
     193             : /************************************************************************/
     194             : 
     195        3979 : CNCSError GDALECWCompressor::WriteReadLine(UINT32 nNextLine,
     196             :                                            void **ppInputArray)
     197             : 
     198             : {
     199             :     CPLErr eErr;
     200             : 
     201             : #ifdef DEBUG_VERBOSE
     202             :     CPLDebug("ECW", "nNextLine = %d", nNextLine);
     203             : #endif
     204             : 
     205        3979 :     if (m_poSrcDS == nullptr || m_poSrcDS->GetRasterBand(1) == nullptr)
     206             :     {
     207           0 :         return GetCNCSError(NCS_FILEIO_ERROR);
     208             :     }
     209        3979 :     if (m_nSwathLines <= 0)
     210             :     {
     211             :         int nBlockX;
     212          32 :         constexpr int MIN_SWATH_LINES = 256;
     213          32 :         m_poSrcDS->GetRasterBand(1)->GetBlockSize(&nBlockX, &m_nSwathLines);
     214          32 :         if (m_nSwathLines < MIN_SWATH_LINES)
     215          30 :             m_nSwathLines = MIN_SWATH_LINES;
     216             :     }
     217             : 
     218        3979 :     const GSpacing nPixelSpace = GDALGetDataTypeSizeBytes(eWorkDT);
     219        3979 :     const GSpacing nLineSpace = sFileInfo.nSizeX * nPixelSpace;
     220        3979 :     const GSpacing nBandSpace = nLineSpace * m_nSwathLines;
     221             : 
     222        3979 :     if (m_pabySwathBuf == nullptr)
     223             :     {
     224          32 :         size_t nBufSize = static_cast<size_t>(nBandSpace * sFileInfo.nBands);
     225          32 :         m_pabySwathBuf = (GByte *)VSI_MALLOC_VERBOSE(nBufSize);
     226             :     }
     227        3979 :     if (m_pabySwathBuf == nullptr)
     228             :     {
     229           0 :         return GetCNCSError(NCS_FILE_NO_MEMORY);
     230             :     }
     231             : 
     232        3979 :     if (nNextLine == 0 || nNextLine >= m_nSwathOffset + m_nSwathLines)
     233             :     {
     234          41 :         int nSwathLines = m_nSwathLines;
     235          41 :         if (nNextLine + nSwathLines > sFileInfo.nSizeY)
     236             :         {
     237          29 :             nSwathLines = sFileInfo.nSizeY - nNextLine;
     238             :         }
     239         123 :         eErr = m_poSrcDS->RasterIO(
     240          41 :             GF_Read, 0, nNextLine, sFileInfo.nSizeX, nSwathLines,
     241          41 :             m_pabySwathBuf, sFileInfo.nSizeX, nSwathLines, eWorkDT,
     242          41 :             sFileInfo.nBands, &m_anBandMap[0], nPixelSpace, nLineSpace,
     243             :             nBandSpace, nullptr);
     244          41 :         m_nSwathOffset = nNextLine;
     245          41 :         UINT32 nNextSwathLine = nNextLine + nSwathLines;
     246          41 :         if (nNextSwathLine < sFileInfo.nSizeY)
     247             :         {
     248           9 :             if (nNextSwathLine + nSwathLines > sFileInfo.nSizeY)
     249             :             {
     250           3 :                 nSwathLines = sFileInfo.nSizeY - nNextSwathLine;
     251             :             }
     252          18 :             m_poSrcDS->AdviseRead(0, nNextSwathLine, sFileInfo.nSizeX,
     253           9 :                                   nSwathLines, sFileInfo.nSizeX, nSwathLines,
     254           9 :                                   eWorkDT, sFileInfo.nBands, &m_anBandMap[0],
     255           9 :                                   nullptr);
     256          41 :         }
     257             :     }
     258             :     else
     259             :     {
     260        3938 :         eErr = CE_None;
     261             :     }
     262             : 
     263        9928 :     for (int iBand = 0; iBand < (int)sFileInfo.nBands; iBand++)
     264             :     {
     265        5949 :         memcpy(ppInputArray[iBand],
     266        5949 :                m_pabySwathBuf + nLineSpace * (nNextLine - m_nSwathOffset) +
     267        5949 :                    nBandSpace * iBand,
     268        5949 :                static_cast<size_t>(nPixelSpace * sFileInfo.nSizeX));
     269             :     }
     270             : 
     271        3979 :     if (eErr == CE_None)
     272        3979 :         return GetCNCSError(NCS_SUCCESS);
     273             :     else
     274           0 :         return GetCNCSError(NCS_FILEIO_ERROR);
     275             : }
     276             : 
     277             : /************************************************************************/
     278             : /*                            WriteStatus()                             */
     279             : /************************************************************************/
     280             : #if ECWSDK_VERSION >= 50
     281             : void GDALECWCompressor::WriteStatus(IEEE4 fPercentComplete,
     282             :                                     const NCS::CString &sStatusText,
     283             :                                     const CompressionCounters &Counters)
     284             : {
     285             :     std::string sStatusUTF8;
     286             :     sStatusText.utf8_str(sStatusUTF8);
     287             : 
     288             :     m_bCanceled = !pfnProgress(fPercentComplete / 100.0, sStatusUTF8.c_str(),
     289             :                                pProgressData);
     290             : }
     291             : #else
     292             : 
     293        3979 : void GDALECWCompressor::WriteStatus(UINT32 nCurrentLine)
     294             : 
     295             : {
     296        3979 :     m_bCanceled = !pfnProgress(nCurrentLine / (float)sFileInfo.nSizeY, nullptr,
     297             :                                pProgressData);
     298        3979 : }
     299             : #endif
     300             : /************************************************************************/
     301             : /*                            WriteCancel()                             */
     302             : /************************************************************************/
     303             : 
     304        3979 : bool GDALECWCompressor::WriteCancel()
     305             : 
     306             : {
     307        3979 :     return (bool)m_bCanceled;
     308             : }
     309             : 
     310             : /************************************************************************/
     311             : /*                            WriteJP2Box()                             */
     312             : /************************************************************************/
     313             : 
     314          70 : CPLErr GDALECWCompressor::WriteJP2Box(GDALJP2Box *poBox)
     315             : 
     316             : {
     317             :     JP2UserBox *poECWBox;
     318             : 
     319          70 :     if (poBox == nullptr)
     320           8 :         return CE_None;
     321             : 
     322          62 :     poECWBox = new JP2UserBox();
     323          62 :     memcpy(&(poECWBox->m_nTBox), poBox->GetType(), 4);
     324          62 :     CPL_MSBPTR32(&(poECWBox->m_nTBox));
     325             : 
     326          62 :     poECWBox->SetData((int)poBox->GetDataLength(), poBox->GetWritableData());
     327             : 
     328          62 :     AddBox(poECWBox);
     329             : 
     330          62 :     delete poBox;
     331             : 
     332         124 :     papoJP2UserBox = (JP2UserBox **)CPLRealloc(
     333          62 :         papoJP2UserBox, (nJP2UserBox + 1) * sizeof(JP2UserBox *));
     334          62 :     papoJP2UserBox[nJP2UserBox] = poECWBox;
     335          62 :     nJP2UserBox++;
     336             : 
     337          62 :     return CE_None;
     338             : }
     339             : 
     340             : /************************************************************************/
     341             : /*                           WriteXMLBoxes()                            */
     342             : /************************************************************************/
     343             : 
     344           6 : void GDALECWCompressor::WriteXMLBoxes()
     345             : {
     346           6 :     int nBoxes = 0;
     347             :     GDALJP2Box **papoBoxes =
     348           6 :         GDALJP2Metadata::CreateXMLBoxes(m_poSrcDS, &nBoxes);
     349           7 :     for (int i = 0; i < nBoxes; i++)
     350             :     {
     351           1 :         WriteJP2Box(papoBoxes[i]);
     352             :     }
     353           6 :     CPLFree(papoBoxes);
     354           6 : }
     355             : 
     356             : /************************************************************************/
     357             : /*                          ourWriteLineBIL()                           */
     358             : /************************************************************************/
     359             : 
     360         200 : CPLErr GDALECWCompressor::ourWriteLineBIL(UINT16 nBands, void **ppOutputLine,
     361             :                                           UINT32 *pLineSteps)
     362             : {
     363             : 
     364             :     CNCSError oError = CNCSFile::WriteLineBIL(sFileInfo.eCellType, nBands,
     365         400 :                                               ppOutputLine, pLineSteps);
     366             : 
     367         200 :     if (oError.GetErrorNumber() != NCS_SUCCESS)
     368             :     {
     369           0 :         ECWReportError(oError, "Scanline write write failed.\n");
     370           0 :         return CE_Failure;
     371             :     }
     372         200 :     return CE_None;
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                             Initialize()                             */
     377             : /*                                                                      */
     378             : /*      Initialize compressor output.                                   */
     379             : /************************************************************************/
     380             : 
     381          38 : CPLErr GDALECWCompressor::Initialize(
     382             :     const char *pszFilename, CSLConstList papszOptions, int nXSize, int nYSize,
     383             :     int nBands, const char *const *papszBandDescriptions, int bRGBColorSpace,
     384             :     GDALDataType eType, const OGRSpatialReference *poSRS,
     385             :     const GDALGeoTransform &gt, int nGCPCount, const GDAL_GCP *pasGCPList,
     386             :     int bIsJPEG2000, int bPixelIsPoint, CSLConstList papszRPCMD,
     387             :     GDALDataset *poSrcDS)
     388             : 
     389             : {
     390             : /* -------------------------------------------------------------------- */
     391             : /*      For 4.x and beyond you need a license key to compress data.     */
     392             : /*      Check for it as a configuration option or a creation option.    */
     393             : /* -------------------------------------------------------------------- */
     394             : #if ECWSDK_VERSION >= 40
     395             :     const char *pszECWKey = CSLFetchNameValue(papszOptions, "ECW_ENCODE_KEY");
     396             :     if (pszECWKey == nullptr)
     397             :         pszECWKey = CPLGetConfigOption("ECW_ENCODE_KEY", nullptr);
     398             : 
     399             :     const char *pszECWCompany =
     400             :         CSLFetchNameValue(papszOptions, "ECW_ENCODE_COMPANY");
     401             :     if (pszECWCompany == nullptr)
     402             :         pszECWCompany = CPLGetConfigOption("ECW_ENCODE_COMPANY", nullptr);
     403             : 
     404             :     if (pszECWKey && pszECWCompany)
     405             :     {
     406             :         CPLDebug("ECW", "SetOEMKey(%s,%s)", pszECWCompany, pszECWKey);
     407             :         CNCSFile::SetOEMKey((char *)pszECWCompany, (char *)pszECWKey);
     408             :     }
     409             :     else if (pszECWKey || pszECWCompany)
     410             :     {
     411             :         CPLError(CE_Failure, CPLE_AppDefined,
     412             :                  "Only one of ECW_ENCODE_KEY and ECW_ENCODE_COMPANY were "
     413             :                  "provided.\nBoth are required.");
     414             :         return CE_Failure;
     415             :     }
     416             :     else
     417             :     {
     418             :         CPLError(CE_Failure, CPLE_AppDefined,
     419             :                  "None of ECW_ENCODE_KEY and ECW_ENCODE_COMPANY were "
     420             :                  "provided.\nBoth are required.");
     421             :         return CE_Failure;
     422             :     }
     423             : 
     424             : #endif /* ECWSDK_VERSION >= 40 */
     425             : 
     426             :     /* -------------------------------------------------------------------- */
     427             :     /*      Do some rudimentary checking in input.                          */
     428             :     /* -------------------------------------------------------------------- */
     429          38 :     if (nBands == 0)
     430             :     {
     431           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     432             :                  "ECW driver requires at least one band.");
     433           0 :         return CE_Failure;
     434             :     }
     435             : 
     436             :     /* -------------------------------------------------------------------- */
     437             :     /*      Parse out some known options.                                   */
     438             :     /* -------------------------------------------------------------------- */
     439             :     float fTargetCompression;
     440             : 
     441             :     // Default compression based on image type per request from Paul Beaty.
     442          38 :     if (nBands > 1)
     443          11 :         fTargetCompression = 95.0;
     444             :     else
     445          27 :         fTargetCompression = 90.0;
     446             : 
     447          38 :     if (CSLFetchNameValue(papszOptions, "TARGET") != nullptr)
     448             :     {
     449          10 :         fTargetCompression =
     450          10 :             (float)CPLAtof(CSLFetchNameValue(papszOptions, "TARGET"));
     451             : 
     452             :         /* The max allowed value should be 100 - 100 / 65535 = 99.9984740978 */
     453             :         /* so that nCompressionRate fits on a uint16 (see below) */
     454             :         /* No need to be so pedantic, so we will limit to 99.99 % */
     455             :         /* (compression rate = 10 000) */
     456          10 :         if (fTargetCompression < 0.0 || fTargetCompression > 99.99)
     457             :         {
     458           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     459             :                      "TARGET compression of %.3f invalid, should be a\n"
     460             :                      "value between 0 and 99.99 percent.\n",
     461             :                      (double)fTargetCompression);
     462           0 :             return CE_Failure;
     463             :         }
     464             :     }
     465             : 
     466             :     /* -------------------------------------------------------------------- */
     467             :     /*      Create and initialize compressor.                               */
     468             :     /* -------------------------------------------------------------------- */
     469          38 :     NCSFileViewFileInfoEx *psClient = &(sFileInfo);
     470          38 :     const char *pszOption = nullptr;
     471             : #if ECWSDK_VERSION >= 50
     472             :     if (bIsJPEG2000 == FALSE)
     473             :     {
     474             :         bool bECWV3 = false;
     475             :         pszOption = CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
     476             :         if (pszOption != nullptr)
     477             :         {
     478             :             bECWV3 = (3 == atoi(pszOption));
     479             :         }
     480             :         psClient->nFormatVersion = (bECWV3) ? 3 : 2;
     481             :     }
     482             :     else
     483             :     {
     484             :         psClient->nFormatVersion = 1;
     485             :     }
     486             : #endif
     487          38 :     psClient->nBands = (UINT16)nBands;
     488          38 :     psClient->nSizeX = nXSize;
     489          38 :     psClient->nSizeY = nYSize;
     490          38 :     psClient->nCompressionRate =
     491          38 :         (UINT16)MAX(1, 100 / (100 - fTargetCompression));
     492          38 :     psClient->eCellSizeUnits = ECW_CELL_UNITS_METERS;
     493             : 
     494          38 :     if (nBands == 1)
     495          27 :         psClient->eColorSpace = NCSCS_GREYSCALE;
     496          11 :     else if (nBands == 3 && bRGBColorSpace)
     497           5 :         psClient->eColorSpace = NCSCS_sRGB;
     498             : #if ECWSDK_VERSION >= 40
     499             :     else if (nBands == 4 && bRGBColorSpace)
     500             :         psClient->eColorSpace = NCSCS_sRGB;
     501             : #endif
     502             :     else
     503           6 :         psClient->eColorSpace = NCSCS_MULTIBAND;
     504             : 
     505             :     /* -------------------------------------------------------------------- */
     506             :     /*      Figure out the data type.                                       */
     507             :     /* -------------------------------------------------------------------- */
     508          38 :     int bSigned = FALSE;
     509          38 :     int nBits = 8;
     510          38 :     eWorkDT = eType;
     511             : 
     512          38 :     switch (eWorkDT)
     513             :     {
     514          30 :         case GDT_UInt8:
     515             : #if ECWSDK_VERSION >= 50
     516             :             psClient->nCellBitDepth = 8;
     517             : #endif
     518          30 :             psClient->eCellType = NCSCT_UINT8;
     519          30 :             nBits = 8;
     520          30 :             bSigned = FALSE;
     521          30 :             break;
     522             : 
     523           2 :         case GDT_UInt16:
     524             : #if ECWSDK_VERSION >= 50
     525             :             psClient->nCellBitDepth = 16;
     526             : #endif
     527           2 :             psClient->eCellType = NCSCT_UINT16;
     528           2 :             nBits = 16;
     529           2 :             bSigned = FALSE;
     530           2 :             break;
     531             : 
     532           1 :         case GDT_UInt32:
     533             : #if ECWSDK_VERSION >= 50
     534             :             psClient->nCellBitDepth = 32;
     535             : #endif
     536           1 :             psClient->eCellType = NCSCT_UINT32;
     537           1 :             nBits = 32;
     538           1 :             bSigned = FALSE;
     539           1 :             break;
     540             : 
     541           3 :         case GDT_Int16:
     542             : #if ECWSDK_VERSION >= 50
     543             :             psClient->nCellBitDepth = 16;
     544             : #endif
     545           3 :             psClient->eCellType = NCSCT_INT16;
     546           3 :             nBits = 16;
     547           3 :             bSigned = TRUE;
     548           3 :             break;
     549             : 
     550           1 :         case GDT_Int32:
     551             : #if ECWSDK_VERSION >= 50
     552             :             psClient->nCellBitDepth = 32;
     553             : #endif
     554           1 :             psClient->eCellType = NCSCT_INT32;
     555           1 :             nBits = 32;
     556           1 :             bSigned = TRUE;
     557           1 :             break;
     558             : 
     559           1 :         case GDT_Float32:
     560           1 :             psClient->eCellType = NCSCT_IEEE4;
     561           1 :             nBits = 32;
     562           1 :             bSigned = TRUE;
     563           1 :             break;
     564             : 
     565             : #if ECWSDK_VERSION >= 40
     566             :         case GDT_Float64:
     567             :             psClient->eCellType = NCSCT_IEEE8;
     568             :             nBits = 64;
     569             :             bSigned = TRUE;
     570             :             break;
     571             : #endif
     572             : 
     573           0 :         default:
     574             :             // We treat complex types as float.
     575           0 :             psClient->eCellType = NCSCT_IEEE4;
     576           0 :             nBits = 32;
     577           0 :             bSigned = TRUE;
     578           0 :             eWorkDT = GDT_Float32;
     579           0 :             break;
     580             :     }
     581             : 
     582             :     /* -------------------------------------------------------------------- */
     583             :     /*      Create band information structures.                             */
     584             :     /* -------------------------------------------------------------------- */
     585             :     int iBand;
     586             : 
     587          38 :     psClient->pBands =
     588          38 :         (NCSFileBandInfo *)NCSMalloc(sizeof(NCSFileBandInfo) * nBands, true);
     589          98 :     for (iBand = 0; iBand < nBands; iBand++)
     590             :     {
     591          60 :         const char *pszNBITS = CSLFetchNameValue(papszOptions, GDALMD_NBITS);
     592          60 :         if (pszNBITS && atoi(pszNBITS) > 0)
     593           2 :             psClient->pBands[iBand].nBits = (UINT8)atoi(pszNBITS);
     594             :         else
     595          58 :             psClient->pBands[iBand].nBits = (UINT8)nBits;
     596          60 :         psClient->pBands[iBand].bSigned = (BOOLEAN)bSigned;
     597             : #if ECWSDK_VERSION >= 50
     598             :         psClient->pBands[iBand].szDesc =
     599             :             NCSStrDup(papszBandDescriptions[iBand]);
     600             : #else
     601         120 :         psClient->pBands[iBand].szDesc =
     602          60 :             NCSStrDup((char *)papszBandDescriptions[iBand]);
     603             : #endif
     604             :     }
     605             : 
     606             :     /* -------------------------------------------------------------------- */
     607             :     /*      Allow CNCSFile::SetParameter() requests.                        */
     608             :     /* -------------------------------------------------------------------- */
     609             : 
     610          38 :     if (bIsJPEG2000)
     611             :     {
     612          33 :         pszOption = CSLFetchNameValue(papszOptions, "PROFILE");
     613          33 :         if (pszOption != nullptr && EQUAL(pszOption, "BASELINE_0"))
     614           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_0);
     615          33 :         else if (pszOption != nullptr && EQUAL(pszOption, "BASELINE_1"))
     616           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_1);
     617          33 :         else if (pszOption != nullptr && EQUAL(pszOption, "BASELINE_2"))
     618           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_2);
     619          33 :         else if (pszOption != nullptr && EQUAL(pszOption, "NPJE"))
     620           7 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_NPJE);
     621          26 :         else if (pszOption != nullptr && EQUAL(pszOption, "EPJE"))
     622           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_EPJE);
     623             : 
     624          33 :         pszOption = CSLFetchNameValue(papszOptions, "CODESTREAM_ONLY");
     625          62 :         if (pszOption == nullptr &&
     626          62 :             EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "j2k"))
     627           2 :             pszOption = "YES";
     628          33 :         if (pszOption != nullptr)
     629          12 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_CODESTREAM_ONLY,
     630           6 :                          CPLTestBool(pszOption));
     631             : 
     632          33 :         pszOption = CSLFetchNameValue(papszOptions, "LEVELS");
     633          33 :         if (pszOption != nullptr)
     634           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_LEVELS,
     635           0 :                          (UINT32)atoi(pszOption));
     636             : 
     637          33 :         pszOption = CSLFetchNameValue(papszOptions, "LAYERS");
     638          33 :         if (pszOption != nullptr)
     639           3 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_LAYERS,
     640           3 :                          (UINT32)atoi(pszOption));
     641             : 
     642          33 :         pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_WIDTH");
     643          33 :         if (pszOption != nullptr)
     644           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PRECINCT_WIDTH,
     645           0 :                          (UINT32)atoi(pszOption));
     646             : 
     647          33 :         pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_HEIGHT");
     648          33 :         if (pszOption != nullptr)
     649           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PRECINCT_HEIGHT,
     650           0 :                          (UINT32)atoi(pszOption));
     651             : 
     652          33 :         pszOption = CSLFetchNameValue(papszOptions, "TILE_WIDTH");
     653          33 :         if (pszOption != nullptr)
     654           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_TILE_WIDTH,
     655           0 :                          (UINT32)atoi(pszOption));
     656             : 
     657          33 :         pszOption = CSLFetchNameValue(papszOptions, "TILE_HEIGHT");
     658          33 :         if (pszOption != nullptr)
     659           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_TILE_HEIGHT,
     660           0 :                          (UINT32)atoi(pszOption));
     661             : 
     662          33 :         pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_SOP");
     663          33 :         if (pszOption != nullptr)
     664           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_INCLUDE_SOP,
     665           0 :                          CPLTestBool(pszOption));
     666             : 
     667          33 :         pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_EPH");
     668          33 :         if (pszOption != nullptr)
     669           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_INCLUDE_EPH,
     670           0 :                          CPLTestBool(pszOption));
     671             : 
     672          33 :         pszOption = CSLFetchNameValue(papszOptions, "PROGRESSION");
     673          33 :         if (pszOption != nullptr && EQUAL(pszOption, "LRCP"))
     674           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_LRCP);
     675             : 
     676          33 :         else if (pszOption != nullptr && EQUAL(pszOption, "RLCP"))
     677           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RLCP);
     678             : 
     679          33 :         else if (pszOption != nullptr && EQUAL(pszOption, "RPCL"))
     680           0 :             SetParameter(CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RPCL);
     681             : 
     682          33 :         pszOption = CSLFetchNameValue(papszOptions, "GEODATA_USAGE");
     683          33 :         if (pszOption == nullptr)
     684             :             // Default to suppressing ECW SDK geodata, just use our own stuff.
     685          33 :             SetGeodataUsage(JP2_GEODATA_USE_NONE);
     686           0 :         else if (EQUAL(pszOption, "NONE"))
     687           0 :             SetGeodataUsage(JP2_GEODATA_USE_NONE);
     688           0 :         else if (EQUAL(pszOption, "PCS_ONLY"))
     689           0 :             SetGeodataUsage(JP2_GEODATA_USE_PCS_ONLY);
     690           0 :         else if (EQUAL(pszOption, "GML_ONLY"))
     691           0 :             SetGeodataUsage(JP2_GEODATA_USE_GML_ONLY);
     692           0 :         else if (EQUAL(pszOption, "PCS_GML"))
     693           0 :             SetGeodataUsage(JP2_GEODATA_USE_PCS_GML);
     694           0 :         else if (EQUAL(pszOption, "GML_PCS"))
     695           0 :             SetGeodataUsage(JP2_GEODATA_USE_GML_PCS);
     696           0 :         else if (EQUAL(pszOption, "ALL"))
     697           0 :             SetGeodataUsage(JP2_GEODATA_USE_GML_PCS_WLD);
     698             : 
     699          33 :         pszOption = CSLFetchNameValue(papszOptions, "DECOMPRESS_LAYERS");
     700          33 :         if (pszOption != nullptr)
     701           0 :             SetParameter(CNCSJP2FileView::JP2_DECOMPRESS_LAYERS,
     702           0 :                          (UINT32)atoi(pszOption));
     703             : 
     704          33 :         pszOption = CSLFetchNameValue(papszOptions,
     705             :                                       "DECOMPRESS_RECONSTRUCTION_PARAMETER");
     706          33 :         if (pszOption != nullptr)
     707           0 :             SetParameter(
     708             :                 CNCSJP2FileView::JPC_DECOMPRESS_RECONSTRUCTION_PARAMETER,
     709           0 :                 (IEEE4)CPLAtof(pszOption));
     710             :     }
     711             : 
     712             :     /* -------------------------------------------------------------------- */
     713             :     /*      Georeferencing.                                                 */
     714             :     /* -------------------------------------------------------------------- */
     715             : 
     716          38 :     psClient->fOriginX = 0.0;
     717          38 :     psClient->fOriginY = psClient->nSizeY;
     718          38 :     psClient->fCellIncrementX = 1.0;
     719          38 :     psClient->fCellIncrementY = -1.0;
     720          38 :     psClient->fCWRotationDegrees = 0.0;
     721             : 
     722          38 :     if (gt.xrot != 0.0 || gt.yrot != 0.0)
     723           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     724             :                  "Rotational coefficients ignored, georeferencing of\n"
     725             :                  "output ECW file will be incorrect.");
     726             :     else
     727             :     {
     728          38 :         psClient->fOriginX = gt.xorig;
     729          38 :         psClient->fOriginY = gt.yorig;
     730          38 :         psClient->fCellIncrementX = gt.xscale;
     731          38 :         psClient->fCellIncrementY = gt.yscale;
     732             :     }
     733             : 
     734             :     /* -------------------------------------------------------------------- */
     735             :     /*      Projection.                                                     */
     736             :     /* -------------------------------------------------------------------- */
     737             :     char szProjection[128];
     738             :     char szDatum[128];
     739             :     char szUnits[128];
     740             : 
     741          38 :     strcpy(szProjection, "RAW");
     742          38 :     strcpy(szDatum, "RAW");
     743             : 
     744          38 :     if (CSLFetchNameValue(papszOptions, "PROJ") != nullptr)
     745             :     {
     746           0 :         strncpy(szProjection, CSLFetchNameValue(papszOptions, "PROJ"),
     747             :                 sizeof(szProjection));
     748           0 :         szProjection[sizeof(szProjection) - 1] = 0;
     749             :     }
     750             : 
     751          38 :     if (CSLFetchNameValue(papszOptions, "DATUM") != nullptr)
     752             :     {
     753           0 :         strncpy(szDatum, CSLFetchNameValue(papszOptions, "DATUM"),
     754             :                 sizeof(szDatum));
     755           0 :         szDatum[sizeof(szDatum) - 1] = 0;
     756           0 :         if (EQUAL(szProjection, "RAW"))
     757           0 :             strcpy(szProjection, "GEODETIC");
     758             :     }
     759             : 
     760          38 :     const char *pszUnits = CSLFetchNameValue(papszOptions, "UNITS");
     761          38 :     if (pszUnits != nullptr)
     762             :     {
     763           0 :         psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(pszUnits);
     764             :     }
     765             : 
     766          38 :     if (EQUAL(szProjection, "RAW") && poSRS != nullptr && !poSRS->IsEmpty())
     767             :     {
     768          25 :         ECWTranslateFromWKT(poSRS, szProjection, sizeof(szProjection), szDatum,
     769             :                             sizeof(szDatum), szUnits);
     770          25 :         psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
     771             :     }
     772             : 
     773          38 :     NCSFree(psClient->szDatum);
     774          38 :     psClient->szDatum = NCSStrDup(szDatum);
     775          38 :     NCSFree(psClient->szProjection);
     776          38 :     psClient->szProjection = NCSStrDup(szProjection);
     777             : 
     778          38 :     CPLDebug("ECW", "Writing with PROJ=%s, DATUM=%s, UNITS=%s", szProjection,
     779             :              szDatum, ECWTranslateFromCellSizeUnits(psClient->eCellSizeUnits));
     780             : 
     781             :     /* -------------------------------------------------------------------- */
     782             :     /*      Setup GML and GeoTIFF information.                              */
     783             :     /* -------------------------------------------------------------------- */
     784          38 :     if ((poSRS != nullptr && !poSRS->IsEmpty()) || gt != GDALGeoTransform() ||
     785          76 :         nGCPCount > 0 || papszRPCMD != nullptr)
     786             :     {
     787          74 :         GDALJP2Metadata oJP2MD;
     788             : 
     789          37 :         oJP2MD.SetSpatialRef(poSRS);
     790          37 :         oJP2MD.SetGeoTransform(gt);
     791          37 :         oJP2MD.SetGCPs(nGCPCount, pasGCPList);
     792          37 :         oJP2MD.bPixelIsPoint = bPixelIsPoint;
     793          37 :         oJP2MD.SetRPCMD(papszRPCMD);
     794             : 
     795          37 :         if (bIsJPEG2000)
     796             :         {
     797          32 :             if (CPLFetchBool(papszOptions, "WRITE_METADATA", false))
     798             :             {
     799           6 :                 if (!CPLFetchBool(papszOptions, "MAIN_MD_DOMAIN_ONLY", false))
     800             :                 {
     801           6 :                     WriteXMLBoxes();
     802             :                 }
     803           6 :                 WriteJP2Box(
     804             :                     GDALJP2Metadata::CreateGDALMultiDomainMetadataXMLBox(
     805           6 :                         m_poSrcDS, CPLFetchBool(papszOptions,
     806             :                                                 "MAIN_MD_DOMAIN_ONLY", false)));
     807             :             }
     808          32 :             if (CPLFetchBool(papszOptions, "GMLJP2", true))
     809             :             {
     810             :                 const char *pszGMLJP2V2Def =
     811          29 :                     CSLFetchNameValue(papszOptions, "GMLJP2V2_DEF");
     812          29 :                 if (pszGMLJP2V2Def != nullptr)
     813             :                 {
     814           0 :                     WriteJP2Box(oJP2MD.CreateGMLJP2V2(nXSize, nYSize,
     815             :                                                       pszGMLJP2V2Def, poSrcDS));
     816             :                 }
     817             :                 else
     818             :                 {
     819          48 :                     if (!poSRS || poSRS->IsEmpty() ||
     820          19 :                         GDALJP2Metadata::IsSRSCompatible(poSRS))
     821             :                     {
     822          28 :                         WriteJP2Box(oJP2MD.CreateGMLJP2(nXSize, nYSize));
     823             :                     }
     824           1 :                     else if (CSLFetchNameValue(papszOptions, "GMLJP2"))
     825             :                     {
     826           0 :                         CPLError(CE_Warning, CPLE_AppDefined,
     827             :                                  "GMLJP2 box was explicitly required but "
     828             :                                  "cannot be written due "
     829             :                                  "to lack of georeferencing and/or unsupported "
     830             :                                  "georeferencing "
     831             :                                  "for GMLJP2");
     832             :                     }
     833             :                     else
     834             :                     {
     835           1 :                         CPLDebug(
     836             :                             "JP2ECW",
     837             :                             "Cannot write GMLJP2 box due to unsupported SRS");
     838             :                     }
     839             :                 }
     840             :             }
     841          32 :             if (CPLFetchBool(papszOptions, "GeoJP2", true))
     842          29 :                 WriteJP2Box(oJP2MD.CreateJP2GeoTIFF());
     843          38 :             if (CPLFetchBool(papszOptions, "WRITE_METADATA", false) &&
     844           6 :                 !CPLFetchBool(papszOptions, "MAIN_MD_DOMAIN_ONLY", false))
     845             :             {
     846           6 :                 WriteJP2Box(GDALJP2Metadata::CreateXMPBox(m_poSrcDS));
     847             :             }
     848             :         }
     849             :     }
     850             :     /* -------------------------------------------------------------------- */
     851             :     /*      We handle all jpeg2000 files via the VSIIOStream, but ECW       */
     852             :     /*      files cannot be done this way for some reason.                  */
     853             :     /* -------------------------------------------------------------------- */
     854          38 :     VSILFILE *fpVSIL = nullptr;
     855             : 
     856          38 :     if (bIsJPEG2000)
     857             :     {
     858          66 :         int bSeekable = !(STARTS_WITH(pszFilename, "/vsistdout/") ||
     859          33 :                           STARTS_WITH(pszFilename, "/vsizip/") ||
     860          33 :                           STARTS_WITH(pszFilename, "/vsigzip/"));
     861          33 :         fpVSIL = VSIFOpenL(pszFilename, (bSeekable) ? "wb+" : "wb");
     862          33 :         if (fpVSIL == nullptr)
     863             :         {
     864           2 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open/create %s.",
     865             :                      pszFilename);
     866           2 :             return CE_Failure;
     867             :         }
     868             : 
     869          31 :         m_OStream->Access(fpVSIL, TRUE, (BOOLEAN)bSeekable, pszFilename, 0, -1);
     870             :     }
     871             :     else
     872             :     {
     873           5 :         if (!STARTS_WITH(pszFilename, "/vsi"))
     874             :         {
     875             :             // Try now to create the file to avoid memory leaks if it is
     876             :             // the SDK that fails to do it.
     877           5 :             fpVSIL = VSIFOpenL(pszFilename, "wb");
     878           5 :             if (fpVSIL == nullptr)
     879             :             {
     880           2 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     881             :                          "Failed to open/create %s.", pszFilename);
     882           2 :                 return CE_Failure;
     883             :             }
     884           3 :             VSIFCloseL(fpVSIL);
     885           3 :             VSIUnlink(pszFilename);
     886           3 :             fpVSIL = nullptr;
     887             :         }
     888             :     }
     889             : 
     890             : /* -------------------------------------------------------------------- */
     891             : /*      Check if we can enable large files.  This option should only    */
     892             : /*      be set when the application is adhering to one of the           */
     893             : /*      ERMapper options for licensing larger than 500MB input          */
     894             : /*      files.  See Bug 767.  This option no longer exists with         */
     895             : /*      version 4+.                                                     */
     896             : /* -------------------------------------------------------------------- */
     897             : #if ECWSDK_VERSION < 40
     898          34 :     const char *pszLargeOK = CSLFetchNameValue(papszOptions, "LARGE_OK");
     899          34 :     if (pszLargeOK == nullptr)
     900          34 :         pszLargeOK = "NO";
     901             : 
     902          34 :     pszLargeOK = CPLGetConfigOption("ECW_LARGE_OK", pszLargeOK);
     903             : 
     904          34 :     if (CPLTestBool(pszLargeOK))
     905             :     {
     906           0 :         CNCSFile::SetKeySize();
     907           0 :         CPLDebug("ECW", "Large file generation enabled.");
     908             :     }
     909             : #endif /* ECWSDK_VERSION < 40 */
     910             : /* -------------------------------------------------------------------- */
     911             : /*      Infer metadata information from source dataset if possible      */
     912             : /* -------------------------------------------------------------------- */
     913             : #if ECWSDK_VERSION >= 50
     914             :     if (psClient->nFormatVersion > 2)
     915             :     {
     916             :         if (psClient->pFileMetaData == nullptr)
     917             :         {
     918             :             NCSEcwInitMetaData(&psClient->pFileMetaData);
     919             :         }
     920             :         if (m_poSrcDS && m_poSrcDS->GetMetadataItem(
     921             :                              "FILE_METADATA_ACQUISITION_DATE") != nullptr)
     922             :         {
     923             :             psClient->pFileMetaData->sAcquisitionDate =
     924             :                 NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem(
     925             :                                             "FILE_METADATA_ACQUISITION_DATE"))
     926             :                                .c_str());
     927             :         }
     928             : 
     929             :         if (m_poSrcDS &&
     930             :             m_poSrcDS->GetMetadataItem(
     931             :                 "FILE_METADATA_ACQUISITION_SENSOR_NAME") != nullptr)
     932             :         {
     933             :             psClient->pFileMetaData->sAcquisitionSensorName = NCSStrDupT(
     934             :                 NCS::CString(m_poSrcDS->GetMetadataItem(
     935             :                                  "FILE_METADATA_ACQUISITION_SENSOR_NAME"))
     936             :                     .c_str());
     937             :         }
     938             :         if (m_poSrcDS &&
     939             :             m_poSrcDS->GetMetadataItem("FILE_METADATA_ADDRESS") != nullptr)
     940             :         {
     941             :             psClient->pFileMetaData->sAddress =
     942             :                 NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem(
     943             :                                             "FILE_METADATA_ADDRESS"))
     944             :                                .c_str());
     945             :         }
     946             :         if (m_poSrcDS &&
     947             :             m_poSrcDS->GetMetadataItem("FILE_METADATA_AUTHOR") != nullptr)
     948             :         {
     949             :             psClient->pFileMetaData->sAuthor = NCSStrDupT(
     950             :                 NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_AUTHOR"))
     951             :                     .c_str());
     952             :         }
     953             :         if (m_poSrcDS && m_poSrcDS->GetMetadataItem(
     954             :                              "FILE_METADATA_CLASSIFICATION") != nullptr)
     955             :         {
     956             :             psClient->pFileMetaData->sClassification =
     957             :                 NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem(
     958             :                                             "FILE_METADATA_CLASSIFICATION"))
     959             :                                .c_str());
     960             :         }
     961             :         if (pszECWCompany != nullptr &&
     962             :             CPLTestBool(CPLGetConfigOption("GDAL_ECW_WRITE_COMPANY", "YES")))
     963             :         {
     964             :             psClient->pFileMetaData->sCompany =
     965             :                 NCSStrDupT(NCS::CString(pszECWCompany).c_str());
     966             :         }
     967             :         CPLString osCompressionSoftware = GetCompressionSoftwareName();
     968             :         if (!osCompressionSoftware.empty())
     969             :         {
     970             :             psClient->pFileMetaData->sCompressionSoftware =
     971             :                 NCSStrDupT(NCS::CString(osCompressionSoftware.c_str()).c_str());
     972             :         }
     973             :         if (m_poSrcDS &&
     974             :             m_poSrcDS->GetMetadataItem("FILE_METADATA_COPYRIGHT") != nullptr)
     975             :         {
     976             :             psClient->pFileMetaData->sCopyright =
     977             :                 NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem(
     978             :                                             "FILE_METADATA_COPYRIGHT"))
     979             :                                .c_str());
     980             :         }
     981             :         if (m_poSrcDS &&
     982             :             m_poSrcDS->GetMetadataItem("FILE_METADATA_EMAIL") != nullptr)
     983             :         {
     984             :             psClient->pFileMetaData->sEmail = NCSStrDupT(
     985             :                 NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_EMAIL"))
     986             :                     .c_str());
     987             :         }
     988             :         if (m_poSrcDS &&
     989             :             m_poSrcDS->GetMetadataItem("FILE_METADATA_TELEPHONE") != nullptr)
     990             :         {
     991             :             psClient->pFileMetaData->sTelephone =
     992             :                 NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem(
     993             :                                             "FILE_METADATA_TELEPHONE"))
     994             :                                .c_str());
     995             :         }
     996             :     }
     997             : #endif
     998             :     /* -------------------------------------------------------------------- */
     999             :     /*      Set the file info.                                              */
    1000             :     /* -------------------------------------------------------------------- */
    1001          68 :     CNCSError oError = SetFileInfo(sFileInfo);
    1002             : 
    1003          34 :     if (oError.GetErrorNumber() == NCS_SUCCESS)
    1004             :     {
    1005          34 :         if (fpVSIL == nullptr)
    1006             :         {
    1007             : #if ECWSDK_VERSION >= 40 && defined(_WIN32)
    1008             :             if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
    1009             :             {
    1010             :                 wchar_t *pwszFilename =
    1011             :                     CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
    1012             :                 oError = GetCNCSError(Open(pwszFilename, false, true));
    1013             :                 CPLFree(pwszFilename);
    1014             :             }
    1015             :             else
    1016             : #endif
    1017             :             {
    1018           3 :                 oError = GetCNCSError(Open((char *)pszFilename, false, true));
    1019             :             }
    1020             :         }
    1021             :         else
    1022             :         {
    1023             : #if ECWSDK_VERSION >= 55
    1024             :             oError = CNCSJP2FileView::Open(m_OStream);
    1025             : #else
    1026          31 :             oError = CNCSJP2FileView::Open(m_OStream.get());
    1027             : #endif
    1028             :         }
    1029             :     }
    1030             : 
    1031          34 :     if (oError.GetErrorNumber() == NCS_SUCCESS)
    1032          34 :         return CE_None;
    1033           0 :     else if (oError.GetErrorNumber() == NCS_INPUT_SIZE_EXCEEDED)
    1034             :     {
    1035           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1036             :                  "ECW SDK compress limit exceeded.");
    1037           0 :         return CE_Failure;
    1038             :     }
    1039             :     else
    1040             :     {
    1041           0 :         ECWReportError(oError);
    1042             : 
    1043           0 :         return CE_Failure;
    1044             :     }
    1045             : }
    1046             : 
    1047             : /************************************************************************/
    1048             : /*                      ECWIsInputRGBColorSpace()                       */
    1049             : /************************************************************************/
    1050             : 
    1051          38 : static int ECWIsInputRGBColorSpace(GDALDataset *poSrcDS)
    1052             : {
    1053          38 :     int nBands = poSrcDS->GetRasterCount();
    1054             : 
    1055             :     /* -------------------------------------------------------------------- */
    1056             :     /*      Is the input RGB or RGBA?                                       */
    1057             :     /* -------------------------------------------------------------------- */
    1058          38 :     int bRGBColorSpace = FALSE;
    1059          38 :     int bRGB = FALSE;
    1060          38 :     if (nBands >= 3)
    1061             :     {
    1062           8 :         bRGB = (poSrcDS->GetRasterBand(1)->GetColorInterpretation() ==
    1063             :                 GCI_RedBand);
    1064           8 :         bRGB &= (poSrcDS->GetRasterBand(2)->GetColorInterpretation() ==
    1065             :                  GCI_GreenBand);
    1066           8 :         bRGB &= (poSrcDS->GetRasterBand(3)->GetColorInterpretation() ==
    1067             :                  GCI_BlueBand);
    1068             :     }
    1069          38 :     if (nBands == 3)
    1070             :     {
    1071           6 :         bRGBColorSpace = bRGB;
    1072             :     }
    1073          32 :     else if (nBands == 4 && bRGB)
    1074             :     {
    1075           0 :         bRGBColorSpace = (poSrcDS->GetRasterBand(4)->GetColorInterpretation() ==
    1076             :                           GCI_AlphaBand);
    1077             :     }
    1078             : 
    1079          38 :     return bRGBColorSpace;
    1080             : }
    1081             : 
    1082             : /************************************************************************/
    1083             : /*                           ECWCreateCopy()                            */
    1084             : /************************************************************************/
    1085             : 
    1086          36 : static GDALDataset *ECWCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
    1087             :                                   int bStrict, CSLConstList papszOptions,
    1088             :                                   GDALProgressFunc pfnProgress,
    1089             :                                   void *pProgressData, int bIsJPEG2000)
    1090             : 
    1091             : {
    1092          36 :     ECWInitialize();
    1093             : 
    1094             :     /* -------------------------------------------------------------------- */
    1095             :     /*      Get various values from the source dataset.                     */
    1096             :     /* -------------------------------------------------------------------- */
    1097          36 :     int nBands = poSrcDS->GetRasterCount();
    1098          36 :     int nXSize = poSrcDS->GetRasterXSize();
    1099          36 :     int nYSize = poSrcDS->GetRasterYSize();
    1100             : 
    1101          36 :     if (nBands == 0)
    1102             :     {
    1103           0 :         CPLError(
    1104             :             CE_Failure, CPLE_NotSupported,
    1105             :             "ECW driver does not support source datasets with zero bands.");
    1106           0 :         return nullptr;
    1107             :     }
    1108             : 
    1109          36 :     GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
    1110             : 
    1111          36 :     const OGRSpatialReference *poSRS = poSrcDS->GetSpatialRef();
    1112          36 :     GDALGeoTransform gt;
    1113          36 :     poSrcDS->GetGeoTransform(gt);
    1114             : 
    1115          36 :     if (poSrcDS->GetGCPCount() > 0)
    1116           1 :         poSRS = poSrcDS->GetGCPSpatialRef();
    1117             : 
    1118             :     /* --------------------------------------------------------------------
    1119             :          */
    1120             :     /*      For ECW, confirm the datatype is 8bit (or uint16 for ECW v3) */
    1121             :     /* --------------------------------------------------------------------
    1122             :          */
    1123             : #if ECWSDK_VERSION >= 50
    1124             :     bool bECWV3 = false;
    1125             :     if (bIsJPEG2000 == FALSE)
    1126             :     {
    1127             :         const char *pszOption =
    1128             :             CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
    1129             :         if (pszOption != nullptr)
    1130             :         {
    1131             :             bECWV3 = (3 == atoi(pszOption));
    1132             :         }
    1133             :     }
    1134             : #endif
    1135          36 :     if (!(eType == GDT_UInt8 ||
    1136             : #if ECWSDK_VERSION >= 50
    1137             :           (bECWV3 && eType == GDT_UInt16) ||
    1138             : #endif
    1139             :           bIsJPEG2000))
    1140             :     {
    1141           0 :         if (bStrict)
    1142             :         {
    1143           0 :             CPLError(
    1144             :                 CE_Failure, CPLE_AppDefined,
    1145             :                 "Attempt to create ECW file with pixel data type %s failed.\n"
    1146             :                 "Only Byte data type supported for ECW version 2 files."
    1147             : #if ECWSDK_VERSION >= 50
    1148             :                 " ECW version 3 files supports UInt16 as well."
    1149             :                 " Specify ECW_FORMAT_VERSION=3 creation option to write "
    1150             :                 "version 3 file. \n"
    1151             : #else
    1152             :                 ". \n"
    1153             : #endif
    1154             :                 ,
    1155             :                 GDALGetDataTypeName(eType));
    1156             :         }
    1157             :         else
    1158             :         {
    1159             : #if ECWSDK_VERSION >= 50
    1160             :             if (eType == GDT_UInt16)
    1161             :             {
    1162             :                 CPLError(CE_Warning, CPLE_AppDefined,
    1163             :                          "ECW version 2 does not support UInt16 data type, "
    1164             :                          "truncating to Byte."
    1165             :                          " Consider specifying ECW_FORMAT_VERSION=3 for full "
    1166             :                          "UInt16 support available in ECW version 3. ");
    1167             :             }
    1168             :             else
    1169             : #endif
    1170           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1171             :                          "ECW v2 does not support data type, ignoring request "
    1172             :                          "for %s. \n",
    1173             :                          GDALGetDataTypeName(eType));
    1174             : 
    1175           0 :             eType = GDT_UInt8;
    1176             :         }
    1177             :     }
    1178             : 
    1179             :     /* -------------------------------------------------------------------- */
    1180             :     /*      Is the input RGB or RGBA?                                       */
    1181             :     /* -------------------------------------------------------------------- */
    1182          36 :     int bRGBColorSpace = ECWIsInputRGBColorSpace(poSrcDS);
    1183             : 
    1184             :     /* -------------------------------------------------------------------- */
    1185             :     /*      Setup the compressor.                                           */
    1186             :     /* -------------------------------------------------------------------- */
    1187          72 :     GDALECWCompressor oCompressor;
    1188             : 
    1189          36 :     oCompressor.pfnProgress = pfnProgress;
    1190          36 :     oCompressor.pProgressData = pProgressData;
    1191          36 :     oCompressor.m_poSrcDS = poSrcDS;
    1192             : 
    1193          72 :     CPLStringList aosBandDescriptions;
    1194          92 :     for (int i = 0; i < nBands; i++)
    1195             :     {
    1196             :         /* Make a copy since ECWGetColorInterpretationName() can return a string
    1197             :          * generated */
    1198             :         /* by CPLSPrintf(), which has just a few rotating entries. */
    1199             :         aosBandDescriptions.AddString(ECWGetColorInterpretationName(
    1200          56 :             poSrcDS->GetRasterBand(i + 1)->GetColorInterpretation(), i));
    1201             :     }
    1202             : 
    1203          36 :     const char *pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
    1204          36 :     int bPixelIsPoint =
    1205          36 :         pszAreaOrPoint != nullptr && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
    1206             : 
    1207          36 :     if (oCompressor.Initialize(
    1208             :             pszFilename, papszOptions, nXSize, nYSize, nBands,
    1209          36 :             aosBandDescriptions.List(), bRGBColorSpace, eType, poSRS, gt,
    1210          36 :             poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(), bIsJPEG2000,
    1211          36 :             bPixelIsPoint, poSrcDS->GetMetadata(GDAL_MDD_RPC),
    1212          36 :             poSrcDS) != CE_None)
    1213             :     {
    1214           4 :         return nullptr;
    1215             :     }
    1216             : 
    1217             :     /* -------------------------------------------------------------------- */
    1218             :     /*      Start the compression.                                          */
    1219             :     /* -------------------------------------------------------------------- */
    1220             : 
    1221          32 :     if (!pfnProgress(0.0, nullptr, pProgressData))
    1222           0 :         return nullptr;
    1223             : 
    1224          64 :     CNCSError oErr = oCompressor.Write();
    1225             : 
    1226          32 :     if (oErr.GetErrorNumber() != NCS_SUCCESS)
    1227             :     {
    1228           0 :         ECWReportError(oErr);
    1229           0 :         return nullptr;
    1230             :     }
    1231             : 
    1232             :     /* -------------------------------------------------------------------- */
    1233             :     /*      Cleanup, and return read-only handle.                           */
    1234             :     /* -------------------------------------------------------------------- */
    1235          32 :     oCompressor.CloseDown();
    1236          32 :     pfnProgress(1.0, nullptr, pProgressData);
    1237             : 
    1238             :     /* -------------------------------------------------------------------- */
    1239             :     /*      Re-open dataset, and copy any auxiliary pam information.         */
    1240             :     /* -------------------------------------------------------------------- */
    1241          32 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
    1242          32 :     GDALPamDataset *poDS = nullptr;
    1243             : 
    1244          32 :     if (bIsJPEG2000)
    1245          29 :         poDS = cpl::down_cast<GDALPamDataset *>(
    1246             :             ECWDatasetOpenJPEG2000(&oOpenInfo));
    1247             :     else
    1248             :         poDS =
    1249           3 :             cpl::down_cast<GDALPamDataset *>(ECWDataset::OpenECW(&oOpenInfo));
    1250             : 
    1251          32 :     if (poDS)
    1252             :     {
    1253             : #if ECWSDK_VERSION >= 50
    1254             :         for (int i = 1; i <= poSrcDS->GetRasterCount(); i++)
    1255             :         {
    1256             :             double dMin, dMax, dMean, dStdDev;
    1257             :             if (poSrcDS->GetRasterBand(i)->GetStatistics(
    1258             :                     FALSE, FALSE, &dMin, &dMax, &dMean, &dStdDev) == CE_None)
    1259             :             {
    1260             :                 poDS->GetRasterBand(i)->SetStatistics(dMin, dMax, dMean,
    1261             :                                                       dStdDev);
    1262             :             }
    1263             :             double dHistMin, dHistMax;
    1264             :             int nBuckets;
    1265             :             GUIntBig *pHistogram = nullptr;
    1266             :             if (poSrcDS->GetRasterBand(i)->GetDefaultHistogram(
    1267             :                     &dHistMin, &dHistMax, &nBuckets, &pHistogram, FALSE,
    1268             :                     nullptr, nullptr) == CE_None)
    1269             :             {
    1270             :                 poDS->GetRasterBand(i)->SetDefaultHistogram(
    1271             :                     dHistMin, dHistMax, nBuckets, pHistogram);
    1272             :                 VSIFree(pHistogram);
    1273             :             }
    1274             :         }
    1275             : #endif
    1276             : 
    1277          32 :         cpl::down_cast<ECWDataset *>(poDS)->SetPreventCopyingSomeMetadata(TRUE);
    1278          32 :         int nFlags = GCIF_PAM_DEFAULT;
    1279          32 :         if (bIsJPEG2000 && !CPLFetchBool(papszOptions, "WRITE_METADATA", false))
    1280          23 :             nFlags &= ~GCIF_METADATA;
    1281          32 :         poDS->CloneInfo(poSrcDS, nFlags);
    1282          32 :         cpl::down_cast<ECWDataset *>(poDS)->SetPreventCopyingSomeMetadata(
    1283             :             FALSE);
    1284             :     }
    1285             : 
    1286          32 :     return poDS;
    1287             : }
    1288             : 
    1289             : /************************************************************************/
    1290             : /*                          ECWCreateCopyECW()                          */
    1291             : /************************************************************************/
    1292             : 
    1293          21 : GDALDataset *ECWCreateCopyECW(const char *pszFilename, GDALDataset *poSrcDS,
    1294             :                               int bStrict, CSLConstList papszOptions,
    1295             :                               GDALProgressFunc pfnProgress, void *pProgressData)
    1296             : 
    1297             : {
    1298          21 :     int nBands = poSrcDS->GetRasterCount();
    1299          21 :     if (nBands == 0)
    1300             :     {
    1301           1 :         CPLError(
    1302             :             CE_Failure, CPLE_NotSupported,
    1303             :             "ECW driver does not support source datasets with zero bands.");
    1304           1 :         return nullptr;
    1305             :     }
    1306             : 
    1307          20 :     if (!EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "ecw"))
    1308             :     {
    1309           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1310             :                  "ECW driver does not support creating ECW files\n"
    1311             :                  "with an extension other than .ecw");
    1312           0 :         return nullptr;
    1313             :     }
    1314             : 
    1315             : #if ECWSDK_VERSION >= 50
    1316             :     bool bECWV3 = false;
    1317             :     const char *pszOption =
    1318             :         CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
    1319             :     if (pszOption != nullptr)
    1320             :     {
    1321             :         bECWV3 = (3 == atoi(pszOption));
    1322             :     }
    1323             : 
    1324             : #endif
    1325             : 
    1326          20 :     GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
    1327          20 :     if (eDataType != GDT_UInt8
    1328             : #if ECWSDK_VERSION >= 50
    1329             :         && !(bECWV3 && (eDataType == GDT_UInt16))
    1330             : #endif
    1331          10 :         && bStrict)
    1332             :     {
    1333             : #if ECWSDK_VERSION >= 50
    1334             :         if (eDataType == GDT_UInt16)
    1335             :         {
    1336             :             CPLError(CE_Failure, CPLE_NotSupported,
    1337             :                      "ECW v2 does not support UInt16 data type. Consider "
    1338             :                      " specifying ECW_FORMAT_VERSION=3 for full UInt16 support "
    1339             :                      "available in ECW v3. ");
    1340             :         }
    1341             :         else
    1342             : #endif
    1343             :         {
    1344          10 :             CPLError(CE_Failure, CPLE_NotSupported,
    1345             :                      "ECW driver doesn't support data type %s. "
    1346             :                      "Only unsigned eight "
    1347             : #if ECWSDK_VERSION >= 50
    1348             :                      "or sixteen "
    1349             : #endif
    1350             :                      "bit bands supported. \n",
    1351             :                      GDALGetDataTypeName(eDataType));
    1352             :         }
    1353             : 
    1354          10 :         return nullptr;
    1355             :     }
    1356             : 
    1357          10 :     if (poSrcDS->GetRasterXSize() < 128 || poSrcDS->GetRasterYSize() < 128)
    1358             :     {
    1359           5 :         CPLError(CE_Failure, CPLE_NotSupported,
    1360             :                  "ECW driver requires image to be at least 128x128,\n"
    1361             :                  "the source image is %dx%d.\n",
    1362             :                  poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
    1363             : 
    1364           5 :         return nullptr;
    1365             :     }
    1366             : 
    1367           5 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr)
    1368             :     {
    1369           0 :         CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    1370             :                  "ECW driver ignores color table. "
    1371             :                  "The source raster band will be considered as grey level.\n"
    1372             :                  "Consider using color table expansion (-expand option in "
    1373             :                  "gdal_translate)");
    1374           0 :         if (bStrict)
    1375           0 :             return nullptr;
    1376             :     }
    1377             : 
    1378           5 :     return ECWCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
    1379           5 :                          pfnProgress, pProgressData, FALSE);
    1380             : }
    1381             : 
    1382             : /************************************************************************/
    1383             : /*                       ECWCreateCopyJPEG2000()                        */
    1384             : /************************************************************************/
    1385             : 
    1386          37 : GDALDataset *ECWCreateCopyJPEG2000(const char *pszFilename,
    1387             :                                    GDALDataset *poSrcDS, int bStrict,
    1388             :                                    CSLConstList papszOptions,
    1389             :                                    GDALProgressFunc pfnProgress,
    1390             :                                    void *pProgressData)
    1391             : 
    1392             : {
    1393          37 :     int nBands = poSrcDS->GetRasterCount();
    1394          37 :     if (nBands == 0)
    1395             :     {
    1396           1 :         CPLError(
    1397             :             CE_Failure, CPLE_NotSupported,
    1398             :             "JP2ECW driver does not support source datasets with zero bands.");
    1399           1 :         return nullptr;
    1400             :     }
    1401             : 
    1402          36 :     if (EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "ecw"))
    1403             :     {
    1404           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1405             :                  "JP2ECW driver does not support creating JPEG2000 files\n"
    1406             :                  "with a .ecw extension.  Please use anything else.");
    1407           0 :         return nullptr;
    1408             :     }
    1409             : 
    1410          36 :     GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
    1411          36 :     if (eDataType != GDT_UInt8 && eDataType != GDT_Int16 &&
    1412           8 :         eDataType != GDT_UInt16 && eDataType != GDT_Int32 &&
    1413           6 :         eDataType != GDT_UInt32 && eDataType != GDT_Float32
    1414             : #if ECWSDK_VERSION >= 40
    1415             :         && eDataType != GDT_Float64
    1416             : #endif
    1417           5 :         && bStrict)
    1418             :     {
    1419           5 :         CPLError(CE_Failure, CPLE_NotSupported,
    1420             :                  "JP2ECW driver doesn't support data type %s. ",
    1421             :                  GDALGetDataTypeName(eDataType));
    1422             : 
    1423           5 :         return nullptr;
    1424             :     }
    1425             : 
    1426          31 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr)
    1427             :     {
    1428           0 :         CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
    1429             :                  "JP2ECW driver ignores color table. "
    1430             :                  "The source raster band will be considered as grey level.\n"
    1431             :                  "Consider using color table expansion (-expand option in "
    1432             :                  "gdal_translate)");
    1433           0 :         if (bStrict)
    1434           0 :             return nullptr;
    1435             :     }
    1436             : 
    1437          31 :     return ECWCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
    1438          31 :                          pfnProgress, pProgressData, TRUE);
    1439             : }
    1440             : 
    1441             : /************************************************************************/
    1442             : /************************************************************************
    1443             : 
    1444             :                ECW/JPEG200 Create() Support
    1445             :                ----------------------------
    1446             : 
    1447             :   The remainder of the file is code to implement the Create() method.
    1448             :   New dataset and raster band classes are defined specifically for the
    1449             :   purpose of being write-only.  In particular, you cannot read back data
    1450             :   from these datasets, and writing must occur in a pretty specific order.
    1451             : 
    1452             :   That is, you need to write all metadata (projection, georef, etc) first
    1453             :   and then write the image data.  All bands data for the first scanline
    1454             :   should be written followed by all bands for the second scanline and so on.
    1455             : 
    1456             :   Creation supports the same virtual subfile names as CreateCopy() supports.
    1457             : 
    1458             :  ************************************************************************/
    1459             : /************************************************************************/
    1460             : 
    1461             : /************************************************************************/
    1462             : /* ==================================================================== */
    1463             : /*                              ECWWriteDataset                         */
    1464             : /* ==================================================================== */
    1465             : /************************************************************************/
    1466             : 
    1467             : class ECWWriteRasterBand;
    1468             : 
    1469             : #ifdef OPTIMIZED_FOR_GDALWARP
    1470             : class IRasterIORequest
    1471             : {
    1472             :   public:
    1473             :     GDALRasterBand *poBand;
    1474             :     int nXOff;
    1475             :     int nYOff;
    1476             :     int nXSize;
    1477             :     int nYSize;
    1478             :     GByte *pabyData;
    1479             :     int nBufXSize;
    1480             :     int nBufYSize;
    1481             : 
    1482           0 :     IRasterIORequest(GDALRasterBand *poBandIn, int nXOffIn, int nYOffIn,
    1483             :                      int nXSizeIn, int nYSizeIn, void *pData, int nBufXSizeIn,
    1484             :                      int nBufYSizeIn, GDALDataType eBufType,
    1485             :                      GSpacing nPixelSpace, GSpacing nLineSpace)
    1486           0 :         : poBand(poBandIn), nXOff(nXOffIn), nYOff(nYOffIn), nXSize(nXSizeIn),
    1487             :           nYSize(nYSizeIn), pabyData(nullptr), nBufXSize(nBufXSizeIn),
    1488           0 :           nBufYSize(nBufYSizeIn)
    1489             :     {
    1490           0 :         GDALDataType eDataType = poBand->GetRasterDataType();
    1491           0 :         const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1492           0 :         pabyData = (GByte *)CPLMalloc(static_cast<size_t>(nBufXSize) *
    1493           0 :                                       nBufYSize * nDataTypeSize);
    1494           0 :         for (int iY = 0; iY < nBufYSize; iY++)
    1495             :         {
    1496           0 :             GDALCopyWords((GByte *)pData + iY * nLineSpace, eBufType,
    1497             :                           static_cast<int>(nPixelSpace),
    1498           0 :                           pabyData + static_cast<size_t>(iY) * nBufXSize *
    1499           0 :                                          nDataTypeSize,
    1500             :                           eDataType, nDataTypeSize, nBufXSize);
    1501             :         }
    1502           0 :     }
    1503             : 
    1504           0 :     ~IRasterIORequest()
    1505           0 :     {
    1506           0 :         CPLFree(pabyData);
    1507           0 :     }
    1508             : };
    1509             : #endif
    1510             : 
    1511             : class ECWWriteDataset final : public GDALDataset
    1512             : {
    1513             :     friend class ECWWriteRasterBand;
    1514             : 
    1515             :     char *pszFilename;
    1516             : 
    1517             :     int bIsJPEG2000;
    1518             :     GDALDataType eDataType;
    1519             :     char **papszOptions;
    1520             : 
    1521             :     OGRSpatialReference m_oSRS{};
    1522             :     GDALGeoTransform m_gt{};
    1523             : 
    1524             :     GDALECWCompressor oCompressor;
    1525             :     int bCrystalized;  // TODO: Spelling.
    1526             : 
    1527             :     int nLoadedLine;
    1528             :     GByte *pabyBILBuffer;
    1529             : 
    1530             :     int bOutOfOrderWriteOccurred;
    1531             : #ifdef OPTIMIZED_FOR_GDALWARP
    1532             :     int nPrevIRasterIOBand;
    1533             : #endif
    1534             : 
    1535             :     CPLErr Crystalize();  // TODO: Spelling.
    1536             :     CPLErr FlushLine();
    1537             : 
    1538             :   public:
    1539             :     ECWWriteDataset(const char *, int, int, int, GDALDataType,
    1540             :                     CSLConstList papszOptions, int);
    1541             :     ~ECWWriteDataset() override;
    1542             : 
    1543             :     CPLErr FlushCache(bool bAtClosing) override;
    1544             : 
    1545             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
    1546             :     CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
    1547             :     const OGRSpatialReference *GetSpatialRef() const override;
    1548             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
    1549             : 
    1550             : #ifdef OPTIMIZED_FOR_GDALWARP
    1551             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
    1552             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
    1553             :                      GDALDataType eBufType, int nBandCount,
    1554             :                      BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
    1555             :                      GSpacing nLineSpace, GSpacing nBandSpace,
    1556             :                      GDALRasterIOExtraArg *psExtraArg) override;
    1557             : #endif
    1558             : };
    1559             : 
    1560             : /************************************************************************/
    1561             : /* ==================================================================== */
    1562             : /*                         ECWWriteRasterBand                           */
    1563             : /* ==================================================================== */
    1564             : /************************************************************************/
    1565             : 
    1566             : class ECWWriteRasterBand final : public GDALRasterBand
    1567             : {
    1568             :     friend class ECWWriteDataset;
    1569             : 
    1570             :     // NOTE: poDS may be altered for NITF/JPEG2000 files!
    1571             :     ECWWriteDataset *poGDS;
    1572             : 
    1573             :     GDALColorInterp eInterp;
    1574             : 
    1575             : #ifdef OPTIMIZED_FOR_GDALWARP
    1576             :     IRasterIORequest *poIORequest;
    1577             : #endif
    1578             : 
    1579             :   public:
    1580             :     ECWWriteRasterBand(ECWWriteDataset *, int);
    1581             :     ~ECWWriteRasterBand() override;
    1582             : 
    1583           6 :     CPLErr SetColorInterpretation(GDALColorInterp eInterpIn) override
    1584             :     {
    1585           6 :         eInterp = eInterpIn;
    1586           6 :         if (strlen(GetDescription()) == 0)
    1587           3 :             SetDescription(ECWGetColorInterpretationName(eInterp, nBand - 1));
    1588           6 :         return CE_None;
    1589             :     }
    1590             : 
    1591           6 :     GDALColorInterp GetColorInterpretation() override
    1592             :     {
    1593           6 :         return eInterp;
    1594             :     }
    1595             : 
    1596             :     CPLErr IReadBlock(int, int, void *) override;
    1597             :     CPLErr IWriteBlock(int, int, void *) override;
    1598             : 
    1599             : #ifdef OPTIMIZED_FOR_GDALWARP
    1600             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
    1601             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
    1602             :                      GDALDataType eBufType, GSpacing nPixelSpace,
    1603             :                      GSpacing nLineSpace,
    1604             :                      GDALRasterIOExtraArg *psExtraArg) override;
    1605             : #endif
    1606             : };
    1607             : 
    1608             : /************************************************************************/
    1609             : /*                          ECWWriteDataset()                           */
    1610             : /************************************************************************/
    1611             : 
    1612          33 : ECWWriteDataset::ECWWriteDataset(const char *pszFilenameIn, int nXSize,
    1613             :                                  int nYSize, int nBandCount, GDALDataType eType,
    1614          33 :                                  CSLConstList papszOptionsIn, int bIsJPEG2000In)
    1615             : 
    1616             : {
    1617          33 :     bCrystalized = FALSE;
    1618          33 :     pabyBILBuffer = nullptr;
    1619          33 :     nLoadedLine = -1;
    1620             : 
    1621          33 :     eAccess = GA_Update;
    1622             : 
    1623          33 :     this->bIsJPEG2000 = bIsJPEG2000In;
    1624          33 :     this->eDataType = eType;
    1625          33 :     this->papszOptions = CSLDuplicate(papszOptionsIn);
    1626          33 :     this->pszFilename = CPLStrdup(pszFilenameIn);
    1627             : 
    1628          33 :     nRasterXSize = nXSize;
    1629          33 :     nRasterYSize = nYSize;
    1630             : 
    1631             :     // create band objects.
    1632         104 :     for (int iBand = 1; iBand <= nBandCount; iBand++)
    1633             :     {
    1634          71 :         SetBand(iBand, new ECWWriteRasterBand(this, iBand));
    1635             :     }
    1636             : 
    1637          33 :     bOutOfOrderWriteOccurred = FALSE;
    1638             : #ifdef OPTIMIZED_FOR_GDALWARP
    1639          33 :     nPrevIRasterIOBand = -1;
    1640             : #endif
    1641          33 : }
    1642             : 
    1643             : /************************************************************************/
    1644             : /*                          ~ECWWriteDataset()                          */
    1645             : /************************************************************************/
    1646             : 
    1647          66 : ECWWriteDataset::~ECWWriteDataset()
    1648             : 
    1649             : {
    1650          33 :     ECWWriteDataset::FlushCache(true);
    1651             : 
    1652          33 :     if (bCrystalized)
    1653             :     {
    1654           2 :         if (bOutOfOrderWriteOccurred)
    1655             :         {
    1656             :             /* Otherwise there's a hang-up in the destruction of the oCompressor
    1657             :              * object */
    1658           0 :             while (nLoadedLine < nRasterYSize - 1)
    1659           0 :                 FlushLine();
    1660             :         }
    1661           2 :         if (nLoadedLine == nRasterYSize - 1)
    1662           2 :             FlushLine();
    1663           2 :         oCompressor.CloseDown();
    1664             :     }
    1665             : 
    1666          33 :     CPLFree(pabyBILBuffer);
    1667          33 :     CSLDestroy(papszOptions);
    1668          33 :     CPLFree(pszFilename);
    1669          66 : }
    1670             : 
    1671             : /************************************************************************/
    1672             : /*                             FlushCache()                             */
    1673             : /************************************************************************/
    1674             : 
    1675          35 : CPLErr ECWWriteDataset::FlushCache(bool bAtClosing)
    1676             : 
    1677             : {
    1678          35 :     return BlockBasedFlushCache(bAtClosing);
    1679             : }
    1680             : 
    1681             : /************************************************************************/
    1682             : /*                           GetSpatialRef()                            */
    1683             : /************************************************************************/
    1684             : 
    1685           0 : const OGRSpatialReference *ECWWriteDataset::GetSpatialRef() const
    1686             : {
    1687           0 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
    1688             : }
    1689             : 
    1690             : /************************************************************************/
    1691             : /*                          GetGeoTransform()                           */
    1692             : /************************************************************************/
    1693             : 
    1694          31 : CPLErr ECWWriteDataset::GetGeoTransform(GDALGeoTransform &gt) const
    1695             : 
    1696             : {
    1697          31 :     gt = m_gt;
    1698          31 :     return CE_None;
    1699             : }
    1700             : 
    1701             : /************************************************************************/
    1702             : /*                          SetGeoTransform()                           */
    1703             : /************************************************************************/
    1704             : 
    1705          32 : CPLErr ECWWriteDataset::SetGeoTransform(const GDALGeoTransform &gt)
    1706             : 
    1707             : {
    1708          32 :     m_gt = gt;
    1709          32 :     return CE_None;
    1710             : }
    1711             : 
    1712             : /************************************************************************/
    1713             : /*                           SetSpatialRef()                            */
    1714             : /************************************************************************/
    1715             : 
    1716          32 : CPLErr ECWWriteDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
    1717             : 
    1718             : {
    1719          32 :     m_oSRS.Clear();
    1720          32 :     if (poSRS)
    1721          32 :         m_oSRS = *poSRS;
    1722             : 
    1723          32 :     return CE_None;
    1724             : }
    1725             : 
    1726             : /************************************************************************/
    1727             : /*                             Crystalize()                             */
    1728             : /************************************************************************/
    1729             : 
    1730           2 : CPLErr ECWWriteDataset::Crystalize()
    1731             : 
    1732             : {
    1733           2 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
    1734             : 
    1735             :     CPLErr eErr;
    1736             : 
    1737           2 :     if (bCrystalized)
    1738           0 :         return CE_None;
    1739             : 
    1740             :     const char **paszBandDescriptions =
    1741           2 :         (const char **)CPLMalloc(nBands * sizeof(char *));
    1742           6 :     for (int i = 0; i < nBands; i++)
    1743             :     {
    1744           4 :         paszBandDescriptions[i] = GetRasterBand(i + 1)->GetDescription();
    1745             :     }
    1746             : 
    1747           2 :     int bRGBColorSpace = ECWIsInputRGBColorSpace(this);
    1748             : 
    1749           4 :     eErr = oCompressor.Initialize(pszFilename, papszOptions, nRasterXSize,
    1750             :                                   nRasterYSize, nBands, paszBandDescriptions,
    1751           2 :                                   bRGBColorSpace, eDataType, &m_oSRS, m_gt, 0,
    1752             :                                   nullptr, bIsJPEG2000, FALSE, nullptr);
    1753             : 
    1754           2 :     if (eErr == CE_None)
    1755           2 :         bCrystalized = TRUE;
    1756             : 
    1757           2 :     nLoadedLine = -1;
    1758           4 :     pabyBILBuffer = (GByte *)CPLMalloc(static_cast<size_t>(nWordSize) * nBands *
    1759           2 :                                        nRasterXSize);
    1760             : 
    1761           2 :     CPLFree(paszBandDescriptions);
    1762             : 
    1763           2 :     return eErr;
    1764             : }
    1765             : 
    1766             : /************************************************************************/
    1767             : /*                             FlushLine()                              */
    1768             : /************************************************************************/
    1769             : 
    1770         202 : CPLErr ECWWriteDataset::FlushLine()
    1771             : 
    1772             : {
    1773         202 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
    1774             :     CPLErr eErr;
    1775             : 
    1776             :     /* -------------------------------------------------------------------- */
    1777             :     /*      Crystallize if not already done.                                */
    1778             :     /* -------------------------------------------------------------------- */
    1779         202 :     if (!bCrystalized)
    1780             :     {
    1781           2 :         eErr = Crystalize();
    1782             : 
    1783           2 :         if (eErr != CE_None)
    1784           0 :             return eErr;
    1785             :     }
    1786             : 
    1787             :     /* -------------------------------------------------------------------- */
    1788             :     /*      Write out the currently loaded line.                            */
    1789             :     /* -------------------------------------------------------------------- */
    1790         202 :     if (nLoadedLine != -1)
    1791             :     {
    1792             : 
    1793         200 :         void **papOutputLine = (void **)CPLMalloc(sizeof(void *) * nBands);
    1794         600 :         for (int i = 0; i < nBands; i++)
    1795         400 :             papOutputLine[i] =
    1796         400 :                 (void *)(pabyBILBuffer +
    1797         400 :                          static_cast<size_t>(i) * nWordSize * nRasterXSize);
    1798             : 
    1799         200 :         eErr = oCompressor.ourWriteLineBIL((UINT16)nBands, papOutputLine);
    1800         200 :         CPLFree(papOutputLine);
    1801         200 :         if (eErr != CE_None)
    1802             :         {
    1803           0 :             return eErr;
    1804             :         }
    1805             :     }
    1806             : 
    1807             :     /* -------------------------------------------------------------------- */
    1808             :     /*      Clear the buffer and increment the "current line" indicator.    */
    1809             :     /* -------------------------------------------------------------------- */
    1810         202 :     memset(pabyBILBuffer, 0,
    1811         202 :            static_cast<size_t>(nWordSize) * nRasterXSize * nBands);
    1812         202 :     nLoadedLine++;
    1813             : 
    1814         202 :     return CE_None;
    1815             : }
    1816             : 
    1817             : #ifdef OPTIMIZED_FOR_GDALWARP
    1818             : /************************************************************************/
    1819             : /*                             IRasterIO()                              */
    1820             : /************************************************************************/
    1821             : 
    1822         200 : CPLErr ECWWriteDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    1823             :                                   int nXSize, int nYSize, void *pData,
    1824             :                                   int nBufXSize, int nBufYSize,
    1825             :                                   GDALDataType eBufType, int nBandCount,
    1826             :                                   BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
    1827             :                                   GSpacing nLineSpace, GSpacing nBandSpace,
    1828             :                                   GDALRasterIOExtraArg *psExtraArg)
    1829             : {
    1830         200 :     ECWWriteRasterBand *po4thBand = nullptr;
    1831         200 :     IRasterIORequest *poIORequest = nullptr;
    1832             : 
    1833         200 :     if (bOutOfOrderWriteOccurred)
    1834           0 :         return CE_Failure;
    1835             : 
    1836         200 :     if (eRWFlag == GF_Write && nBandCount == 3 && nBands == 4)
    1837             :     {
    1838           0 :         po4thBand = cpl::down_cast<ECWWriteRasterBand *>(GetRasterBand(4));
    1839           0 :         poIORequest = po4thBand->poIORequest;
    1840           0 :         if (poIORequest != nullptr)
    1841             :         {
    1842           0 :             if (nXOff != poIORequest->nXOff || nYOff != poIORequest->nYOff ||
    1843           0 :                 nXSize != poIORequest->nXSize ||
    1844           0 :                 nYSize != poIORequest->nYSize ||
    1845           0 :                 nBufXSize != poIORequest->nBufXSize ||
    1846           0 :                 nBufYSize != poIORequest->nBufYSize)
    1847             :             {
    1848           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Out of order write");
    1849           0 :                 bOutOfOrderWriteOccurred = TRUE;
    1850           0 :                 return CE_Failure;
    1851             :             }
    1852             :         }
    1853             :     }
    1854             : 
    1855         200 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1856         200 :     if (eRWFlag == GF_Write && nXOff == 0 && nXSize == nRasterXSize &&
    1857         200 :         nBufXSize == nXSize && nBufYSize == nYSize && eBufType == eDataType &&
    1858         100 :         (nBandCount == nBands ||
    1859           0 :          (nBandCount == 3 && poIORequest != nullptr && nBands == 4)) &&
    1860         100 :         nPixelSpace == nDataTypeSize &&
    1861         100 :         nLineSpace == nPixelSpace * nRasterXSize)
    1862             :     {
    1863         100 :         CPLErr eErr = CE_None;
    1864         100 :         GByte *pabyData = (GByte *)pData;
    1865         200 :         for (int iY = 0; iY < nYSize; iY++)
    1866             :         {
    1867         200 :             for (int iBand = 0; iBand < nBandCount && eErr == CE_None; iBand++)
    1868             :             {
    1869         100 :                 eErr = GetRasterBand(panBandMap[iBand])
    1870         200 :                            ->WriteBlock(0, iY + nYOff,
    1871         100 :                                         pabyData + iY * nLineSpace +
    1872         100 :                                             iBand * nBandSpace);
    1873             :             }
    1874             : 
    1875         100 :             if (poIORequest != nullptr && eErr == CE_None)
    1876             :             {
    1877           0 :                 eErr = po4thBand->WriteBlock(0, iY + nYOff,
    1878           0 :                                              poIORequest->pabyData +
    1879           0 :                                                  iY * nDataTypeSize * nXSize);
    1880             :             }
    1881             :         }
    1882             : 
    1883         100 :         if (poIORequest != nullptr)
    1884             :         {
    1885           0 :             delete poIORequest;
    1886           0 :             po4thBand->poIORequest = nullptr;
    1887             :         }
    1888             : 
    1889         100 :         return eErr;
    1890             :     }
    1891             :     else
    1892         100 :         return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1893             :                                       pData, nBufXSize, nBufYSize, eBufType,
    1894             :                                       nBandCount, panBandMap, nPixelSpace,
    1895         100 :                                       nLineSpace, nBandSpace, psExtraArg);
    1896             : }
    1897             : #endif
    1898             : 
    1899             : /************************************************************************/
    1900             : /* ==================================================================== */
    1901             : /*                          ECWWriteRasterBand                          */
    1902             : /* ==================================================================== */
    1903             : /************************************************************************/
    1904             : 
    1905             : /************************************************************************/
    1906             : /*                         ECWWriteRasterBand()                         */
    1907             : /************************************************************************/
    1908             : 
    1909          71 : ECWWriteRasterBand::ECWWriteRasterBand(ECWWriteDataset *poDSIn, int nBandIn)
    1910             : 
    1911             : {
    1912          71 :     nBand = nBandIn;
    1913          71 :     poDS = poDSIn;
    1914          71 :     poGDS = poDSIn;
    1915          71 :     nBlockXSize = poDSIn->GetRasterXSize();
    1916          71 :     nBlockYSize = 1;
    1917          71 :     eDataType = poDSIn->eDataType;
    1918          71 :     eInterp = GCI_Undefined;
    1919             : #ifdef OPTIMIZED_FOR_GDALWARP
    1920          71 :     poIORequest = nullptr;
    1921             : #endif
    1922          71 : }
    1923             : 
    1924             : /************************************************************************/
    1925             : /*                        ~ECWWriteRasterBand()                         */
    1926             : /************************************************************************/
    1927             : 
    1928         142 : ECWWriteRasterBand::~ECWWriteRasterBand()
    1929             : 
    1930             : {
    1931             : #ifdef OPTIMIZED_FOR_GDALWARP
    1932          71 :     delete poIORequest;
    1933             : #endif
    1934         142 : }
    1935             : 
    1936             : /************************************************************************/
    1937             : /*                             IReadBlock()                             */
    1938             : /************************************************************************/
    1939             : 
    1940           0 : CPLErr ECWWriteRasterBand::IReadBlock(CPL_UNUSED int nBlockX,
    1941             :                                       CPL_UNUSED int nBlockY, void *pBuffer)
    1942             : {
    1943           0 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
    1944             : 
    1945             :     // We zero stuff out here, but we can't really read stuff from
    1946             :     // a write only stream.
    1947             : 
    1948           0 :     memset(pBuffer, 0, static_cast<size_t>(nBlockXSize) * nWordSize);
    1949             : 
    1950           0 :     return CE_None;
    1951             : }
    1952             : 
    1953             : #ifdef OPTIMIZED_FOR_GDALWARP
    1954             : /************************************************************************/
    1955             : /*                             IRasterIO()                              */
    1956             : /************************************************************************/
    1957             : 
    1958         300 : CPLErr ECWWriteRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    1959             :                                      int nXSize, int nYSize, void *pData,
    1960             :                                      int nBufXSize, int nBufYSize,
    1961             :                                      GDALDataType eBufType,
    1962             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
    1963             :                                      GDALRasterIOExtraArg *psExtraArg)
    1964             : {
    1965         300 :     if (eRWFlag == GF_Write && nBand == 4 && poGDS->nBands == 4 &&
    1966           0 :         poGDS->nPrevIRasterIOBand < 0)
    1967             :     {
    1968             :         /* Triggered when gdalwarp outputs an alpha band */
    1969             :         /* It is called before GDALDatasetRasterIO() on the 3 first bands */
    1970           0 :         if (poIORequest != nullptr)
    1971           0 :             return CE_Failure;
    1972           0 :         poIORequest = new IRasterIORequest(this, nXOff, nYOff, nXSize, nYSize,
    1973             :                                            pData, nBufXSize, nBufYSize,
    1974           0 :                                            eBufType, nPixelSpace, nLineSpace);
    1975           0 :         return CE_None;
    1976             :     }
    1977             : 
    1978         300 :     poGDS->nPrevIRasterIOBand = nBand;
    1979         300 :     return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1980             :                                      pData, nBufXSize, nBufYSize, eBufType,
    1981         300 :                                      nPixelSpace, nLineSpace, psExtraArg);
    1982             : }
    1983             : #endif
    1984             : 
    1985             : /************************************************************************/
    1986             : /*                            IWriteBlock()                             */
    1987             : /************************************************************************/
    1988             : 
    1989         400 : CPLErr ECWWriteRasterBand::IWriteBlock(CPL_UNUSED int nBlockX, int nBlockY,
    1990             :                                        void *pBuffer)
    1991             : {
    1992         400 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDataType);
    1993             :     CPLErr eErr;
    1994             : 
    1995         400 :     if (poGDS->bOutOfOrderWriteOccurred)
    1996           0 :         return CE_Failure;
    1997             : 
    1998             :     /* -------------------------------------------------------------------- */
    1999             :     /*      Flush previous line if needed.                                  */
    2000             :     /* -------------------------------------------------------------------- */
    2001         400 :     if (nBlockY == poGDS->nLoadedLine + 1)
    2002             :     {
    2003         200 :         eErr = poGDS->FlushLine();
    2004         200 :         if (eErr != CE_None)
    2005           0 :             return eErr;
    2006             :     }
    2007             : 
    2008             :     /* -------------------------------------------------------------------- */
    2009             :     /*      Blow a gasket if we have been asked to write something out      */
    2010             :     /*      of order.                                                       */
    2011             :     /* -------------------------------------------------------------------- */
    2012         400 :     if (nBlockY != poGDS->nLoadedLine)
    2013             :     {
    2014           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2015             :                  "Apparent attempt to write to ECW non-sequentially.\n"
    2016             :                  "Loaded line is %d, but %d of band %d was written to.",
    2017           0 :                  poGDS->nLoadedLine, nBlockY, nBand);
    2018           0 :         poGDS->bOutOfOrderWriteOccurred = TRUE;
    2019           0 :         return CE_Failure;
    2020             :     }
    2021             : 
    2022             :     /* -------------------------------------------------------------------- */
    2023             :     /*      Copy passed data into current line buffer.                      */
    2024             :     /* -------------------------------------------------------------------- */
    2025         400 :     memcpy(poGDS->pabyBILBuffer + (nBand - 1) * nWordSize * nRasterXSize,
    2026         400 :            pBuffer, nWordSize * nRasterXSize);
    2027             : 
    2028         400 :     return CE_None;
    2029             : }
    2030             : 
    2031             : /************************************************************************/
    2032             : /*                         ECWCreateJPEG2000()                          */
    2033             : /************************************************************************/
    2034             : 
    2035          51 : GDALDataset *ECWCreateJPEG2000(const char *pszFilename, int nXSize, int nYSize,
    2036             :                                int nBands, GDALDataType eType,
    2037             :                                CSLConstList papszOptions)
    2038             : 
    2039             : {
    2040          51 :     if (nBands == 0)
    2041             :     {
    2042          18 :         CPLError(CE_Failure, CPLE_NotSupported, "0 band not supported");
    2043          18 :         return nullptr;
    2044             :     }
    2045          33 :     ECWInitialize();
    2046             : 
    2047             :     return new ECWWriteDataset(pszFilename, nXSize, nYSize, nBands, eType,
    2048          33 :                                papszOptions, TRUE);
    2049             : }
    2050             : 
    2051             : /************************************************************************/
    2052             : /*                            ECWCreateECW()                            */
    2053             : /************************************************************************/
    2054             : 
    2055           0 : GDALDataset *ECWCreateECW(const char *pszFilename, int nXSize, int nYSize,
    2056             :                           int nBands, GDALDataType eType,
    2057             :                           CSLConstList papszOptions)
    2058             : 
    2059             : {
    2060           0 :     if (nBands == 0)
    2061             :     {
    2062           0 :         CPLError(CE_Failure, CPLE_NotSupported, "0 band not supported");
    2063           0 :         return nullptr;
    2064             :     }
    2065           0 :     ECWInitialize();
    2066             : 
    2067             :     return new ECWWriteDataset(pszFilename, nXSize, nYSize, nBands, eType,
    2068           0 :                                papszOptions, FALSE);
    2069             : }
    2070             : 
    2071             : #endif /* def HAVE_COMPRESS */

Generated by: LCOV version 1.14