/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 |