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