LCOV - code coverage report
Current view: top level - frmts/nitf - nitfdrivercore.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 106 109 97.2 %
Date: 2026-02-20 07:20:35 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  NITF Read/Write Translator
       4             :  * Purpose:  NITFDataset and driver related implementations.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12             :  * represented by the Minister of National Defence, 2006.
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************/
      16             : 
      17             : #include "gdal_priv.h"
      18             : #include "gdal_frmts.h"
      19             : #include "gdalplugindriverproxy.h"
      20             : 
      21             : #include "nitfdrivercore.h"
      22             : 
      23             : /************************************************************************/
      24             : /*                         NITFDriverIdentify()                         */
      25             : /************************************************************************/
      26             : 
      27       69318 : int NITFDriverIdentify(GDALOpenInfo *poOpenInfo)
      28             : 
      29             : {
      30       69318 :     const char *pszFilename = poOpenInfo->pszFilename;
      31             : 
      32             :     /* -------------------------------------------------------------------- */
      33             :     /*      Is this a dataset selector? If so, it is obviously NITF.        */
      34             :     /* -------------------------------------------------------------------- */
      35       69318 :     if (STARTS_WITH_CI(pszFilename, "NITF_IM:"))
      36          40 :         return TRUE;
      37             : 
      38             :     /* -------------------------------------------------------------------- */
      39             :     /*      Avoid that on Windows, JPEG_SUBFILE:x,y,z,data/../tmp/foo.ntf   */
      40             :     /*      to be recognized by the NITF driver, because                    */
      41             :     /*      'JPEG_SUBFILE:x,y,z,data' is considered as a (valid) directory  */
      42             :     /*      and thus the whole filename is evaluated as tmp/foo.ntf         */
      43             :     /* -------------------------------------------------------------------- */
      44       69278 :     if (STARTS_WITH_CI(pszFilename, "JPEG_SUBFILE:"))
      45         146 :         return FALSE;
      46             : 
      47             :     /* -------------------------------------------------------------------- */
      48             :     /*      First we check to see if the file has the expected header       */
      49             :     /*      bytes.                                                          */
      50             :     /* -------------------------------------------------------------------- */
      51       69132 :     if (poOpenInfo->nHeaderBytes < 4)
      52       58362 :         return FALSE;
      53             : 
      54       10770 :     const char *pszHeader =
      55             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
      56       10770 :     if (!STARTS_WITH_CI(pszHeader, "NITF") &&
      57        9654 :         !STARTS_WITH_CI(pszHeader, "NSIF") &&
      58        9606 :         !STARTS_WITH_CI(pszHeader, "NITF"))
      59        9606 :         return FALSE;
      60             : 
      61        1164 :     if (!poOpenInfo->IsSingleAllowedDriver("NITF"))
      62             :     {
      63             :         /* Check that it is not in fact a NITF A.TOC file, which is handled by the
      64             :      * RPFTOC driver */
      65     1050370 :         for (int i = 0; i < static_cast<int>(poOpenInfo->nHeaderBytes) -
      66             :                                 static_cast<int>(strlen("A.TOC"));
      67             :              i++)
      68             :         {
      69     1049290 :             if (STARTS_WITH_CI(pszHeader + i, "A.TOC"))
      70           1 :                 return FALSE;
      71             :         }
      72             :     }
      73             : 
      74        1163 :     return TRUE;
      75             : }
      76             : 
      77             : /************************************************************************/
      78             : /*                    NITFDriverSetCommonMetadata()                     */
      79             : /************************************************************************/
      80             : 
      81        1778 : void NITFDriverSetCommonMetadata(GDALDriver *poDriver)
      82             : {
      83        1778 :     poDriver->SetDescription(NITF_DRIVER_NAME);
      84        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
      85        1778 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
      86        1778 :                               "National Imagery Transmission Format");
      87             : 
      88        1778 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/nitf.html");
      89        1778 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ntf");
      90        1778 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
      91        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
      92        1778 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
      93        1778 :                               "Byte UInt16 Int16 UInt32 Int32 Float32");
      94             : 
      95        1778 :     poDriver->SetMetadataItem(
      96             :         GDAL_DMD_OPENOPTIONLIST,
      97             :         "<OpenOptionList>"
      98             :         "  <Option name='VALIDATE' type='boolean' description='Whether "
      99             :         "validation of metadata should be done' default='NO' />"
     100             :         "  <Option name='FAIL_IF_VALIDATION_ERROR' type='boolean' "
     101             :         "description='Whether a validation error should cause dataset opening "
     102             :         "to fail' default='NO' />"
     103        1778 :         "</OpenOptionList>");
     104             : 
     105        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     106             : 
     107        1778 :     poDriver->pfnIdentify = NITFDriverIdentify;
     108        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     109        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
     110        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     111             : 
     112        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     113        1778 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "RasterValues");
     114        1778 : }
     115             : 
     116             : /************************************************************************/
     117             : /*                        RPFTOCDriverIdentify()                        */
     118             : /************************************************************************/
     119             : 
     120       67981 : int RPFTOCDriverIdentify(GDALOpenInfo *poOpenInfo)
     121             : 
     122             : {
     123       67981 :     const char *pszFilename = poOpenInfo->pszFilename;
     124             : 
     125             :     /* -------------------------------------------------------------------- */
     126             :     /*      Is this a sub-dataset selector? If so, it is obviously RPFTOC.  */
     127             :     /* -------------------------------------------------------------------- */
     128             : 
     129       67981 :     if (STARTS_WITH_CI(pszFilename, "NITF_TOC_ENTRY:"))
     130          20 :         return TRUE;
     131             : 
     132             :     /* -------------------------------------------------------------------- */
     133             :     /*      First we check to see if the file has the expected header       */
     134             :     /*      bytes.                                                          */
     135             :     /* -------------------------------------------------------------------- */
     136       67961 :     if (poOpenInfo->nHeaderBytes < 48)
     137       58538 :         return FALSE;
     138             : 
     139        9423 :     if (RPFTOCIsNonNITFFileTOC(poOpenInfo, pszFilename))
     140           6 :         return TRUE;
     141             : 
     142        9417 :     const char *pszHeader =
     143             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     144        9417 :     if (!STARTS_WITH_CI(pszHeader, "NITF") &&
     145        9411 :         !STARTS_WITH_CI(pszHeader, "NSIF") &&
     146        9410 :         !STARTS_WITH_CI(pszHeader, "NITF"))
     147        9410 :         return FALSE;
     148             : 
     149             :     /* If it is a NITF A.TOC file, it must contain A.TOC in its header */
     150        4940 :     for (int i = 0; i < static_cast<int>(poOpenInfo->nHeaderBytes) -
     151             :                             static_cast<int>(strlen("A.TOC"));
     152             :          i++)
     153             :     {
     154        4935 :         if (STARTS_WITH_CI(pszHeader + i, "A.TOC"))
     155           2 :             return TRUE;
     156             :     }
     157             : 
     158           5 :     return FALSE;
     159             : }
     160             : 
     161             : /************************************************************************/
     162             : /*                          IsNonNITFFileTOC()                          */
     163             : /************************************************************************/
     164             : 
     165             : /* Check whether the file is a TOC file without NITF header */
     166        9437 : int RPFTOCIsNonNITFFileTOC(GDALOpenInfo *poOpenInfo, const char *pszFilename)
     167             : {
     168        9437 :     const char pattern[] = {0,   0,   '0', ' ', ' ', ' ', ' ', ' ',
     169             :                             ' ', ' ', 'A', '.', 'T', 'O', 'C'};
     170        9437 :     if (poOpenInfo)
     171             :     {
     172        9427 :         if (poOpenInfo->nHeaderBytes < 48)
     173           0 :             return FALSE;
     174        9427 :         return memcmp(pattern, poOpenInfo->pabyHeader, 15) == 0;
     175             :     }
     176             :     else
     177             :     {
     178          10 :         VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
     179          10 :         if (fp == nullptr)
     180             :         {
     181           0 :             return FALSE;
     182             :         }
     183             : 
     184             :         char buffer[48];
     185          20 :         int ret = (VSIFReadL(buffer, 1, 48, fp) == 48) &&
     186          10 :                   memcmp(pattern, buffer, 15) == 0;
     187          10 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     188          10 :         return ret;
     189             :     }
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                   RPFTOCDriverSetCommonMetadata()                    */
     194             : /************************************************************************/
     195             : 
     196        1778 : void RPFTOCDriverSetCommonMetadata(GDALDriver *poDriver)
     197             : {
     198        1778 :     poDriver->SetDescription(RPFTOC_DRIVER_NAME);
     199        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     200        1778 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     201        1778 :                               "Raster Product Format TOC format");
     202        1778 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rpftoc.html");
     203        1778 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "toc");
     204        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     205        1778 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     206        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     207        1778 :     poDriver->pfnIdentify = RPFTOCDriverIdentify;
     208             : 
     209        1778 :     poDriver->SetMetadataItem(
     210             :         GDAL_DMD_OPENOPTIONLIST,
     211             :         "<OpenOptionList>"
     212             :         "  <Option name='FORCE_RGBA' type='boolean' description='Whether "
     213             :         "dataset should be exposed as RGBA rather than single band with "
     214             :         "color palette' default='NO' />"
     215        1778 :         "</OpenOptionList>");
     216             : 
     217             : #ifdef GDAL_ENABLE_ALGORITHMS
     218        3556 :     poDriver->DeclareAlgorithm({"create"});
     219             : #endif
     220        1778 : }
     221             : 
     222             : /************************************************************************/
     223             : /*                       ECRGTOCDriverIdentify()                        */
     224             : /************************************************************************/
     225             : 
     226       67984 : int ECRGTOCDriverIdentify(GDALOpenInfo *poOpenInfo)
     227             : 
     228             : {
     229       67984 :     const char *pszFilename = poOpenInfo->pszFilename;
     230             : 
     231             :     /* -------------------------------------------------------------------- */
     232             :     /*      Is this a sub-dataset selector? If so, it is obviously ECRGTOC. */
     233             :     /* -------------------------------------------------------------------- */
     234       67984 :     if (STARTS_WITH_CI(pszFilename, "ECRG_TOC_ENTRY:"))
     235          40 :         return TRUE;
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*  First we check to see if the file has the expected header           */
     239             :     /*  bytes.                                                              */
     240             :     /* -------------------------------------------------------------------- */
     241       67944 :     const char *pabyHeader =
     242             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     243       67944 :     if (pabyHeader == nullptr)
     244       58111 :         return FALSE;
     245             : 
     246        9833 :     if (strstr(pabyHeader, "<Table_of_Contents") != nullptr &&
     247          14 :         strstr(pabyHeader, "<file_header ") != nullptr)
     248          14 :         return TRUE;
     249             : 
     250        9819 :     if (strstr(pabyHeader, "<!DOCTYPE Table_of_Contents [") != nullptr)
     251           0 :         return TRUE;
     252             : 
     253        9819 :     return FALSE;
     254             : }
     255             : 
     256             : /************************************************************************/
     257             : /*                   ECRGTOCDriverSetCommonMetadata()                   */
     258             : /************************************************************************/
     259             : 
     260        1778 : void ECRGTOCDriverSetCommonMetadata(GDALDriver *poDriver)
     261             : {
     262        1778 :     poDriver->SetDescription(ECRGTOC_DRIVER_NAME);
     263        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     264        1778 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ECRG TOC format");
     265        1778 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
     266        1778 :                               "drivers/raster/ecrgtoc.html");
     267        1778 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml");
     268        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     269        1778 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     270        1778 :     poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
     271        1778 :     poDriver->pfnIdentify = ECRGTOCDriverIdentify;
     272        1778 : }
     273             : 
     274             : /************************************************************************/
     275             : /*                     DeclareDeferredNITFPlugin()                      */
     276             : /************************************************************************/
     277             : 
     278             : #ifdef PLUGIN_FILENAME
     279             : void DeclareDeferredNITFPlugin()
     280             : {
     281             :     if (GDALGetDriverByName(NITF_DRIVER_NAME) != nullptr)
     282             :     {
     283             :         return;
     284             :     }
     285             : 
     286             :     {
     287             :         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             :         NITFDriverSetCommonMetadata(poDriver);
     293             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     294             :     }
     295             : 
     296             :     {
     297             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     298             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     299             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     300             :                                   PLUGIN_INSTALLATION_MESSAGE);
     301             : #endif
     302             :         RPFTOCDriverSetCommonMetadata(poDriver);
     303             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     304             :     }
     305             : 
     306             :     {
     307             :         auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
     308             : #ifdef PLUGIN_INSTALLATION_MESSAGE
     309             :         poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
     310             :                                   PLUGIN_INSTALLATION_MESSAGE);
     311             : #endif
     312             :         ECRGTOCDriverSetCommonMetadata(poDriver);
     313             :         GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
     314             :     }
     315             : }
     316             : #endif

Generated by: LCOV version 1.14