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