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