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 65933 : int NITFDriverIdentify(GDALOpenInfo *poOpenInfo)
28 :
29 : {
30 65933 : const char *pszFilename = poOpenInfo->pszFilename;
31 :
32 : /* -------------------------------------------------------------------- */
33 : /* Is this a dataset selector? If so, it is obviously NITF. */
34 : /* -------------------------------------------------------------------- */
35 65933 : 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 65893 : 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 65747 : if (poOpenInfo->nHeaderBytes < 4)
52 56338 : return FALSE;
53 :
54 9409 : const char *pszHeader =
55 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
56 9409 : if (!STARTS_WITH_CI(pszHeader, "NITF") &&
57 8497 : !STARTS_WITH_CI(pszHeader, "NSIF") &&
58 8449 : !STARTS_WITH_CI(pszHeader, "NITF"))
59 8449 : return FALSE;
60 :
61 : /* Check that it is not in fact a NITF A.TOC file, which is handled by the
62 : * RPFTOC driver */
63 934096 : for (int i = 0; i < static_cast<int>(poOpenInfo->nHeaderBytes) -
64 : static_cast<int>(strlen("A.TOC"));
65 : i++)
66 : {
67 933136 : if (STARTS_WITH_CI(pszHeader + i, "A.TOC"))
68 0 : return FALSE;
69 : }
70 :
71 960 : return TRUE;
72 : }
73 :
74 : /************************************************************************/
75 : /* NITFDriverSetCommonMetadata() */
76 : /************************************************************************/
77 :
78 1750 : void NITFDriverSetCommonMetadata(GDALDriver *poDriver)
79 : {
80 1750 : poDriver->SetDescription(NITF_DRIVER_NAME);
81 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
82 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
83 1750 : "National Imagery Transmission Format");
84 :
85 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/nitf.html");
86 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ntf");
87 1750 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
88 1750 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
89 1750 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
90 1750 : "Byte UInt16 Int16 UInt32 Int32 Float32");
91 :
92 1750 : poDriver->SetMetadataItem(
93 : GDAL_DMD_OPENOPTIONLIST,
94 : "<OpenOptionList>"
95 : " <Option name='VALIDATE' type='boolean' description='Whether "
96 : "validation of metadata should be done' default='NO' />"
97 : " <Option name='FAIL_IF_VALIDATION_ERROR' type='boolean' "
98 : "description='Whether a validation error should cause dataset opening "
99 : "to fail' default='NO' />"
100 1750 : "</OpenOptionList>");
101 :
102 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
103 :
104 1750 : poDriver->pfnIdentify = NITFDriverIdentify;
105 1750 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
106 1750 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
107 1750 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
108 :
109 1750 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
110 1750 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "RasterValues");
111 1750 : }
112 :
113 : /************************************************************************/
114 : /* RPFTOCDriverIdentify() */
115 : /************************************************************************/
116 :
117 64834 : int RPFTOCDriverIdentify(GDALOpenInfo *poOpenInfo)
118 :
119 : {
120 64834 : const char *pszFilename = poOpenInfo->pszFilename;
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Is this a sub-dataset selector? If so, it is obviously RPFTOC. */
124 : /* -------------------------------------------------------------------- */
125 :
126 64834 : if (STARTS_WITH_CI(pszFilename, "NITF_TOC_ENTRY:"))
127 14 : return TRUE;
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* First we check to see if the file has the expected header */
131 : /* bytes. */
132 : /* -------------------------------------------------------------------- */
133 64820 : if (poOpenInfo->nHeaderBytes < 48)
134 56552 : return FALSE;
135 :
136 8268 : if (RPFTOCIsNonNITFFileTOC(poOpenInfo, pszFilename))
137 6 : return TRUE;
138 :
139 8262 : const char *pszHeader =
140 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
141 8262 : if (!STARTS_WITH_CI(pszHeader, "NITF") &&
142 8258 : !STARTS_WITH_CI(pszHeader, "NSIF") &&
143 8257 : !STARTS_WITH_CI(pszHeader, "NITF"))
144 8257 : return FALSE;
145 :
146 : /* If it is a NITF A.TOC file, it must contain A.TOC in its header */
147 4846 : for (int i = 0; i < static_cast<int>(poOpenInfo->nHeaderBytes) -
148 : static_cast<int>(strlen("A.TOC"));
149 : i++)
150 : {
151 4841 : if (STARTS_WITH_CI(pszHeader + i, "A.TOC"))
152 0 : return TRUE;
153 : }
154 :
155 5 : return FALSE;
156 : }
157 :
158 : /************************************************************************/
159 : /* IsNonNITFFileTOC() */
160 : /************************************************************************/
161 :
162 : /* Check whether the file is a TOC file without NITF header */
163 8278 : int RPFTOCIsNonNITFFileTOC(GDALOpenInfo *poOpenInfo, const char *pszFilename)
164 : {
165 8278 : const char pattern[] = {0, 0, '0', ' ', ' ', ' ', ' ', ' ',
166 : ' ', ' ', 'A', '.', 'T', 'O', 'C'};
167 8278 : if (poOpenInfo)
168 : {
169 8271 : if (poOpenInfo->nHeaderBytes < 48)
170 0 : return FALSE;
171 8271 : return memcmp(pattern, poOpenInfo->pabyHeader, 15) == 0;
172 : }
173 : else
174 : {
175 7 : VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
176 7 : if (fp == nullptr)
177 : {
178 0 : return FALSE;
179 : }
180 :
181 : char buffer[48];
182 14 : int ret = (VSIFReadL(buffer, 1, 48, fp) == 48) &&
183 7 : memcmp(pattern, buffer, 15) == 0;
184 7 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
185 7 : return ret;
186 : }
187 : }
188 :
189 : /************************************************************************/
190 : /* RPFTOCDriverSetCommonMetadata() */
191 : /************************************************************************/
192 :
193 1750 : void RPFTOCDriverSetCommonMetadata(GDALDriver *poDriver)
194 : {
195 1750 : poDriver->SetDescription(RPFTOC_DRIVER_NAME);
196 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
197 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
198 1750 : "Raster Product Format TOC format");
199 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rpftoc.html");
200 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "toc");
201 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
202 1750 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
203 1750 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
204 1750 : poDriver->pfnIdentify = RPFTOCDriverIdentify;
205 1750 : }
206 :
207 : /************************************************************************/
208 : /* ECRGTOCDriverIdentify() */
209 : /************************************************************************/
210 :
211 64845 : int ECRGTOCDriverIdentify(GDALOpenInfo *poOpenInfo)
212 :
213 : {
214 64845 : const char *pszFilename = poOpenInfo->pszFilename;
215 :
216 : /* -------------------------------------------------------------------- */
217 : /* Is this a sub-dataset selector? If so, it is obviously ECRGTOC. */
218 : /* -------------------------------------------------------------------- */
219 64845 : if (STARTS_WITH_CI(pszFilename, "ECRG_TOC_ENTRY:"))
220 40 : return TRUE;
221 :
222 : /* -------------------------------------------------------------------- */
223 : /* First we check to see if the file has the expected header */
224 : /* bytes. */
225 : /* -------------------------------------------------------------------- */
226 64805 : const char *pabyHeader =
227 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
228 64805 : if (pabyHeader == nullptr)
229 56130 : return FALSE;
230 :
231 8675 : if (strstr(pabyHeader, "<Table_of_Contents") != nullptr &&
232 14 : strstr(pabyHeader, "<file_header ") != nullptr)
233 14 : return TRUE;
234 :
235 8661 : if (strstr(pabyHeader, "<!DOCTYPE Table_of_Contents [") != nullptr)
236 0 : return TRUE;
237 :
238 8661 : return FALSE;
239 : }
240 :
241 : /************************************************************************/
242 : /* ECRGTOCDriverSetCommonMetadata() */
243 : /************************************************************************/
244 :
245 1750 : void ECRGTOCDriverSetCommonMetadata(GDALDriver *poDriver)
246 : {
247 1750 : poDriver->SetDescription(ECRGTOC_DRIVER_NAME);
248 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
249 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ECRG TOC format");
250 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
251 1750 : "drivers/raster/ecrgtoc.html");
252 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml");
253 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
254 1750 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
255 1750 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
256 1750 : poDriver->pfnIdentify = ECRGTOCDriverIdentify;
257 1750 : }
258 :
259 : /************************************************************************/
260 : /* DeclareDeferredNITFPlugin() */
261 : /************************************************************************/
262 :
263 : #ifdef PLUGIN_FILENAME
264 : void DeclareDeferredNITFPlugin()
265 : {
266 : if (GDALGetDriverByName(NITF_DRIVER_NAME) != nullptr)
267 : {
268 : return;
269 : }
270 :
271 : {
272 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
273 : #ifdef PLUGIN_INSTALLATION_MESSAGE
274 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
275 : PLUGIN_INSTALLATION_MESSAGE);
276 : #endif
277 : NITFDriverSetCommonMetadata(poDriver);
278 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
279 : }
280 :
281 : {
282 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
283 : #ifdef PLUGIN_INSTALLATION_MESSAGE
284 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
285 : PLUGIN_INSTALLATION_MESSAGE);
286 : #endif
287 : RPFTOCDriverSetCommonMetadata(poDriver);
288 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
289 : }
290 :
291 : {
292 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
293 : #ifdef PLUGIN_INSTALLATION_MESSAGE
294 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
295 : PLUGIN_INSTALLATION_MESSAGE);
296 : #endif
297 : ECRGTOCDriverSetCommonMetadata(poDriver);
298 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
299 : }
300 : }
301 : #endif
|