Line data Source code
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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "reader_spot.h"
16 :
17 : #include <ctime>
18 :
19 : #include "cpl_conv.h"
20 : #include "cpl_error.h"
21 : #include "cpl_minixml.h"
22 : #include "cpl_string.h"
23 : #include "cpl_time.h"
24 :
25 : #include "gdal_mdreader.h"
26 :
27 : /**
28 : * GDALMDReaderSpot()
29 : */
30 5085 : GDALMDReaderSpot::GDALMDReaderSpot(const char *pszPath,
31 5085 : char **papszSiblingFiles)
32 5085 : : GDALMDReaderPleiades(pszPath, papszSiblingFiles)
33 : {
34 5085 : const char *pszDirName = CPLGetDirname(pszPath);
35 :
36 5085 : if (m_osIMDSourceFilename.empty())
37 : {
38 : std::string osIMDSourceFilename =
39 10170 : CPLFormFilename(pszDirName, "METADATA.DIM", nullptr);
40 :
41 5085 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
42 : {
43 1 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
44 : }
45 : else
46 : {
47 : osIMDSourceFilename =
48 5084 : CPLFormFilename(pszDirName, "metadata.dim", nullptr);
49 5084 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
50 : {
51 0 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
52 : }
53 : }
54 : }
55 :
56 : // if the file name ended on METADATA.DIM
57 : // Linux specific
58 : // example: R2_CAT_091028105025131_1\METADATA.DIM
59 5085 : if (m_osIMDSourceFilename.empty())
60 : {
61 5084 : if (EQUAL(CPLGetFilename(pszPath), "IMAGERY.TIF"))
62 : {
63 : std::string osIMDSourceFilename =
64 0 : CPLSPrintf("%s\\METADATA.DIM", CPLGetPath(pszPath));
65 :
66 0 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
67 : {
68 0 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
69 : }
70 : else
71 : {
72 : osIMDSourceFilename =
73 0 : CPLSPrintf("%s\\metadata.dim", CPLGetPath(pszPath));
74 0 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
75 : {
76 0 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
77 : }
78 : }
79 : }
80 : }
81 :
82 5085 : if (!m_osIMDSourceFilename.empty())
83 1 : CPLDebug("MDReaderSpot", "IMD Filename: %s",
84 : m_osIMDSourceFilename.c_str());
85 5085 : }
86 :
87 : /**
88 : * ~GDALMDReaderSpot()
89 : */
90 10170 : GDALMDReaderSpot::~GDALMDReaderSpot()
91 : {
92 10170 : }
93 :
94 : /**
95 : * LoadMetadata()
96 : */
97 2 : void GDALMDReaderSpot::LoadMetadata()
98 : {
99 2 : if (m_bIsMetadataLoad)
100 1 : return;
101 :
102 1 : if (!m_osIMDSourceFilename.empty())
103 : {
104 1 : CPLXMLNode *psNode = CPLParseXMLFile(m_osIMDSourceFilename);
105 :
106 1 : if (psNode != nullptr)
107 : {
108 1 : CPLXMLNode *psisdNode = CPLSearchXMLNode(psNode, "=Dimap_Document");
109 :
110 1 : if (psisdNode != nullptr)
111 : {
112 1 : m_papszIMDMD = ReadXMLToList(psisdNode->psChild, m_papszIMDMD);
113 : }
114 1 : CPLDestroyXMLNode(psNode);
115 : }
116 : }
117 :
118 1 : m_papszDEFAULTMD =
119 1 : CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "DIMAP");
120 :
121 1 : m_bIsMetadataLoad = true;
122 :
123 1 : if (nullptr == m_papszIMDMD)
124 : {
125 0 : return;
126 : }
127 :
128 : // extract imagery metadata
129 1 : int nCounter = -1;
130 2 : const char *pszSatId1 = CSLFetchNameValue(
131 1 : m_papszIMDMD,
132 : "Dataset_Sources.Source_Information.Scene_Source.MISSION");
133 1 : if (nullptr == pszSatId1)
134 : {
135 0 : nCounter = 1;
136 0 : for (int i = 0; i < 5; i++)
137 : {
138 0 : pszSatId1 = CSLFetchNameValue(
139 0 : m_papszIMDMD, CPLSPrintf("Dataset_Sources.Source_Information_%"
140 : "d.Scene_Source.MISSION",
141 : nCounter));
142 0 : if (nullptr != pszSatId1)
143 0 : break;
144 0 : nCounter++;
145 : }
146 : }
147 :
148 : const char *pszSatId2;
149 1 : if (nCounter == -1)
150 1 : pszSatId2 = CSLFetchNameValue(
151 1 : m_papszIMDMD,
152 : "Dataset_Sources.Source_Information.Scene_Source.MISSION_INDEX");
153 : else
154 0 : pszSatId2 = CSLFetchNameValue(
155 0 : m_papszIMDMD, CPLSPrintf("Dataset_Sources.Source_Information_%d."
156 : "Scene_Source.MISSION_INDEX",
157 : nCounter));
158 :
159 1 : if (nullptr != pszSatId1 && nullptr != pszSatId2)
160 : {
161 2 : m_papszIMAGERYMD = CSLAddNameValue(
162 : m_papszIMAGERYMD, MD_NAME_SATELLITE,
163 2 : CPLSPrintf("%s %s", CPLStripQuotes(pszSatId1).c_str(),
164 2 : CPLStripQuotes(pszSatId2).c_str()));
165 : }
166 0 : else if (nullptr != pszSatId1 && nullptr == pszSatId2)
167 : {
168 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
169 0 : CPLStripQuotes(pszSatId1));
170 : }
171 0 : else if (nullptr == pszSatId1 && nullptr != pszSatId2)
172 : {
173 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
174 0 : CPLStripQuotes(pszSatId2));
175 : }
176 :
177 : const char *pszDate;
178 1 : if (nCounter == -1)
179 1 : pszDate = CSLFetchNameValue(
180 1 : m_papszIMDMD,
181 : "Dataset_Sources.Source_Information.Scene_Source.IMAGING_DATE");
182 : else
183 0 : pszDate = CSLFetchNameValue(
184 0 : m_papszIMDMD, CPLSPrintf("Dataset_Sources.Source_Information_%d."
185 : "Scene_Source.IMAGING_DATE",
186 : nCounter));
187 :
188 1 : if (nullptr != pszDate)
189 : {
190 : const char *pszTime;
191 1 : if (nCounter == -1)
192 1 : pszTime = CSLFetchNameValue(
193 1 : m_papszIMDMD,
194 : "Dataset_Sources.Source_Information.Scene_Source.IMAGING_TIME");
195 : else
196 0 : pszTime = CSLFetchNameValue(
197 0 : m_papszIMDMD, CPLSPrintf("Dataset_Sources.Source_Information_%"
198 : "d.Scene_Source.IMAGING_TIME",
199 : nCounter));
200 :
201 1 : if (nullptr == pszTime)
202 0 : pszTime = "00:00:00.0Z";
203 :
204 : char buffer[80];
205 : GIntBig timeMid =
206 1 : GetAcquisitionTimeFromString(CPLSPrintf("%sT%s", pszDate, pszTime));
207 : struct tm tmBuf;
208 1 : strftime(buffer, 80, MD_DATETIMEFORMAT,
209 1 : CPLUnixTimeToYMDHMS(timeMid, &tmBuf));
210 1 : m_papszIMAGERYMD =
211 1 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_ACQDATETIME, buffer);
212 : }
213 :
214 1 : m_papszIMAGERYMD =
215 1 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER, MD_CLOUDCOVER_NA);
216 : }
217 :
218 : /**
219 : * ReadXMLToList()
220 : */
221 58 : char **GDALMDReaderSpot::ReadXMLToList(CPLXMLNode *psNode, char **papszList,
222 : const char *pszName)
223 : {
224 58 : if (nullptr == psNode)
225 0 : return papszList;
226 :
227 58 : if (psNode->eType == CXT_Text)
228 : {
229 22 : if (!EQUAL(pszName, ""))
230 22 : return AddXMLNameValueToList(papszList, pszName, psNode->pszValue);
231 : }
232 :
233 36 : if (psNode->eType == CXT_Element && !EQUAL(psNode->pszValue, "Data_Strip"))
234 : {
235 31 : int nAddIndex = 0;
236 31 : bool bReset = false;
237 80 : for (CPLXMLNode *psChildNode = psNode->psChild; nullptr != psChildNode;
238 49 : psChildNode = psChildNode->psNext)
239 : {
240 49 : if (psChildNode->eType == CXT_Element)
241 : {
242 : // check name duplicates
243 25 : if (nullptr != psChildNode->psNext)
244 : {
245 16 : if (bReset)
246 : {
247 0 : bReset = false;
248 0 : nAddIndex = 0;
249 : }
250 :
251 16 : if (EQUAL(psChildNode->pszValue,
252 : psChildNode->psNext->pszValue))
253 : {
254 0 : nAddIndex++;
255 : }
256 : else
257 : { // the name changed
258 :
259 16 : if (nAddIndex > 0)
260 : {
261 0 : bReset = true;
262 0 : nAddIndex++;
263 : }
264 : }
265 : }
266 : else
267 : {
268 9 : if (nAddIndex > 0)
269 : {
270 0 : nAddIndex++;
271 : }
272 : }
273 :
274 : char szName[512];
275 25 : if (nAddIndex > 0)
276 : {
277 0 : CPLsnprintf(szName, 511, "%s_%d", psChildNode->pszValue,
278 : nAddIndex);
279 : }
280 : else
281 : {
282 25 : CPLStrlcpy(szName, psChildNode->pszValue, 511);
283 : }
284 :
285 : char szNameNew[512];
286 25 : if (CPLStrnlen(pszName, 511) >
287 : 0) // if no prefix just set name to node name
288 : {
289 10 : CPLsnprintf(szNameNew, 511, "%s.%s", pszName, szName);
290 : }
291 : else
292 : {
293 15 : CPLsnprintf(szNameNew, 511, "%s.%s", psNode->pszValue,
294 : szName);
295 : }
296 :
297 25 : papszList = ReadXMLToList(psChildNode, papszList, szNameNew);
298 : }
299 : else
300 : {
301 : // Text nodes should always have name
302 24 : if (EQUAL(pszName, ""))
303 : {
304 : papszList =
305 0 : ReadXMLToList(psChildNode, papszList, psNode->pszValue);
306 : }
307 : else
308 : {
309 24 : papszList = ReadXMLToList(psChildNode, papszList, pszName);
310 : }
311 : }
312 : }
313 : }
314 :
315 : // proceed next only on top level
316 :
317 36 : if (nullptr != psNode->psNext && EQUAL(pszName, ""))
318 : {
319 8 : papszList = ReadXMLToList(psNode->psNext, papszList, pszName);
320 : }
321 :
322 36 : return papszList;
323 : }
|