Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Read metadata from Alos 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 "reader_alos.h"
15 :
16 : #include <cstdio>
17 : #include <cstdlib>
18 :
19 : #include <string>
20 :
21 : #include "cpl_conv.h"
22 : #include "cpl_error.h"
23 : #include "cpl_string.h"
24 : #include "cpl_time.h"
25 : #include "gdal_mdreader.h"
26 :
27 : /**
28 : * GDALMDReaderALOS()
29 : */
30 5342 : GDALMDReaderALOS::GDALMDReaderALOS(const char *pszPath,
31 5342 : char **papszSiblingFiles)
32 5342 : : GDALMDReaderBase(pszPath, papszSiblingFiles)
33 : {
34 10684 : const CPLString osDirName = CPLGetDirnameSafe(pszPath);
35 10684 : const CPLString osBaseName = CPLGetBasenameSafe(pszPath);
36 :
37 : CPLString osIMDSourceFilename =
38 10684 : CPLFormFilenameSafe(osDirName, "summary", ".txt");
39 5342 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
40 : {
41 1 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
42 : }
43 : else
44 : {
45 5341 : osIMDSourceFilename = CPLFormFilenameSafe(osDirName, "SUMMARY", ".TXT");
46 5341 : if (CPLCheckForFile(&osIMDSourceFilename[0], papszSiblingFiles))
47 : {
48 0 : m_osIMDSourceFilename = std::move(osIMDSourceFilename);
49 : }
50 : }
51 :
52 5342 : if (osBaseName.size() >= 6)
53 : {
54 : // check if this is separate band or whole image
55 : // test without 6 symbols
56 6342 : CPLString osHDRFileName = CPLFormFilenameSafe(
57 6342 : osDirName, (std::string("HDR") + (osBaseName.c_str() + 6)).c_str(),
58 6342 : "txt");
59 3171 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
60 : {
61 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
62 : }
63 : else
64 : {
65 3171 : osHDRFileName = CPLFormFilenameSafe(
66 : osDirName,
67 6342 : (std::string("HDR") + (osBaseName.c_str() + 6)).c_str(), "TXT");
68 3171 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
69 : {
70 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
71 : }
72 : }
73 : }
74 :
75 : // test without 3 symbols
76 5342 : if (osBaseName.size() >= 3 && m_osHDRSourceFilename.empty())
77 : {
78 10648 : CPLString osHDRFileName = CPLFormFilenameSafe(
79 10648 : osDirName, (std::string("HDR") + (osBaseName.c_str() + 3)).c_str(),
80 10648 : "txt");
81 5324 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
82 : {
83 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
84 : }
85 : else
86 : {
87 5324 : osHDRFileName = CPLFormFilenameSafe(
88 : osDirName,
89 10648 : (std::string("HDR") + (osBaseName.c_str() + 3)).c_str(), "TXT");
90 5324 : if (CPLCheckForFile(&osHDRFileName[0], papszSiblingFiles))
91 : {
92 0 : m_osHDRSourceFilename = std::move(osHDRFileName);
93 : }
94 : }
95 : }
96 :
97 : // test without 6 symbols
98 5342 : if (osBaseName.size() >= 6)
99 : {
100 6342 : CPLString osRPCFileName = CPLFormFilenameSafe(
101 6342 : osDirName, (std::string("RPC") + (osBaseName.c_str() + 6)).c_str(),
102 6342 : "txt");
103 3171 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
104 : {
105 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
106 : }
107 : else
108 : {
109 3171 : osRPCFileName = CPLFormFilenameSafe(
110 : osDirName,
111 6342 : (std::string("RPC") + (osBaseName.c_str() + 6)).c_str(), "TXT");
112 3171 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
113 : {
114 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
115 : }
116 : }
117 : }
118 :
119 : // test without 3 symbols
120 5342 : if (osBaseName.size() >= 3 && m_osRPBSourceFilename.empty())
121 : {
122 10648 : CPLString osRPCFileName = CPLFormFilenameSafe(
123 10648 : osDirName, (std::string("RPC") + (osBaseName.c_str() + 3)).c_str(),
124 10648 : "txt");
125 5324 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
126 : {
127 1 : m_osRPBSourceFilename = std::move(osRPCFileName);
128 : }
129 : else
130 : {
131 5323 : osRPCFileName = CPLFormFilenameSafe(
132 : osDirName,
133 10646 : (std::string("RPC") + (osBaseName.c_str() + 3)).c_str(), "TXT");
134 5323 : if (CPLCheckForFile(&osRPCFileName[0], papszSiblingFiles))
135 : {
136 0 : m_osRPBSourceFilename = std::move(osRPCFileName);
137 : }
138 : }
139 : }
140 :
141 5342 : if (!m_osIMDSourceFilename.empty())
142 1 : CPLDebug("MDReaderALOS", "IMD Filename: %s",
143 : m_osIMDSourceFilename.c_str());
144 5342 : if (!m_osHDRSourceFilename.empty())
145 0 : CPLDebug("MDReaderALOS", "HDR Filename: %s",
146 : m_osHDRSourceFilename.c_str());
147 5342 : if (!m_osRPBSourceFilename.empty())
148 1 : CPLDebug("MDReaderALOS", "RPB Filename: %s",
149 : m_osRPBSourceFilename.c_str());
150 5342 : }
151 :
152 : /**
153 : * ~GDALMDReaderALOS()
154 : */
155 10684 : GDALMDReaderALOS::~GDALMDReaderALOS()
156 : {
157 10684 : }
158 :
159 : /**
160 : * HasRequiredFiles()
161 : */
162 5342 : bool GDALMDReaderALOS::HasRequiredFiles() const
163 : {
164 5342 : if (!m_osIMDSourceFilename.empty())
165 1 : return true;
166 :
167 5341 : if (!m_osHDRSourceFilename.empty() && !m_osRPBSourceFilename.empty())
168 0 : return true;
169 :
170 5341 : return false;
171 : }
172 :
173 : /**
174 : * GetMetadataFiles()
175 : */
176 1 : char **GDALMDReaderALOS::GetMetadataFiles() const
177 : {
178 1 : char **papszFileList = nullptr;
179 1 : if (!m_osIMDSourceFilename.empty())
180 1 : papszFileList = CSLAddString(papszFileList, m_osIMDSourceFilename);
181 1 : if (!m_osHDRSourceFilename.empty())
182 0 : papszFileList = CSLAddString(papszFileList, m_osHDRSourceFilename);
183 1 : if (!m_osRPBSourceFilename.empty())
184 1 : papszFileList = CSLAddString(papszFileList, m_osRPBSourceFilename);
185 :
186 1 : return papszFileList;
187 : }
188 :
189 : /**
190 : * LoadMetadata()
191 : */
192 2 : void GDALMDReaderALOS::LoadMetadata()
193 : {
194 2 : if (m_bIsMetadataLoad)
195 1 : return;
196 :
197 1 : if (!m_osIMDSourceFilename.empty())
198 : {
199 1 : m_papszIMDMD = CSLLoad(m_osIMDSourceFilename);
200 : }
201 :
202 1 : if (!m_osHDRSourceFilename.empty())
203 : {
204 0 : if (nullptr == m_papszIMDMD)
205 : {
206 0 : m_papszIMDMD = CSLLoad(m_osHDRSourceFilename);
207 : }
208 : else
209 : {
210 0 : char **papszHDR = CSLLoad(m_osHDRSourceFilename);
211 0 : m_papszIMDMD = CSLMerge(m_papszIMDMD, papszHDR);
212 0 : CSLDestroy(papszHDR);
213 : }
214 : }
215 :
216 1 : m_papszRPCMD = LoadRPCTxtFile();
217 :
218 1 : m_papszDEFAULTMD =
219 1 : CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "ALOS");
220 :
221 1 : m_bIsMetadataLoad = true;
222 :
223 1 : const char *pszSatId1 = CSLFetchNameValue(m_papszIMDMD, "Lbi_Satellite");
224 1 : const char *pszSatId2 = CSLFetchNameValue(m_papszIMDMD, "Lbi_Sensor");
225 1 : if (nullptr != pszSatId1 && nullptr != pszSatId2)
226 : {
227 2 : m_papszIMAGERYMD = CSLAddNameValue(
228 : m_papszIMAGERYMD, MD_NAME_SATELLITE,
229 2 : CPLSPrintf("%s %s", CPLStripQuotes(pszSatId1).c_str(),
230 2 : CPLStripQuotes(pszSatId2).c_str()));
231 : }
232 0 : else if (nullptr != pszSatId1 && nullptr == pszSatId2)
233 : {
234 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
235 0 : CPLStripQuotes(pszSatId1));
236 : }
237 0 : else if (nullptr == pszSatId1 && nullptr != pszSatId2)
238 : {
239 0 : m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
240 0 : CPLStripQuotes(pszSatId2));
241 : }
242 :
243 : const char *pszCloudCover =
244 1 : CSLFetchNameValue(m_papszIMDMD, "Img_CloudQuantityOfAllImage");
245 1 : if (nullptr != pszCloudCover)
246 : {
247 0 : int nCC = atoi(pszCloudCover);
248 0 : if (nCC >= 99)
249 : {
250 0 : m_papszIMAGERYMD = CSLAddNameValue(
251 : m_papszIMAGERYMD, MD_NAME_CLOUDCOVER, MD_CLOUDCOVER_NA);
252 : }
253 : else
254 : {
255 0 : m_papszIMAGERYMD =
256 0 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
257 : CPLSPrintf("%d", nCC * 10));
258 : }
259 : }
260 :
261 : const char *pszDate =
262 1 : CSLFetchNameValue(m_papszIMDMD, "Img_SceneCenterDateTime");
263 :
264 1 : if (nullptr != pszDate)
265 : {
266 : char buffer[80];
267 0 : GIntBig timeMid = GetAcquisitionTimeFromString(CPLStripQuotes(pszDate));
268 : struct tm tmBuf;
269 0 : strftime(buffer, 80, MD_DATETIMEFORMAT,
270 0 : CPLUnixTimeToYMDHMS(timeMid, &tmBuf));
271 0 : m_papszIMAGERYMD =
272 0 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_ACQDATETIME, buffer);
273 : }
274 : else
275 : {
276 1 : pszDate = CSLFetchNameValue(m_papszIMDMD, "Lbi_ObservationDate");
277 1 : if (nullptr != pszDate)
278 : {
279 1 : const char *pszTime = "00:00:00.000";
280 :
281 : char buffer[80];
282 2 : GIntBig timeMid = GetAcquisitionTimeFromString(
283 2 : CPLSPrintf("%s %s", CPLStripQuotes(pszDate).c_str(),
284 2 : CPLStripQuotes(pszTime).c_str()));
285 : struct tm tmBuf;
286 1 : strftime(buffer, 80, MD_DATETIMEFORMAT,
287 1 : CPLUnixTimeToYMDHMS(timeMid, &tmBuf));
288 1 : m_papszIMAGERYMD =
289 1 : CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_ACQDATETIME, buffer);
290 : }
291 : }
292 : }
293 :
294 : /**
295 : * LoadRPCTxtFile
296 : */
297 1 : char **GDALMDReaderALOS::LoadRPCTxtFile()
298 : {
299 1 : if (m_osRPBSourceFilename.empty())
300 0 : return nullptr;
301 :
302 2 : const CPLStringList aosLines(CSLLoad(m_osRPBSourceFilename));
303 1 : if (aosLines.empty())
304 0 : return nullptr;
305 :
306 1 : const char *pszFirstRow = aosLines[0];
307 2 : CPLStringList aosRPB;
308 1 : if (nullptr != pszFirstRow)
309 : {
310 : static const struct
311 : {
312 : const char *pszName;
313 : int nSize;
314 : } apsFieldDescriptors[] = {
315 : {RPC_LINE_OFF, 6}, {RPC_SAMP_OFF, 5}, {RPC_LAT_OFF, 8},
316 : {RPC_LONG_OFF, 9}, {RPC_HEIGHT_OFF, 5}, {RPC_LINE_SCALE, 6},
317 : {RPC_SAMP_SCALE, 5}, {RPC_LAT_SCALE, 8}, {RPC_LONG_SCALE, 9},
318 : {RPC_HEIGHT_SCALE, 5},
319 : };
320 :
321 1 : int nRequiredSize = 0;
322 11 : for (const auto &sFieldDescriptor : apsFieldDescriptors)
323 : {
324 10 : nRequiredSize += sFieldDescriptor.nSize;
325 : }
326 :
327 : static const char *const apszRPCTXT20ValItems[] = {
328 : RPC_LINE_NUM_COEFF, RPC_LINE_DEN_COEFF, RPC_SAMP_NUM_COEFF,
329 : RPC_SAMP_DEN_COEFF};
330 :
331 1 : constexpr int RPC_COEFF_COUNT1 = CPL_ARRAYSIZE(apszRPCTXT20ValItems);
332 1 : constexpr int RPC_COEFF_COUNT2 = 20;
333 1 : constexpr int RPC_COEFF_SIZE = 12;
334 1 : nRequiredSize += RPC_COEFF_COUNT1 * RPC_COEFF_COUNT2 * RPC_COEFF_SIZE;
335 1 : if (strlen(pszFirstRow) < static_cast<size_t>(nRequiredSize))
336 : {
337 0 : CPLError(CE_Failure, CPLE_AppDefined,
338 : "%s has only %d bytes wherea %d are required",
339 0 : m_osRPBSourceFilename.c_str(), int(strlen(pszFirstRow)),
340 : nRequiredSize);
341 0 : return nullptr;
342 : }
343 :
344 1 : int nOffset = 0;
345 1 : char buff[16] = {0};
346 11 : for (const auto &sFieldDescriptor : apsFieldDescriptors)
347 : {
348 10 : CPLAssert(sFieldDescriptor.nSize < int(sizeof(buff)));
349 10 : memcpy(buff, pszFirstRow + nOffset, sFieldDescriptor.nSize);
350 10 : buff[sFieldDescriptor.nSize] = 0;
351 10 : aosRPB.SetNameValue(sFieldDescriptor.pszName, buff);
352 10 : nOffset += sFieldDescriptor.nSize;
353 : }
354 :
355 5 : for (const char *pszItem : apszRPCTXT20ValItems)
356 : {
357 8 : std::string osValue;
358 84 : for (int j = 0; j < RPC_COEFF_COUNT2; j++)
359 : {
360 80 : memcpy(buff, pszFirstRow + nOffset, RPC_COEFF_SIZE);
361 80 : buff[RPC_COEFF_SIZE] = 0;
362 80 : nOffset += RPC_COEFF_SIZE;
363 :
364 80 : if (!osValue.empty())
365 76 : osValue += " ";
366 80 : osValue += buff;
367 : }
368 4 : aosRPB.SetNameValue(pszItem, osValue.c_str());
369 : }
370 : }
371 :
372 1 : return aosRPB.StealList();
373 : }
374 :
375 : /**
376 : * GetAcqisitionTimeFromString()
377 : */
378 1 : GIntBig GDALMDReaderALOS::GetAcquisitionTimeFromString(const char *pszDateTime)
379 : {
380 1 : if (nullptr == pszDateTime)
381 0 : return 0;
382 :
383 : int iYear;
384 : int iMonth;
385 : int iDay;
386 : int iHours;
387 : int iMin;
388 : int iSec;
389 :
390 1 : int r = sscanf(pszDateTime, "%4d%2d%2d %d:%d:%d.%*d", &iYear, &iMonth,
391 : &iDay, &iHours, &iMin, &iSec);
392 :
393 1 : if (r != 6)
394 0 : return 0;
395 :
396 : struct tm tmDateTime;
397 1 : tmDateTime.tm_sec = iSec;
398 1 : tmDateTime.tm_min = iMin;
399 1 : tmDateTime.tm_hour = iHours;
400 1 : tmDateTime.tm_mday = iDay;
401 1 : tmDateTime.tm_mon = iMonth - 1;
402 1 : tmDateTime.tm_year = iYear - 1900;
403 1 : tmDateTime.tm_isdst = -1;
404 :
405 1 : return CPLYMDHMSToUnixTime(&tmDateTime);
406 : }
|