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

Generated by: LCOV version 1.14