1 /******************************************************************************
2 *
3 * Project: GDAL Core
4 * Purpose: Read metadata from Spot imagery.
5 * Author: Alexander Lisovenko
6 * Author: Dmitry Baryshnikov, polimax@mail.ru
7 *
8 ******************************************************************************
9 * Copyright (c) 2014-2015 NextGIS <info@nextgis.ru>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_port.h"
31 #include "reader_spot.h"
32
33 #include <ctime>
34
35 #include "cpl_conv.h"
36 #include "cpl_error.h"
37 #include "cpl_minixml.h"
38 #include "cpl_string.h"
39 #include "gdal_mdreader.h"
40
41 CPL_CVSID("$Id: reader_spot.cpp ec7b85e6bb8f9737693a31f0bf7166e31e10992e 2018-04-16 00:08:36 +0200 Even Rouault $")
42
43 /**
44 * GDALMDReaderSpot()
45 */
GDALMDReaderSpot(const char * pszPath,char ** papszSiblingFiles)46 GDALMDReaderSpot::GDALMDReaderSpot(const char *pszPath,
47 char **papszSiblingFiles) : GDALMDReaderPleiades(pszPath, papszSiblingFiles)
48 {
49 const char* pszDirName = CPLGetDirname(pszPath);
50
51 if(m_osIMDSourceFilename.empty())
52 {
53 CPLString osIMDSourceFilename = CPLFormFilename( pszDirName, "METADATA.DIM", nullptr );
54
55 if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
56 {
57 m_osIMDSourceFilename = osIMDSourceFilename;
58 }
59 else
60 {
61 osIMDSourceFilename = CPLFormFilename( pszDirName, "metadata.dim", nullptr );
62 if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
63 {
64 m_osIMDSourceFilename = osIMDSourceFilename;
65 }
66 }
67 }
68
69 // if the file name ended on METADATA.DIM
70 // Linux specific
71 // example: R2_CAT_091028105025131_1\METADATA.DIM
72 if(m_osIMDSourceFilename.empty())
73 {
74 if(EQUAL(CPLGetFilename(pszPath), "IMAGERY.TIF"))
75 {
76 CPLString osIMDSourceFilename = CPLSPrintf( "%s\\METADATA.DIM",
77 CPLGetPath(pszPath));
78
79 if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
80 {
81 m_osIMDSourceFilename = osIMDSourceFilename;
82 }
83 else
84 {
85 osIMDSourceFilename = CPLSPrintf( "%s\\metadata.dim",
86 CPLGetPath(pszPath));
87 if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
88 {
89 m_osIMDSourceFilename = osIMDSourceFilename;
90 }
91 }
92 }
93 }
94
95 if(!m_osIMDSourceFilename.empty() )
96 CPLDebug( "MDReaderSpot", "IMD Filename: %s",
97 m_osIMDSourceFilename.c_str() );
98 }
99
100 /**
101 * ~GDALMDReaderSpot()
102 */
~GDALMDReaderSpot()103 GDALMDReaderSpot::~GDALMDReaderSpot()
104 {
105 }
106
107 /**
108 * LoadMetadata()
109 */
LoadMetadata()110 void GDALMDReaderSpot::LoadMetadata()
111 {
112 if(m_bIsMetadataLoad)
113 return;
114
115 if (!m_osIMDSourceFilename.empty())
116 {
117 CPLXMLNode* psNode = CPLParseXMLFile(m_osIMDSourceFilename);
118
119 if(psNode != nullptr)
120 {
121 CPLXMLNode* psisdNode = CPLSearchXMLNode(psNode, "=Dimap_Document");
122
123 if(psisdNode != nullptr)
124 {
125 m_papszIMDMD = ReadXMLToList(psisdNode->psChild, m_papszIMDMD);
126 }
127 CPLDestroyXMLNode(psNode);
128 }
129 }
130
131 m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "DIMAP");
132
133 m_bIsMetadataLoad = true;
134
135 if(nullptr == m_papszIMDMD)
136 {
137 return;
138 }
139
140 //extract imagery metadata
141 int nCounter = -1;
142 const char* pszSatId1 = CSLFetchNameValue(m_papszIMDMD,
143 "Dataset_Sources.Source_Information.Scene_Source.MISSION");
144 if(nullptr == pszSatId1)
145 {
146 nCounter = 1;
147 for(int i = 0; i < 5; i++)
148 {
149 pszSatId1 = CSLFetchNameValue(m_papszIMDMD,
150 CPLSPrintf("Dataset_Sources.Source_Information_%d.Scene_Source.MISSION",
151 nCounter));
152 if(nullptr != pszSatId1)
153 break;
154 nCounter++;
155 }
156 }
157
158 const char* pszSatId2;
159 if(nCounter == -1)
160 pszSatId2 = CSLFetchNameValue(m_papszIMDMD,
161 "Dataset_Sources.Source_Information.Scene_Source.MISSION_INDEX");
162 else
163 pszSatId2 = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
164 "Dataset_Sources.Source_Information_%d.Scene_Source.MISSION_INDEX",
165 nCounter));
166
167 if(nullptr != pszSatId1 && nullptr != pszSatId2)
168 {
169 m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
170 MD_NAME_SATELLITE, CPLSPrintf( "%s %s",
171 CPLStripQuotes(pszSatId1).c_str(),
172 CPLStripQuotes(pszSatId2).c_str()));
173 }
174 else if(nullptr != pszSatId1 && nullptr == pszSatId2)
175 {
176 m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
177 MD_NAME_SATELLITE, CPLStripQuotes(pszSatId1));
178 }
179 else if(nullptr == pszSatId1 && nullptr != pszSatId2)
180 {
181 m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
182 MD_NAME_SATELLITE, CPLStripQuotes(pszSatId2));
183 }
184
185 const char* pszDate;
186 if(nCounter == -1)
187 pszDate = CSLFetchNameValue(m_papszIMDMD,
188 "Dataset_Sources.Source_Information.Scene_Source.IMAGING_DATE");
189 else
190 pszDate = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
191 "Dataset_Sources.Source_Information_%d.Scene_Source.IMAGING_DATE",
192 nCounter));
193
194 if(nullptr != pszDate)
195 {
196 const char* pszTime;
197 if(nCounter == -1)
198 pszTime = CSLFetchNameValue(m_papszIMDMD,
199 "Dataset_Sources.Source_Information.Scene_Source.IMAGING_TIME");
200 else
201 pszTime = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
202 "Dataset_Sources.Source_Information_%d.Scene_Source.IMAGING_TIME",
203 nCounter));
204
205 if(nullptr == pszTime)
206 pszTime = "00:00:00.0Z";
207
208 char buffer[80];
209 time_t timeMid = GetAcquisitionTimeFromString(CPLSPrintf( "%sT%s",
210 pszDate, pszTime));
211 strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
212 m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
213 MD_NAME_ACQDATETIME, buffer);
214 }
215
216 m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
217 MD_CLOUDCOVER_NA);
218 }
219
220 /**
221 * ReadXMLToList()
222 */
ReadXMLToList(CPLXMLNode * psNode,char ** papszList,const char * pszName)223 char** GDALMDReaderSpot::ReadXMLToList(CPLXMLNode* psNode, char** papszList,
224 const char* pszName)
225 {
226 if(nullptr == psNode)
227 return papszList;
228
229 if (psNode->eType == CXT_Text)
230 {
231 if(!EQUAL(pszName, ""))
232 return AddXMLNameValueToList(papszList, pszName, psNode->pszValue);
233 }
234
235 if (psNode->eType == CXT_Element && !EQUAL(psNode->pszValue, "Data_Strip"))
236 {
237 int nAddIndex = 0;
238 bool bReset = false;
239 for(CPLXMLNode* psChildNode = psNode->psChild; nullptr != psChildNode;
240 psChildNode = psChildNode->psNext)
241 {
242 if (psChildNode->eType == CXT_Element)
243 {
244 // check name duplicates
245 if(nullptr != psChildNode->psNext)
246 {
247 if(bReset)
248 {
249 bReset = false;
250 nAddIndex = 0;
251 }
252
253 if(EQUAL(psChildNode->pszValue, psChildNode->psNext->pszValue))
254 {
255 nAddIndex++;
256 }
257 else
258 { // the name changed
259
260 if(nAddIndex > 0)
261 {
262 bReset = true;
263 nAddIndex++;
264 }
265 }
266 }
267 else
268 {
269 if(nAddIndex > 0)
270 {
271 nAddIndex++;
272 }
273 }
274
275 char szName[512];
276 if(nAddIndex > 0)
277 {
278 CPLsnprintf( szName, 511, "%s_%d", psChildNode->pszValue,
279 nAddIndex);
280 }
281 else
282 {
283 CPLStrlcpy(szName, psChildNode->pszValue, 511);
284 }
285
286 char szNameNew[512];
287 if(CPLStrnlen( pszName, 511 ) > 0) //if no prefix just set name to node name
288 {
289 CPLsnprintf( szNameNew, 511, "%s.%s", pszName, szName );
290 }
291 else
292 {
293 CPLsnprintf( szNameNew, 511, "%s.%s", psNode->pszValue, szName );
294 }
295
296 papszList = ReadXMLToList(psChildNode, papszList, szNameNew);
297 }
298 else
299 {
300 // Text nodes should always have name
301 if(EQUAL(pszName, ""))
302 {
303 papszList = ReadXMLToList(psChildNode, papszList, psNode->pszValue);
304 }
305 else
306 {
307 papszList = ReadXMLToList(psChildNode, papszList, pszName);
308 }
309 }
310 }
311 }
312
313 // proceed next only on top level
314
315 if(nullptr != psNode->psNext && EQUAL(pszName, ""))
316 {
317 papszList = ReadXMLToList(psNode->psNext, papszList, pszName);
318 }
319
320 return papszList;
321 }
322