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