LCOV - code coverage report
Current view: top level - frmts/ecw - ecwdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 65 66 98.5 %
Date: 2025-10-21 15:59:38 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  ECW driver
       5             :  * Author:   Even Rouault, <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault, <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : // ncsjpcbuffer.h needs the min and max macros.
      14             : #undef NOMINMAX
      15             : 
      16             : #include "gdal_frmts.h"
      17             : 
      18             : #ifdef PLUGIN_FILENAME
      19             : #include "gdalplugindriverproxy.h"
      20             : #endif
      21             : 
      22             : #include "ecwdrivercore.h"
      23             : 
      24             : #include "ecwsdk_headers.h"
      25             : 
      26             : constexpr unsigned char jpc_header[] = {0xff, 0x4f, 0xff,
      27             :                                         0x51};  // SOC + RSIZ markers
      28             : constexpr unsigned char jp2_header[] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50,
      29             :                                         0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
      30             : 
      31             : /* Needed for v4.3 and v5.0 */
      32             : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
      33             : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
      34             : #endif
      35             : 
      36             : /************************************************************************/
      37             : /*                           IdentifyECW()                              */
      38             : /*                                                                      */
      39             : /*      Identify method that only supports ECW files.                   */
      40             : /************************************************************************/
      41             : 
      42       61108 : int ECWDatasetIdentifyECW(GDALOpenInfo *poOpenInfo)
      43             : 
      44             : {
      45             :     /* -------------------------------------------------------------------- */
      46             :     /*      This has to either be a file on disk ending in .ecw or a        */
      47             :     /*      ecwp: protocol url.                                             */
      48             :     /* -------------------------------------------------------------------- */
      49       61108 :     if ((!poOpenInfo->IsExtensionEqualToCI("ecw") ||
      50         131 :          poOpenInfo->nHeaderBytes == 0) &&
      51      122280 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwp:") &&
      52       61041 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwps:"))
      53       61039 :         return FALSE;
      54             : 
      55          69 :     return TRUE;
      56             : }
      57             : 
      58             : /************************************************************************/
      59             : /*                    ECWDriverSetCommonMetadata()                      */
      60             : /************************************************************************/
      61             : 
      62        1769 : void ECWDriverSetCommonMetadata(GDALDriver *poDriver)
      63             : {
      64        1769 :     poDriver->SetDescription(ECW_DRIVER_NAME);
      65        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
      66             : 
      67        3538 :     CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
      68             : 
      69             : #ifdef NCS_ECWSDK_VERSION_STRING
      70             :     osLongName += NCS_ECWSDK_VERSION_STRING;
      71             : #else
      72        1769 :     osLongName += "3.x";
      73             : #endif
      74        1769 :     osLongName += ")";
      75             : 
      76        1769 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
      77        1769 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ecw.html");
      78        1769 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ecw");
      79             : 
      80        1769 :     poDriver->pfnIdentify = ECWDatasetIdentifyECW;
      81        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
      82             : #ifdef HAVE_COMPRESS
      83             :     // The create method does not work with SDK 3.3 ( crash in
      84             :     // CNCSJP2FileView::WriteLineBIL() due to m_pFile being nullptr ).
      85             : #if ECWSDK_VERSION >= 50
      86             :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
      87             : #endif
      88        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
      89             : #if ECWSDK_VERSION >= 50
      90             :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16");
      91             : #else
      92        1769 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
      93             : #endif
      94        1769 :     poDriver->SetMetadataItem(
      95             :         GDAL_DMD_CREATIONOPTIONLIST,
      96             :         "<CreationOptionList>"
      97             :         "   <Option name='TARGET' type='float' description='Compression "
      98             :         "Percentage' />"
      99             :         "   <Option name='PROJ' type='string' description='ECW Projection "
     100             :         "Name'/>"
     101             :         "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
     102             : 
     103             : #if ECWSDK_VERSION < 40
     104             :         "   <Option name='LARGE_OK' type='boolean' description='Enable "
     105             :         "compressing 500+MB files'/>"
     106             : #else
     107             :         "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
     108             :         "Compress Key from ERDAS.'/>"
     109             :         "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
     110             :         "Company Name.'/>"
     111             : #endif
     112             : 
     113             : #if ECWSDK_VERSION >= 50
     114             :         "   <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW "
     115             :         "format version (2 or 3).' default='2'/>"
     116             : #endif
     117             : 
     118        1769 :         "</CreationOptionList>");
     119             : #else
     120             :     // In read-only mode, we support VirtualIO. This is not the case
     121             :     // for ECWCreateCopyECW().
     122             :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     123             : #endif
     124             : 
     125        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     126        1769 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
     127             :                               "GeoTransform SRS "
     128        1769 :                               "DatasetMetadata BandMetadata");
     129        1769 : }
     130             : 
     131             : /************************************************************************/
     132             : /*                        IdentifyJPEG2000()                            */
     133             : /*                                                                      */
     134             : /*          Identify method that only supports JPEG2000 files.          */
     135             : /************************************************************************/
     136             : 
     137       68145 : int ECWDatasetIdentifyJPEG2000(GDALOpenInfo *poOpenInfo)
     138             : 
     139             : {
     140       68145 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "J2K_SUBFILE:"))
     141           0 :         return TRUE;
     142             : 
     143       68145 :     else if (poOpenInfo->nHeaderBytes >= 16 &&
     144       11200 :              (memcmp(poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header)) ==
     145       11145 :                   0 ||
     146       11145 :               memcmp(poOpenInfo->pabyHeader, jp2_header, sizeof(jp2_header)) ==
     147             :                   0))
     148         149 :         return TRUE;
     149             : 
     150             :     else
     151       67996 :         return FALSE;
     152             : }
     153             : 
     154             : /************************************************************************/
     155             : /*                 JP2ECWDriverSetCommonMetadata()                      */
     156             : /************************************************************************/
     157             : 
     158        1769 : void JP2ECWDriverSetCommonMetadata(GDALDriver *poDriver)
     159             : {
     160        1769 :     poDriver->SetDescription(JP2ECW_DRIVER_NAME);
     161        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     162        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     163             : 
     164        3538 :     CPLString osLongName = "ERDAS JPEG2000 (SDK ";
     165             : 
     166             : #ifdef NCS_ECWSDK_VERSION_STRING
     167             :     osLongName += NCS_ECWSDK_VERSION_STRING;
     168             : #else
     169        1769 :     osLongName += "3.x";
     170             : #endif
     171        1769 :     osLongName += ")";
     172             : 
     173        1769 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
     174        1769 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jp2ecw.html");
     175        1769 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jp2");
     176        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     177             : 
     178        1769 :     poDriver->pfnIdentify = ECWDatasetIdentifyJPEG2000;
     179        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     180             : 
     181        1769 :     poDriver->SetMetadataItem(
     182             :         GDAL_DMD_OPENOPTIONLIST,
     183             :         "<OpenOptionList>"
     184             :         "   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' "
     185             :         "description='Whether a 1-bit alpha channel should be promoted to "
     186             :         "8-bit' default='YES'/>"
     187             :         "   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether "
     188             :         "to load remote vector layers referenced by a link in a GMLJP2 v2 box' "
     189             :         "default='NO'/>"
     190             :         "   <Option name='GEOREF_SOURCES' type='string' description='Comma "
     191             :         "separated list made with values "
     192             :         "INTERNAL/GMLJP2/GEOJP2/WORLDFILE/PAM/NONE that describe the priority "
     193             :         "order for georeferencing' default='PAM,GEOJP2,GMLJP2,WORLDFILE'/>"
     194        1769 :         "</OpenOptionList>");
     195             : 
     196             : #ifdef HAVE_COMPRESS
     197        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     198        1769 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     199        1769 :     poDriver->SetMetadataItem(
     200             :         GDAL_DMD_CREATIONDATATYPES,
     201             :         "Byte UInt16 Int16 UInt32 Int32 "
     202             :         "Float32 "
     203             : #if ECWSDK_VERSION >= 40
     204             :         // Crashes for sure with 3.3. Didn't try other versions
     205             :         "Float64"
     206             : #endif
     207        1769 :     );
     208        1769 :     poDriver->SetMetadataItem(
     209             :         GDAL_DMD_CREATIONOPTIONLIST,
     210             :         "<CreationOptionList>"
     211             :         "   <Option name='TARGET' type='float' description='Compression "
     212             :         "Percentage' />"
     213             :         "   <Option name='PROJ' type='string' description='ECW Projection "
     214             :         "Name'/>"
     215             :         "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
     216             :         "   <Option name='UNITS' type='string-select' description='ECW "
     217             :         "Projection Units'>"
     218             :         "       <Value>METERS</Value>"
     219             :         "       <Value>FEET</Value>"
     220             :         "   </Option>"
     221             : 
     222             : #if ECWSDK_VERSION < 40
     223             :         "   <Option name='LARGE_OK' type='boolean' description='Enable "
     224             :         "compressing 500+MB files'/>"
     225             : #else
     226             :         "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
     227             :         "Compress Key from ERDAS.'/>"
     228             :         "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
     229             :         "Company Name.'/>"
     230             : #endif
     231             : 
     232             :         "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
     233             :         "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
     234             :         "   <Option name='GMLJP2V2_DEF' type='string' description='Definition "
     235             :         "file to describe how a GMLJP2 v2 box should be generated. If set to "
     236             :         "YES, a minimal instance will be created'/>"
     237             :         "   <Option name='PROFILE' type='string-select'>"
     238             :         "       <Value>BASELINE_0</Value>"
     239             :         "       <Value>BASELINE_1</Value>"
     240             :         "       <Value>BASELINE_2</Value>"
     241             :         "       <Value>NPJE</Value>"
     242             :         "       <Value>EPJE</Value>"
     243             :         "   </Option>"
     244             :         "   <Option name='PROGRESSION' type='string-select'>"
     245             :         "       <Value>LRCP</Value>"
     246             :         "       <Value>RLCP</Value>"
     247             :         "       <Value>RPCL</Value>"
     248             :         "   </Option>"
     249             :         "   <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 "
     250             :         "wrapper'/>"
     251             :         "   <Option name='NBITS' type='int' description='Bits (precision) for "
     252             :         "sub-byte files (1-7), sub-uint16 (9-15)'/>"
     253             :         "   <Option name='LEVELS' type='int'/>"
     254             :         "   <Option name='LAYERS' type='int'/>"
     255             :         "   <Option name='PRECINCT_WIDTH' type='int'/>"
     256             :         "   <Option name='PRECINCT_HEIGHT' type='int'/>"
     257             :         "   <Option name='TILE_WIDTH' type='int'/>"
     258             :         "   <Option name='TILE_HEIGHT' type='int'/>"
     259             :         "   <Option name='INCLUDE_SOP' type='boolean'/>"
     260             :         "   <Option name='INCLUDE_EPH' type='boolean'/>"
     261             :         "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
     262             :         "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
     263             :         "   <Option name='WRITE_METADATA' type='boolean' description='Whether "
     264             :         "metadata should be written, in a dedicated JP2 XML box' default='NO'/>"
     265             :         "   <Option name='MAIN_MD_DOMAIN_ONLY' type='boolean' "
     266             :         "description='(Only if WRITE_METADATA=YES) Whether only metadata from "
     267             :         "the main domain should be written' default='NO'/>"
     268        1769 :         "</CreationOptionList>");
     269             : #endif
     270        1769 : }
     271             : 
     272             : /************************************************************************/
     273             : /*                    DeclareDeferredECWPlugin()                        */
     274             : /************************************************************************/
     275             : 
     276             : #ifdef PLUGIN_FILENAME
     277        2038 : void DeclareDeferredECWPlugin()
     278             : {
     279        2038 :     if (GDALGetDriverByName(ECW_DRIVER_NAME) != nullptr)
     280             :     {
     281         283 :         return;
     282             :     }
     283             :     {
     284        1755 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     285             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     286             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     287             :                                   PLUGIN_INSTALLATION_MESSAGE);
     288             : #endif
     289        1755 :         ECWDriverSetCommonMetadata(poDriver);
     290        1755 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     291             :     }
     292             :     {
     293        1755 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     294             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     295             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     296             :                                   PLUGIN_INSTALLATION_MESSAGE);
     297             : #endif
     298        1755 :         JP2ECWDriverSetCommonMetadata(poDriver);
     299        1755 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     300             :     }
     301             : }
     302             : #endif

Generated by: LCOV version 1.14