1 /******************************************************************************
2  *
3  * Project:  GDAL Core
4  * Purpose:  Read metadata from GeoEye 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_geo_eye.h"
32 
33 #include <cstddef>
34 #include <cstdio>
35 #include <cstring>
36 
37 #include <string>
38 
39 #include "cpl_conv.h"
40 #include "cpl_error.h"
41 #include "cpl_string.h"
42 
43 CPL_CVSID("$Id: reader_geo_eye.cpp 67e459b8519f44a70d2d7ce774553b59442f5097 2020-06-29 20:35:34 +0200 Even Rouault $")
44 
45 /**
46  * GDALMDReaderGeoEye()
47  */
GDALMDReaderGeoEye(const char * pszPath,char ** papszSiblingFiles)48 GDALMDReaderGeoEye::GDALMDReaderGeoEye(const char *pszPath,
49         char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
50 {
51 
52     const CPLString osBaseName = CPLGetBasename(pszPath);
53     const CPLString osDirName = CPLGetDirname(pszPath);
54     const size_t nBaseNameLen = osBaseName.size();
55     if( nBaseNameLen > 511 )
56         return;
57 
58     // get _metadata.txt file
59 
60     // split file name by _rgb_ or _pan_
61     char szMetadataName[512] = {0};
62     size_t i;
63     for(i = 0; i < nBaseNameLen; i++)
64     {
65         szMetadataName[i] = osBaseName[i];
66         if(STARTS_WITH_CI(osBaseName.c_str() + i, "_rgb_") || STARTS_WITH_CI(osBaseName.c_str() + i, "_pan_"))
67         {
68             break;
69         }
70     }
71 
72     // form metadata file name
73     CPLStrlcpy(szMetadataName + i, "_metadata.txt", 14);
74     CPLString osIMDSourceFilename = CPLFormFilename( osDirName,
75                                                         szMetadataName, nullptr );
76     if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
77     {
78         m_osIMDSourceFilename = osIMDSourceFilename;
79     }
80     else
81     {
82         CPLStrlcpy(szMetadataName + i, "_METADATA.TXT", 14);
83         osIMDSourceFilename = CPLFormFilename( osDirName, szMetadataName, nullptr );
84         if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
85         {
86             m_osIMDSourceFilename = osIMDSourceFilename;
87         }
88     }
89 
90     // get _rpc.txt file
91 
92     CPLString osRPBSourceFilename = CPLFormFilename( osDirName,
93                                                      (osBaseName + "_rpc").c_str(),
94                                                      "txt" );
95     if (CPLCheckForFile(&osRPBSourceFilename[0], papszSiblingFiles))
96     {
97         m_osRPBSourceFilename = osRPBSourceFilename;
98     }
99     else
100     {
101         osRPBSourceFilename = CPLFormFilename( osDirName,
102                                                (osBaseName + "_RPC").c_str(),
103                                                "TXT" );
104         if (CPLCheckForFile(&osRPBSourceFilename[0], papszSiblingFiles))
105         {
106             m_osRPBSourceFilename = osRPBSourceFilename;
107         }
108     }
109 
110     if( !m_osIMDSourceFilename.empty() )
111         CPLDebug( "MDReaderGeoEye", "IMD Filename: %s",
112                   m_osIMDSourceFilename.c_str() );
113     if( !m_osRPBSourceFilename.empty() )
114         CPLDebug( "MDReaderGeoEye", "RPB Filename: %s",
115                   m_osRPBSourceFilename.c_str() );
116 }
117 
118 /**
119  * ~GDALMDReaderGeoEye()
120  */
~GDALMDReaderGeoEye()121 GDALMDReaderGeoEye::~GDALMDReaderGeoEye()
122 {
123 }
124 
125 /**
126  * HasRequiredFiles()
127  */
HasRequiredFiles() const128 bool GDALMDReaderGeoEye::HasRequiredFiles() const
129 {
130     if (!m_osIMDSourceFilename.empty())
131         return true;
132 
133     if (!m_osRPBSourceFilename.empty())
134         return true;
135 
136     return false;
137 }
138 
139 /**
140  * GetMetadataFiles()
141  */
GetMetadataFiles() const142 char** GDALMDReaderGeoEye::GetMetadataFiles() const
143 {
144     char **papszFileList = nullptr;
145     if(!m_osIMDSourceFilename.empty())
146         papszFileList= CSLAddString( papszFileList, m_osIMDSourceFilename );
147     if(!m_osRPBSourceFilename.empty())
148         papszFileList = CSLAddString( papszFileList, m_osRPBSourceFilename );
149 
150     return papszFileList;
151 }
152 
153 /**
154  * LoadMetadata()
155  */
LoadMetadata()156 void GDALMDReaderGeoEye::LoadMetadata()
157 {
158     if(m_bIsMetadataLoad)
159         return;
160 
161     if (!m_osIMDSourceFilename.empty())
162     {
163         m_papszIMDMD = LoadIMDWktFile( );
164     }
165 
166     if(!m_osRPBSourceFilename.empty())
167     {
168         m_papszRPCMD = GDALLoadRPCFile( m_osRPBSourceFilename );
169     }
170 
171     m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "GE");
172 
173     m_bIsMetadataLoad = true;
174 
175     if(nullptr == m_papszIMDMD)
176     {
177         return;
178     }
179 
180     //extract imagery metadata
181     const char* pszSatId = CSLFetchNameValue(m_papszIMDMD,
182                                              "Source Image Metadata.Sensor");
183     if(nullptr != pszSatId)
184     {
185         m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
186                                            MD_NAME_SATELLITE,
187                                            CPLStripQuotes(pszSatId));
188     }
189 
190     const char* pszCloudCover = CSLFetchNameValue(m_papszIMDMD,
191                                    "Source Image Metadata.Percent Cloud Cover");
192     if(nullptr != pszCloudCover)
193     {
194         m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
195                                            MD_NAME_CLOUDCOVER, pszCloudCover);
196     }
197 
198     const char* pszDateTime = CSLFetchNameValue(m_papszIMDMD,
199                                  "Source Image Metadata.Acquisition Date/Time");
200 
201     if(nullptr != pszDateTime)
202     {
203         char buffer[80];
204         time_t timeMid = GetAcquisitionTimeFromString(pszDateTime);
205 
206         strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
207         m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
208                                            MD_NAME_ACQDATETIME, buffer);
209     }
210 }
211 
212 /**
213  * GetAcqisitionTimeFromString()
214  */
GetAcquisitionTimeFromString(const char * pszDateTime)215 time_t GDALMDReaderGeoEye::GetAcquisitionTimeFromString(
216         const char* pszDateTime)
217 {
218     if(nullptr == pszDateTime)
219         return 0;
220 
221     int iYear;
222     int iMonth;
223     int iDay;
224     int iHours;
225     int iMin;
226     int iSec = 0;
227 
228     // string example: Acquisition Date/Time: 2006-03-01 11:08 GMT
229 
230     int r = sscanf ( pszDateTime, "%d-%d-%d %d:%d GMT", &iYear, &iMonth,
231                      &iDay, &iHours, &iMin);
232 
233     if (r != 5)
234         return 0;
235 
236     struct tm tmDateTime;
237     tmDateTime.tm_sec = iSec;
238     tmDateTime.tm_min = iMin;
239     tmDateTime.tm_hour = iHours;
240     tmDateTime.tm_mday = iDay;
241     tmDateTime.tm_mon = iMonth - 1;
242     tmDateTime.tm_year = iYear - 1900;
243     tmDateTime.tm_isdst = -1;
244 
245     return mktime(&tmDateTime);
246 }
247 
248 /**
249  * LoadWKTIMDFile()
250  */
LoadIMDWktFile() const251 char** GDALMDReaderGeoEye::LoadIMDWktFile() const
252 {
253     char** papszResultList = nullptr;
254     char** papszLines = CSLLoad( m_osIMDSourceFilename );
255     bool bBeginSection = false;
256     CPLString osSection;
257     CPLString osKeyLevel1;
258     CPLString osKeyLevel2;
259     CPLString osKeyLevel3;
260     int nLevel = 0;
261     int nSpaceCount;
262 
263     if( papszLines == nullptr )
264         return nullptr;
265 
266     for( int i = 0; papszLines[i] != nullptr; i++ )
267     {
268         // skip section (=== or ---) lines
269 
270         if(STARTS_WITH_CI(papszLines[i], "==="))
271         {
272             bBeginSection = true;
273             continue;
274         }
275 
276         if(STARTS_WITH_CI(papszLines[i], "---") || CPLStrnlen(papszLines[i], 512) == 0)
277             continue;
278 
279         // check the metadata level
280         nSpaceCount = 0;
281         for(int j = 0; j < 11; j++)
282         {
283             if(papszLines[i][j] != ' ')
284                 break;
285             nSpaceCount++;
286         }
287 
288         if(nSpaceCount % 3 != 0)
289             continue; // not a metadata item
290         nLevel = nSpaceCount / 3;
291 
292         const char *pszValue;
293         char *pszKey = nullptr;
294         pszValue = CPLParseNameValue(papszLines[i], &pszKey);
295 
296         if(nullptr != pszValue && CPLStrnlen(pszValue, 512) > 0)
297         {
298 
299             CPLString osCurrentKey;
300             if(nLevel == 0)
301             {
302                 osCurrentKey = CPLOPrintf("%s", pszKey);
303             }
304             else if(nLevel == 1)
305             {
306                 osCurrentKey = osKeyLevel1 + "." +
307                         CPLOPrintf("%s", pszKey + nSpaceCount);
308             }
309             else if(nLevel == 2)
310             {
311                 osCurrentKey = osKeyLevel1 + "." +
312                         osKeyLevel2 + "." + CPLOPrintf("%s", pszKey + nSpaceCount);
313             }
314             else if(nLevel == 3)
315             {
316                 osCurrentKey = osKeyLevel1 + "." +
317                         osKeyLevel2 + "." + osKeyLevel3 + "." +
318                         CPLOPrintf("%s", pszKey + nSpaceCount);
319             }
320 
321             if(!osSection.empty())
322             {
323                 osCurrentKey = osSection + "." + osCurrentKey;
324             }
325 
326             papszResultList = CSLAddNameValue(papszResultList, osCurrentKey, pszValue);
327         }
328 
329         if(nullptr != pszKey && CPLStrnlen(pszKey, 512) > 0)
330         {
331             if(bBeginSection)
332             {
333                 osSection = CPLOPrintf("%s", pszKey);
334                 bBeginSection = false;
335             }
336             else if(nLevel == 0)
337             {
338                 osKeyLevel1 = CPLOPrintf("%s", pszKey);
339             }
340             else if(nLevel == 1)
341             {
342                 osKeyLevel2 = CPLOPrintf("%s", pszKey + nSpaceCount);
343             }
344             else if(nLevel == 2)
345             {
346                 osKeyLevel3 = CPLOPrintf("%s", pszKey + nSpaceCount);
347             }
348         }
349         else
350         {
351             if(bBeginSection)
352             {
353                 osSection = CPLOPrintf("%s", papszLines[i]);
354                 bBeginSection = false;
355             }
356             else if(nLevel == 0)
357             {
358                 osKeyLevel1 = CPLOPrintf("%s", papszLines[i]);
359             }
360             else if(nLevel == 1)
361             {
362                 osKeyLevel2 = CPLOPrintf("%s", papszLines[i] + nSpaceCount);
363             }
364             else if(nLevel == 2)
365             {
366                 osKeyLevel3 = CPLOPrintf("%s", papszLines[i]+ nSpaceCount);
367             }
368         }
369 
370         CPLFree( pszKey );
371     }
372 
373     CSLDestroy( papszLines );
374 
375     return papszResultList;
376 }
377