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