LCOV - code coverage report
Current view: top level - frmts/ecw - ecwcreatecopy.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 530 686 77.3 %
Date: 2024-05-04 12:52:34 Functions: 32 39 82.1 %

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

Generated by: LCOV version 1.14