LCOV - code coverage report
Current view: top level - frmts/ecw - ecwdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 62 63 98.4 %
Date: 2024-05-04 12:52:34 Functions: 5 5 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : // ncsjpcbuffer.h needs the min and max macros.
      30             : #undef NOMINMAX
      31             : 
      32             : #include "ecwdrivercore.h"
      33             : 
      34             : #include "ecwsdk_headers.h"
      35             : 
      36             : constexpr unsigned char jpc_header[] = {0xff, 0x4f, 0xff,
      37             :                                         0x51};  // SOC + RSIZ markers
      38             : constexpr unsigned char jp2_header[] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50,
      39             :                                         0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
      40             : 
      41             : /* Needed for v4.3 and v5.0 */
      42             : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
      43             : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
      44             : #endif
      45             : 
      46             : /************************************************************************/
      47             : /*                           IdentifyECW()                              */
      48             : /*                                                                      */
      49             : /*      Identify method that only supports ECW files.                   */
      50             : /************************************************************************/
      51             : 
      52       51112 : int ECWDatasetIdentifyECW(GDALOpenInfo *poOpenInfo)
      53             : 
      54             : {
      55             :     /* -------------------------------------------------------------------- */
      56             :     /*      This has to either be a file on disk ending in .ecw or a        */
      57             :     /*      ecwp: protocol url.                                             */
      58             :     /* -------------------------------------------------------------------- */
      59       51112 :     if ((!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "ecw") ||
      60         125 :          poOpenInfo->nHeaderBytes == 0) &&
      61      102283 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwp:") &&
      62       51046 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwps:"))
      63       51047 :         return FALSE;
      64             : 
      65          65 :     return TRUE;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                    ECWDriverSetCommonMetadata()                      */
      70             : /************************************************************************/
      71             : 
      72        1230 : void ECWDriverSetCommonMetadata(GDALDriver *poDriver)
      73             : {
      74        1230 :     poDriver->SetDescription(ECW_DRIVER_NAME);
      75        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
      76             : 
      77        2460 :     CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
      78             : 
      79             : #ifdef NCS_ECWSDK_VERSION_STRING
      80             :     osLongName += NCS_ECWSDK_VERSION_STRING;
      81             : #else
      82        1230 :     osLongName += "3.x";
      83             : #endif
      84        1230 :     osLongName += ")";
      85             : 
      86        1230 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
      87        1230 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ecw.html");
      88        1230 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ecw");
      89             : 
      90        1230 :     poDriver->pfnIdentify = ECWDatasetIdentifyECW;
      91        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
      92             : #ifdef HAVE_COMPRESS
      93             :     // The create method does not work with SDK 3.3 ( crash in
      94             :     // CNCSJP2FileView::WriteLineBIL() due to m_pFile being nullptr ).
      95             : #if ECWSDK_VERSION >= 50
      96             :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
      97             : #endif
      98        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
      99             : #if ECWSDK_VERSION >= 50
     100             :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16");
     101             : #else
     102        1230 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
     103             : #endif
     104        1230 :     poDriver->SetMetadataItem(
     105             :         GDAL_DMD_CREATIONOPTIONLIST,
     106             :         "<CreationOptionList>"
     107             :         "   <Option name='TARGET' type='float' description='Compression "
     108             :         "Percentage' />"
     109             :         "   <Option name='PROJ' type='string' description='ECW Projection "
     110             :         "Name'/>"
     111             :         "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
     112             : 
     113             : #if ECWSDK_VERSION < 40
     114             :         "   <Option name='LARGE_OK' type='boolean' description='Enable "
     115             :         "compressing 500+MB files'/>"
     116             : #else
     117             :         "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
     118             :         "Compress Key from ERDAS.'/>"
     119             :         "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
     120             :         "Company Name.'/>"
     121             : #endif
     122             : 
     123             : #if ECWSDK_VERSION >= 50
     124             :         "   <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW "
     125             :         "format version (2 or 3).' default='2'/>"
     126             : #endif
     127             : 
     128        1230 :         "</CreationOptionList>");
     129             : #else
     130             :     // In read-only mode, we support VirtualIO. This is not the case
     131             :     // for ECWCreateCopyECW().
     132             :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     133             : #endif
     134        1230 : }
     135             : 
     136             : /************************************************************************/
     137             : /*                        IdentifyJPEG2000()                            */
     138             : /*                                                                      */
     139             : /*          Identify method that only supports JPEG2000 files.          */
     140             : /************************************************************************/
     141             : 
     142       56720 : int ECWDatasetIdentifyJPEG2000(GDALOpenInfo *poOpenInfo)
     143             : 
     144             : {
     145       56720 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "J2K_SUBFILE:"))
     146           0 :         return TRUE;
     147             : 
     148       56720 :     else if (poOpenInfo->nHeaderBytes >= 16 &&
     149        9752 :              (memcmp(poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header)) ==
     150        9697 :                   0 ||
     151        9697 :               memcmp(poOpenInfo->pabyHeader, jp2_header, sizeof(jp2_header)) ==
     152             :                   0))
     153         147 :         return TRUE;
     154             : 
     155             :     else
     156       56573 :         return FALSE;
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                 JP2ECWDriverSetCommonMetadata()                      */
     161             : /************************************************************************/
     162             : 
     163        1230 : void JP2ECWDriverSetCommonMetadata(GDALDriver *poDriver)
     164             : {
     165        1230 :     poDriver->SetDescription(JP2ECW_DRIVER_NAME);
     166        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     167        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     168             : 
     169        2460 :     CPLString osLongName = "ERDAS JPEG2000 (SDK ";
     170             : 
     171             : #ifdef NCS_ECWSDK_VERSION_STRING
     172             :     osLongName += NCS_ECWSDK_VERSION_STRING;
     173             : #else
     174        1230 :     osLongName += "3.x";
     175             : #endif
     176        1230 :     osLongName += ")";
     177             : 
     178        1230 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
     179        1230 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jp2ecw.html");
     180        1230 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jp2");
     181        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     182             : 
     183        1230 :     poDriver->pfnIdentify = ECWDatasetIdentifyJPEG2000;
     184        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     185             : 
     186        1230 :     poDriver->SetMetadataItem(
     187             :         GDAL_DMD_OPENOPTIONLIST,
     188             :         "<OpenOptionList>"
     189             :         "   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' "
     190             :         "description='Whether a 1-bit alpha channel should be promoted to "
     191             :         "8-bit' default='YES'/>"
     192             :         "   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether "
     193             :         "to load remote vector layers referenced by a link in a GMLJP2 v2 box' "
     194             :         "default='NO'/>"
     195             :         "   <Option name='GEOREF_SOURCES' type='string' description='Comma "
     196             :         "separated list made with values "
     197             :         "INTERNAL/GMLJP2/GEOJP2/WORLDFILE/PAM/NONE that describe the priority "
     198             :         "order for georeferencing' default='PAM,GEOJP2,GMLJP2,WORLDFILE'/>"
     199        1230 :         "</OpenOptionList>");
     200             : 
     201             : #ifdef HAVE_COMPRESS
     202        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     203        1230 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     204        1230 :     poDriver->SetMetadataItem(
     205             :         GDAL_DMD_CREATIONDATATYPES,
     206             :         "Byte UInt16 Int16 UInt32 Int32 "
     207             :         "Float32 "
     208             : #if ECWSDK_VERSION >= 40
     209             :         // Crashes for sure with 3.3. Didn't try other versions
     210             :         "Float64"
     211             : #endif
     212        1230 :     );
     213        1230 :     poDriver->SetMetadataItem(
     214             :         GDAL_DMD_CREATIONOPTIONLIST,
     215             :         "<CreationOptionList>"
     216             :         "   <Option name='TARGET' type='float' description='Compression "
     217             :         "Percentage' />"
     218             :         "   <Option name='PROJ' type='string' description='ECW Projection "
     219             :         "Name'/>"
     220             :         "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
     221             :         "   <Option name='UNITS' type='string-select' description='ECW "
     222             :         "Projection Units'>"
     223             :         "       <Value>METERS</Value>"
     224             :         "       <Value>FEET</Value>"
     225             :         "   </Option>"
     226             : 
     227             : #if ECWSDK_VERSION < 40
     228             :         "   <Option name='LARGE_OK' type='boolean' description='Enable "
     229             :         "compressing 500+MB files'/>"
     230             : #else
     231             :         "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
     232             :         "Compress Key from ERDAS.'/>"
     233             :         "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
     234             :         "Company Name.'/>"
     235             : #endif
     236             : 
     237             :         "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
     238             :         "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
     239             :         "   <Option name='GMLJP2V2_DEF' type='string' description='Definition "
     240             :         "file to describe how a GMLJP2 v2 box should be generated. If set to "
     241             :         "YES, a minimal instance will be created'/>"
     242             :         "   <Option name='PROFILE' type='string-select'>"
     243             :         "       <Value>BASELINE_0</Value>"
     244             :         "       <Value>BASELINE_1</Value>"
     245             :         "       <Value>BASELINE_2</Value>"
     246             :         "       <Value>NPJE</Value>"
     247             :         "       <Value>EPJE</Value>"
     248             :         "   </Option>"
     249             :         "   <Option name='PROGRESSION' type='string-select'>"
     250             :         "       <Value>LRCP</Value>"
     251             :         "       <Value>RLCP</Value>"
     252             :         "       <Value>RPCL</Value>"
     253             :         "   </Option>"
     254             :         "   <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 "
     255             :         "wrapper'/>"
     256             :         "   <Option name='NBITS' type='int' description='Bits (precision) for "
     257             :         "sub-byte files (1-7), sub-uint16 (9-15)'/>"
     258             :         "   <Option name='LEVELS' type='int'/>"
     259             :         "   <Option name='LAYERS' type='int'/>"
     260             :         "   <Option name='PRECINCT_WIDTH' type='int'/>"
     261             :         "   <Option name='PRECINCT_HEIGHT' type='int'/>"
     262             :         "   <Option name='TILE_WIDTH' type='int'/>"
     263             :         "   <Option name='TILE_HEIGHT' type='int'/>"
     264             :         "   <Option name='INCLUDE_SOP' type='boolean'/>"
     265             :         "   <Option name='INCLUDE_EPH' type='boolean'/>"
     266             :         "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
     267             :         "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
     268             :         "   <Option name='WRITE_METADATA' type='boolean' description='Whether "
     269             :         "metadata should be written, in a dedicated JP2 XML box' default='NO'/>"
     270             :         "   <Option name='MAIN_MD_DOMAIN_ONLY' type='boolean' "
     271             :         "description='(Only if WRITE_METADATA=YES) Whether only metadata from "
     272             :         "the main domain should be written' default='NO'/>"
     273        1230 :         "</CreationOptionList>");
     274             : #endif
     275        1230 : }
     276             : 
     277             : /************************************************************************/
     278             : /*                    DeclareDeferredECWPlugin()                        */
     279             : /************************************************************************/
     280             : 
     281             : #ifdef PLUGIN_FILENAME
     282        1520 : void DeclareDeferredECWPlugin()
     283             : {
     284        1520 :     if (GDALGetDriverByName(ECW_DRIVER_NAME) != nullptr)
     285             :     {
     286         301 :         return;
     287             :     }
     288             :     {
     289        1219 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     290             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     291             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     292             :                                   PLUGIN_INSTALLATION_MESSAGE);
     293             : #endif
     294        1219 :         ECWDriverSetCommonMetadata(poDriver);
     295        1219 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     296             :     }
     297             :     {
     298        1219 :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     299             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     300             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     301             :                                   PLUGIN_INSTALLATION_MESSAGE);
     302             : #endif
     303        1219 :         JP2ECWDriverSetCommonMetadata(poDriver);
     304        1219 :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     305             :     }
     306             : }
     307             : #endif

Generated by: LCOV version 1.14