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