Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/rcm/rcmdrivercore.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  DRDC Ottawa GEOINT
4
 * Purpose:  Radarsat Constellation Mission - XML Products (product.xml) driver
5
 * Author:   Roberto Caron, MDA
6
 *           on behalf of DRDC Ottawa
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2020, DRDC Ottawa
10
 *
11
 * Based on the RS2 Dataset Class
12
 *
13
 * SPDX-License-Identifier: MIT
14
 ****************************************************************************/
15
16
#include "gdal_frmts.h"
17
#include "gdalplugindriverproxy.h"
18
19
#include "rcmdrivercore.h"
20
21
int RCMDatasetIdentify(GDALOpenInfo *poOpenInfo)
22
297k
{
23
    /* Check for the case where we're trying to read the calibrated data: */
24
297k
    if (STARTS_WITH_CI(poOpenInfo->pszFilename, szLayerCalibration) &&
25
0
        poOpenInfo->pszFilename[strlen(szLayerCalibration)] == chLayerSeparator)
26
0
    {
27
0
        return TRUE;
28
0
    }
29
30
297k
    if (poOpenInfo->bIsDirectory)
31
3.38k
    {
32
3.38k
        const auto IsRCM = [](const std::string &osMDFilename)
33
3.38k
        {
34
0
            CPLXMLNode *psProduct = CPLParseXMLFile(osMDFilename.c_str());
35
0
            if (psProduct == nullptr)
36
0
                return FALSE;
37
38
0
            CPLXMLNode *psProductAttributes =
39
0
                CPLGetXMLNode(psProduct, "=product");
40
0
            if (psProductAttributes == nullptr)
41
0
            {
42
0
                CPLDestroyXMLNode(psProduct);
43
0
                return FALSE;
44
0
            }
45
46
            /* Check the namespace only, should be rcm */
47
0
            const char *szNamespace =
48
0
                CPLGetXMLValue(psProductAttributes, "xmlns", "");
49
50
0
            if (strstr(szNamespace, "rcm") == nullptr)
51
0
            {
52
                /* Invalid namespace */
53
0
                CPLDestroyXMLNode(psProduct);
54
0
                return FALSE;
55
0
            }
56
57
0
            CPLDestroyXMLNode(psProduct);
58
0
            return TRUE;
59
0
        };
60
61
        /* Check for directory access when there is a product.xml file in the
62
        directory. */
63
3.38k
        const std::string osMDFilename = CPLFormCIFilenameSafe(
64
3.38k
            poOpenInfo->pszFilename, "product.xml", nullptr);
65
66
3.38k
        VSIStatBufL sStat;
67
3.38k
        if (VSIStatL(osMDFilename.c_str(), &sStat) == 0)
68
0
        {
69
0
            return IsRCM(osMDFilename);
70
0
        }
71
72
        /* If not, check for directory extra 'metadata' access when there is a
73
        product.xml file in the directory. */
74
75
3.38k
        const std::string osMDFilenameMetadata = CPLFormCIFilenameSafe(
76
3.38k
            poOpenInfo->pszFilename, GetMetadataProduct(), nullptr);
77
78
3.38k
        VSIStatBufL sStatMetadata;
79
3.38k
        if (VSIStatL(osMDFilenameMetadata.c_str(), &sStatMetadata) == 0)
80
0
        {
81
0
            return IsRCM(osMDFilenameMetadata);
82
0
        }
83
84
3.38k
        return FALSE;
85
3.38k
    }
86
87
    /* otherwise, do our normal stuff */
88
294k
    if (strlen(poOpenInfo->pszFilename) < 11 ||
89
280k
        !EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 11,
90
294k
               "product.xml"))
91
294k
        return FALSE;
92
93
339
    if (poOpenInfo->nHeaderBytes < 100)
94
314
        return FALSE;
95
96
    /* The RCM schema location is rcm_prod_product.xsd */
97
25
    const char *pszHeader =
98
25
        reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
99
25
    return strstr(pszHeader, "/rcm") && strstr(pszHeader, "<product");
100
339
}
101
102
/************************************************************************/
103
/*                     RCMDriverSetCommonMetadata()                     */
104
/************************************************************************/
105
106
void RCMDriverSetCommonMetadata(GDALDriver *poDriver)
107
22
{
108
22
    poDriver->SetDescription(RCM_DRIVER_NAME);
109
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
110
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
111
22
                              "Radarsat Constellation Mission XML Product");
112
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rcm.html");
113
22
    poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
114
22
    poDriver->pfnIdentify = RCMDatasetIdentify;
115
22
    poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
116
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
117
22
}
118
119
/************************************************************************/
120
/*                      DeclareDeferredRCMPlugin()                      */
121
/************************************************************************/
122
123
#ifdef PLUGIN_FILENAME
124
void DeclareDeferredRCMPlugin()
125
{
126
    if (GDALGetDriverByName(RCM_DRIVER_NAME) != nullptr)
127
    {
128
        return;
129
    }
130
131
    auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
132
#ifdef PLUGIN_INSTALLATION_MESSAGE
133
    poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
134
                              PLUGIN_INSTALLATION_MESSAGE);
135
#endif
136
    RCMDriverSetCommonMetadata(poDriver);
137
    GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
138
}
139
#endif