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
|