Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ROI_PAC Raster Reader
4 : * Purpose: Implementation of the ROI_PAC raster reader
5 : * Author: Matthieu Volat (ISTerre), matthieu.volat@ujf-grenoble.fr
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2014, Matthieu Volat <matthieu.volat@ujf-grenoble.fr>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "gdal_frmts.h"
30 : #include "ogr_spatialref.h"
31 : #include "rawdataset.h"
32 :
33 : #include <algorithm>
34 :
35 : /************************************************************************/
36 : /* ==================================================================== */
37 : /* ROIPACDataset */
38 : /* ==================================================================== */
39 : /************************************************************************/
40 :
41 : class ROIPACDataset final : public RawDataset
42 : {
43 : VSILFILE *fpImage;
44 : VSILFILE *fpRsc;
45 :
46 : char *pszRscFilename;
47 :
48 : double adfGeoTransform[6];
49 : bool bValidGeoTransform;
50 :
51 : OGRSpatialReference m_oSRS{};
52 :
53 : CPL_DISALLOW_COPY_ASSIGN(ROIPACDataset)
54 :
55 : CPLErr Close() override;
56 :
57 : public:
58 : ROIPACDataset();
59 : ~ROIPACDataset() override;
60 :
61 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
62 : static int Identify(GDALOpenInfo *poOpenInfo);
63 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
64 : int nBandsIn, GDALDataType eType,
65 : char **papszOptions);
66 :
67 : CPLErr FlushCache(bool bAtClosing) override;
68 : CPLErr GetGeoTransform(double *padfTransform) override;
69 : CPLErr SetGeoTransform(double *padfTransform) override;
70 :
71 3 : const OGRSpatialReference *GetSpatialRef() const override
72 : {
73 3 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
74 : }
75 :
76 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
77 :
78 : char **GetFileList() override;
79 : };
80 :
81 : /************************************************************************/
82 : /* getRscFilename() */
83 : /************************************************************************/
84 :
85 172 : static CPLString getRscFilename(GDALOpenInfo *poOpenInfo)
86 : {
87 172 : char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
88 172 : if (papszSiblingFiles == nullptr)
89 : {
90 : const CPLString osRscFilename =
91 174 : CPLFormFilename(nullptr, poOpenInfo->pszFilename, "rsc");
92 : VSIStatBufL psRscStatBuf;
93 87 : if (VSIStatL(osRscFilename, &psRscStatBuf) != 0)
94 : {
95 87 : return "";
96 : }
97 0 : return osRscFilename;
98 : }
99 :
100 : /* ------------------------------------------------------------ */
101 : /* We need to tear apart the filename to form a .rsc */
102 : /* filename. */
103 : /* ------------------------------------------------------------ */
104 170 : const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
105 170 : const CPLString osName = CPLGetFilename(poOpenInfo->pszFilename);
106 :
107 85 : int iFile = CSLFindString(papszSiblingFiles,
108 : CPLFormFilename(nullptr, osName, "rsc"));
109 85 : if (iFile >= 0)
110 : {
111 45 : return CPLFormFilename(osPath, papszSiblingFiles[iFile], nullptr);
112 : }
113 :
114 40 : return "";
115 : }
116 :
117 : /************************************************************************/
118 : /* ROIPACDataset() */
119 : /************************************************************************/
120 :
121 15 : ROIPACDataset::ROIPACDataset()
122 : : fpImage(nullptr), fpRsc(nullptr), pszRscFilename(nullptr),
123 15 : bValidGeoTransform(false)
124 : {
125 15 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
126 15 : adfGeoTransform[0] = 0.0;
127 15 : adfGeoTransform[1] = 1.0;
128 15 : adfGeoTransform[2] = 0.0;
129 15 : adfGeoTransform[3] = 0.0;
130 15 : adfGeoTransform[4] = 0.0;
131 15 : adfGeoTransform[5] = 1.0;
132 15 : }
133 :
134 : /************************************************************************/
135 : /* ~ROIPACDataset() */
136 : /************************************************************************/
137 :
138 30 : ROIPACDataset::~ROIPACDataset()
139 : {
140 15 : ROIPACDataset::Close();
141 30 : }
142 :
143 : /************************************************************************/
144 : /* Close() */
145 : /************************************************************************/
146 :
147 30 : CPLErr ROIPACDataset::Close()
148 : {
149 30 : CPLErr eErr = CE_None;
150 30 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
151 : {
152 15 : if (ROIPACDataset::FlushCache(true) != CE_None)
153 0 : eErr = CE_Failure;
154 :
155 15 : if (fpRsc != nullptr && VSIFCloseL(fpRsc) != 0)
156 : {
157 0 : eErr = CE_Failure;
158 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
159 : }
160 15 : if (fpImage != nullptr && VSIFCloseL(fpImage) != 0)
161 : {
162 0 : eErr = CE_Failure;
163 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
164 : }
165 15 : CPLFree(pszRscFilename);
166 :
167 15 : if (GDALPamDataset::Close() != CE_None)
168 0 : eErr = CE_Failure;
169 : }
170 30 : return eErr;
171 : }
172 :
173 : /************************************************************************/
174 : /* Open() */
175 : /************************************************************************/
176 :
177 15 : GDALDataset *ROIPACDataset::Open(GDALOpenInfo *poOpenInfo)
178 : {
179 : /* -------------------------------------------------------------------- */
180 : /* Confirm that the header is compatible with a ROIPAC dataset. */
181 : /* -------------------------------------------------------------------- */
182 15 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
183 : {
184 0 : return nullptr;
185 : }
186 :
187 : /* -------------------------------------------------------------------- */
188 : /* Open the .rsc file */
189 : /* -------------------------------------------------------------------- */
190 30 : CPLString osRscFilename = getRscFilename(poOpenInfo);
191 15 : if (osRscFilename.empty())
192 : {
193 0 : return nullptr;
194 : }
195 15 : VSILFILE *fpRsc = nullptr;
196 15 : if (poOpenInfo->eAccess == GA_Update)
197 : {
198 3 : fpRsc = VSIFOpenL(osRscFilename, "r+");
199 : }
200 : else
201 : {
202 12 : fpRsc = VSIFOpenL(osRscFilename, "r");
203 : }
204 15 : if (fpRsc == nullptr)
205 : {
206 0 : return nullptr;
207 : }
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* Load the .rsc information. */
211 : /* -------------------------------------------------------------------- */
212 30 : CPLStringList aosRSC;
213 : while (true)
214 : {
215 189 : const char *pszLine = CPLReadLineL(fpRsc);
216 189 : if (pszLine == nullptr)
217 : {
218 15 : break;
219 : }
220 :
221 : char **papszTokens =
222 174 : CSLTokenizeString2(pszLine, " \t",
223 : CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES |
224 : CSLT_PRESERVEQUOTES | CSLT_PRESERVEESCAPES);
225 174 : if (papszTokens == nullptr || papszTokens[0] == nullptr ||
226 174 : papszTokens[1] == nullptr)
227 : {
228 0 : CSLDestroy(papszTokens);
229 0 : break;
230 : }
231 174 : aosRSC.SetNameValue(papszTokens[0], papszTokens[1]);
232 :
233 174 : CSLDestroy(papszTokens);
234 174 : }
235 :
236 : /* -------------------------------------------------------------------- */
237 : /* Fetch required fields. */
238 : /* -------------------------------------------------------------------- */
239 30 : if (aosRSC.FetchNameValue("WIDTH") == nullptr ||
240 15 : aosRSC.FetchNameValue("FILE_LENGTH") == nullptr)
241 : {
242 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpRsc));
243 0 : return nullptr;
244 : }
245 15 : const int nWidth = atoi(aosRSC.FetchNameValue("WIDTH"));
246 15 : const int nFileLength = atoi(aosRSC.FetchNameValue("FILE_LENGTH"));
247 :
248 15 : if (!GDALCheckDatasetDimensions(nWidth, nFileLength))
249 : {
250 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpRsc));
251 0 : return nullptr;
252 : }
253 :
254 : /* -------------------------------------------------------------------- */
255 : /* Create a corresponding GDALDataset. */
256 : /* -------------------------------------------------------------------- */
257 30 : auto poDS = std::make_unique<ROIPACDataset>();
258 15 : poDS->nRasterXSize = nWidth;
259 15 : poDS->nRasterYSize = nFileLength;
260 15 : poDS->eAccess = poOpenInfo->eAccess;
261 15 : poDS->fpRsc = fpRsc;
262 15 : poDS->pszRscFilename = CPLStrdup(osRscFilename.c_str());
263 15 : std::swap(poDS->fpImage, poOpenInfo->fpL);
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Create band information objects. */
267 : /* -------------------------------------------------------------------- */
268 15 : GDALDataType eDataType = GDT_Unknown;
269 15 : int nBands = 0;
270 :
271 : enum Interleave
272 : {
273 : UNKNOWN,
274 : LINE,
275 : PIXEL
276 15 : } eInterleave = UNKNOWN;
277 :
278 15 : const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
279 15 : if (strcmp(pszExtension, "raw") == 0)
280 : {
281 : /* ------------------------------------------------------------ */
282 : /* TODO: ROI_PAC raw images are what would be GDT_CInt8 typed, */
283 : /* but since that type do not exist, we will have to implement */
284 : /* a specific case in the RasterBand to convert it to */
285 : /* GDT_CInt16 for example */
286 : /* ------------------------------------------------------------ */
287 : #if 0
288 : eDataType = GDT_CInt8;
289 : nBands = 1;
290 : eInterleave = PIXEL;
291 : #else
292 0 : CPLError(CE_Failure, CPLE_NotSupported,
293 : "Reading ROI_PAC raw files is not supported yet.");
294 0 : return nullptr;
295 : #endif
296 : }
297 15 : else if (strcmp(pszExtension, "int") == 0 ||
298 15 : strcmp(pszExtension, "slc") == 0)
299 : {
300 0 : eDataType = GDT_CFloat32;
301 0 : nBands = 1;
302 0 : eInterleave = PIXEL;
303 : }
304 15 : else if (strcmp(pszExtension, "amp") == 0)
305 : {
306 0 : eDataType = GDT_Float32;
307 0 : nBands = 2;
308 0 : eInterleave = PIXEL;
309 : }
310 15 : else if (strcmp(pszExtension, "cor") == 0 ||
311 15 : strcmp(pszExtension, "hgt") == 0 ||
312 15 : strcmp(pszExtension, "unw") == 0 ||
313 15 : strcmp(pszExtension, "msk") == 0 ||
314 15 : strcmp(pszExtension, "trans") == 0)
315 : {
316 0 : eDataType = GDT_Float32;
317 0 : nBands = 2;
318 0 : eInterleave = LINE;
319 : }
320 15 : else if (strcmp(pszExtension, "dem") == 0)
321 : {
322 12 : eDataType = GDT_Int16;
323 12 : nBands = 1;
324 12 : eInterleave = PIXEL;
325 : }
326 3 : else if (strcmp(pszExtension, "flg") == 0)
327 : {
328 3 : eDataType = GDT_Byte;
329 3 : nBands = 1;
330 3 : eInterleave = PIXEL;
331 : }
332 : else
333 : { /* Eeek */
334 0 : return nullptr;
335 : }
336 :
337 15 : int nPixelOffset = 0;
338 15 : int nLineOffset = 0;
339 15 : vsi_l_offset nBandOffset = 0;
340 15 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
341 15 : bool bIntOverflow = false;
342 15 : if (eInterleave == LINE)
343 : {
344 0 : nPixelOffset = nDTSize;
345 0 : if (nWidth > INT_MAX / (nPixelOffset * nBands))
346 0 : bIntOverflow = true;
347 : else
348 : {
349 0 : nLineOffset = nPixelOffset * nWidth * nBands;
350 0 : nBandOffset = static_cast<vsi_l_offset>(nDTSize) * nWidth;
351 : }
352 : }
353 : else
354 : { /* PIXEL */
355 15 : nPixelOffset = nDTSize * nBands;
356 15 : if (nWidth > INT_MAX / nPixelOffset)
357 0 : bIntOverflow = true;
358 : else
359 : {
360 15 : nLineOffset = nPixelOffset * nWidth;
361 15 : nBandOffset = nDTSize;
362 :
363 15 : if (nBands > 1)
364 : {
365 : // GDAL 2.0.[0-3] and 2.1.0 had a value of nLineOffset that was
366 : // equal to the theoretical nLineOffset multiplied by nBands.
367 0 : VSIFSeekL(poDS->fpImage, 0, SEEK_END);
368 0 : const GUIntBig nWrongFileSize =
369 0 : static_cast<GUIntBig>(nDTSize) * nWidth *
370 0 : (static_cast<GUIntBig>(nFileLength - 1) * nBands * nBands +
371 : nBands);
372 0 : if (VSIFTellL(poDS->fpImage) == nWrongFileSize)
373 : {
374 0 : CPLError(
375 : CE_Warning, CPLE_AppDefined,
376 : "This file has been incorrectly generated by an older "
377 : "GDAL version whose line offset computation was "
378 : "erroneous. Taking that into account, "
379 : "but the file should be re-encoded ideally.");
380 0 : nLineOffset = nLineOffset * nBands;
381 : }
382 : }
383 : }
384 : }
385 :
386 15 : if (bIntOverflow)
387 : {
388 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
389 0 : return nullptr;
390 : }
391 :
392 30 : for (int b = 0; b < nBands; b++)
393 : {
394 : auto poBand = RawRasterBand::Create(
395 30 : poDS.get(), b + 1, poDS->fpImage, nBandOffset * b, nPixelOffset,
396 : nLineOffset, eDataType,
397 : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN,
398 15 : RawRasterBand::OwnFP::NO);
399 15 : if (!poBand)
400 0 : return nullptr;
401 15 : poDS->SetBand(b + 1, std::move(poBand));
402 : }
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* Interpret georeferencing, if present. */
406 : /* -------------------------------------------------------------------- */
407 15 : if (aosRSC.FetchNameValue("X_FIRST") != nullptr &&
408 12 : aosRSC.FetchNameValue("X_STEP") != nullptr &&
409 39 : aosRSC.FetchNameValue("Y_FIRST") != nullptr &&
410 12 : aosRSC.FetchNameValue("Y_STEP") != nullptr)
411 : {
412 12 : poDS->adfGeoTransform[0] = CPLAtof(aosRSC.FetchNameValue("X_FIRST"));
413 12 : poDS->adfGeoTransform[1] = CPLAtof(aosRSC.FetchNameValue("X_STEP"));
414 12 : poDS->adfGeoTransform[2] = 0.0;
415 12 : poDS->adfGeoTransform[3] = CPLAtof(aosRSC.FetchNameValue("Y_FIRST"));
416 12 : poDS->adfGeoTransform[4] = 0.0;
417 12 : poDS->adfGeoTransform[5] = CPLAtof(aosRSC.FetchNameValue("Y_STEP"));
418 12 : poDS->bValidGeoTransform = true;
419 : }
420 15 : if (aosRSC.FetchNameValue("PROJECTION") != nullptr)
421 : {
422 : /* ------------------------------------------------------------ */
423 : /* In ROI_PAC, images are georeferenced either with lat/long or */
424 : /* UTM projection. However, using UTM projection is dangerous */
425 : /* because there is no North/South field, or use of latitude */
426 : /* bands! */
427 : /* ------------------------------------------------------------ */
428 24 : OGRSpatialReference oSRS;
429 12 : if (strcmp(aosRSC.FetchNameValue("PROJECTION"), "LL") == 0)
430 : {
431 10 : if (aosRSC.FetchNameValue("DATUM") != nullptr)
432 : {
433 10 : oSRS.SetWellKnownGeogCS(aosRSC.FetchNameValue("DATUM"));
434 : }
435 : else
436 : {
437 0 : oSRS.SetWellKnownGeogCS("WGS84");
438 : }
439 : }
440 2 : else if (STARTS_WITH(aosRSC.FetchNameValue("PROJECTION"), "UTM"))
441 : {
442 2 : const char *pszZone = aosRSC.FetchNameValue("PROJECTION") + 3;
443 2 : oSRS.SetUTM(atoi(pszZone), TRUE); /* FIXME: north/south? */
444 2 : if (aosRSC.FetchNameValue("DATUM") != nullptr)
445 : {
446 2 : oSRS.SetWellKnownGeogCS(aosRSC.FetchNameValue("DATUM"));
447 : }
448 : else
449 : {
450 0 : oSRS.SetWellKnownGeogCS("NAD27");
451 : }
452 : }
453 12 : poDS->m_oSRS = std::move(oSRS);
454 12 : poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
455 : }
456 15 : if (aosRSC.FetchNameValue("Z_OFFSET") != nullptr)
457 : {
458 : const double dfOffset =
459 12 : strtod(aosRSC.FetchNameValue("Z_OFFSET"), nullptr);
460 24 : for (int b = 1; b <= nBands; b++)
461 : {
462 12 : GDALRasterBand *poBand = poDS->GetRasterBand(b);
463 12 : poBand->SetOffset(dfOffset);
464 : }
465 : }
466 15 : if (aosRSC.FetchNameValue("Z_SCALE") != nullptr)
467 : {
468 : const double dfScale =
469 12 : strtod(aosRSC.FetchNameValue("Z_SCALE"), nullptr);
470 24 : for (int b = 1; b <= nBands; b++)
471 : {
472 12 : GDALRasterBand *poBand = poDS->GetRasterBand(b);
473 12 : poBand->SetScale(dfScale);
474 : }
475 : }
476 :
477 : /* -------------------------------------------------------------------- */
478 : /* Set all the other header metadata into the ROI_PAC domain */
479 : /* -------------------------------------------------------------------- */
480 189 : for (int i = 0; i < aosRSC.size(); ++i)
481 : {
482 348 : char **papszTokens = CSLTokenizeString2(
483 174 : aosRSC[i], "=", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
484 348 : if (CSLCount(papszTokens) < 2 || strcmp(papszTokens[0], "WIDTH") == 0 ||
485 159 : strcmp(papszTokens[0], "FILE_LENGTH") == 0 ||
486 144 : strcmp(papszTokens[0], "X_FIRST") == 0 ||
487 132 : strcmp(papszTokens[0], "X_STEP") == 0 ||
488 120 : strcmp(papszTokens[0], "Y_FIRST") == 0 ||
489 108 : strcmp(papszTokens[0], "Y_STEP") == 0 ||
490 96 : strcmp(papszTokens[0], "PROJECTION") == 0 ||
491 84 : strcmp(papszTokens[0], "DATUM") == 0 ||
492 408 : strcmp(papszTokens[0], "Z_OFFSET") == 0 ||
493 60 : strcmp(papszTokens[0], "Z_SCALE") == 0)
494 : {
495 126 : CSLDestroy(papszTokens);
496 126 : continue;
497 : }
498 48 : poDS->SetMetadataItem(papszTokens[0], papszTokens[1], "ROI_PAC");
499 48 : CSLDestroy(papszTokens);
500 : }
501 : /* -------------------------------------------------------------------- */
502 : /* Initialize any PAM information. */
503 : /* -------------------------------------------------------------------- */
504 15 : poDS->SetDescription(poOpenInfo->pszFilename);
505 15 : poDS->TryLoadXML();
506 :
507 : /* -------------------------------------------------------------------- */
508 : /* Check for overviews. */
509 : /* -------------------------------------------------------------------- */
510 15 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
511 :
512 15 : return poDS.release();
513 : }
514 :
515 : /************************************************************************/
516 : /* Identify() */
517 : /************************************************************************/
518 :
519 48718 : int ROIPACDataset::Identify(GDALOpenInfo *poOpenInfo)
520 : {
521 : /* -------------------------------------------------------------------- */
522 : /* Check if: */
523 : /* * 1. The data file extension is known */
524 : /* -------------------------------------------------------------------- */
525 48718 : const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
526 48717 : if (strcmp(pszExtension, "raw") == 0)
527 : {
528 : /* Since gdal do not read natively CInt8, more work is needed
529 : * to read raw files */
530 23 : return false;
531 : }
532 48694 : const bool bExtensionIsValid =
533 48689 : strcmp(pszExtension, "int") == 0 || strcmp(pszExtension, "slc") == 0 ||
534 48671 : strcmp(pszExtension, "amp") == 0 || strcmp(pszExtension, "cor") == 0 ||
535 48669 : strcmp(pszExtension, "hgt") == 0 || strcmp(pszExtension, "unw") == 0 ||
536 48661 : strcmp(pszExtension, "msk") == 0 ||
537 48614 : strcmp(pszExtension, "trans") == 0 ||
538 97383 : strcmp(pszExtension, "dem") == 0 || strcmp(pszExtension, "flg") == 0;
539 48694 : if (!bExtensionIsValid)
540 : {
541 48533 : return false;
542 : }
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* * 2. there is a .rsc file */
546 : /* -------------------------------------------------------------------- */
547 318 : CPLString osRscFilename = getRscFilename(poOpenInfo);
548 157 : if (osRscFilename.empty())
549 : {
550 127 : return false;
551 : }
552 :
553 30 : return true;
554 : }
555 :
556 : /************************************************************************/
557 : /* Create() */
558 : /************************************************************************/
559 :
560 52 : GDALDataset *ROIPACDataset::Create(const char *pszFilename, int nXSize,
561 : int nYSize, int nBandsIn, GDALDataType eType,
562 : char ** /* papszOptions */)
563 : {
564 : /* -------------------------------------------------------------------- */
565 : /* Verify input options. */
566 : /* -------------------------------------------------------------------- */
567 52 : const char *pszExtension = CPLGetExtension(pszFilename);
568 52 : if (strcmp(pszExtension, "int") == 0 || strcmp(pszExtension, "slc") == 0)
569 : {
570 0 : if (nBandsIn != 1 || eType != GDT_CFloat32)
571 : {
572 0 : CPLError(CE_Failure, CPLE_AppDefined,
573 : "Attempt to create ROI_PAC %s dataset with an illegal "
574 : "number of bands (%d) and/or data type (%s).",
575 : pszExtension, nBandsIn, GDALGetDataTypeName(eType));
576 0 : return nullptr;
577 : }
578 : }
579 52 : else if (strcmp(pszExtension, "amp") == 0)
580 : {
581 0 : if (nBandsIn != 2 || eType != GDT_Float32)
582 : {
583 0 : CPLError(CE_Failure, CPLE_AppDefined,
584 : "Attempt to create ROI_PAC %s dataset with an illegal "
585 : "number of bands (%d) and/or data type (%s).",
586 : pszExtension, nBandsIn, GDALGetDataTypeName(eType));
587 0 : return nullptr;
588 : }
589 : }
590 52 : else if (strcmp(pszExtension, "cor") == 0 ||
591 52 : strcmp(pszExtension, "hgt") == 0 ||
592 52 : strcmp(pszExtension, "unw") == 0 ||
593 52 : strcmp(pszExtension, "msk") == 0 ||
594 52 : strcmp(pszExtension, "trans") == 0)
595 : {
596 0 : if (nBandsIn != 2 || eType != GDT_Float32)
597 : {
598 0 : CPLError(CE_Failure, CPLE_AppDefined,
599 : "Attempt to create ROI_PAC %s dataset with an illegal "
600 : "number of bands (%d) and/or data type (%s).",
601 : pszExtension, nBandsIn, GDALGetDataTypeName(eType));
602 0 : return nullptr;
603 : }
604 : }
605 52 : else if (strcmp(pszExtension, "dem") == 0)
606 : {
607 2 : if (nBandsIn != 1 || eType != GDT_Int16)
608 : {
609 0 : CPLError(CE_Failure, CPLE_AppDefined,
610 : "Attempt to create ROI_PAC %s dataset with an illegal "
611 : "number of bands (%d) and/or data type (%s).",
612 : pszExtension, nBandsIn, GDALGetDataTypeName(eType));
613 0 : return nullptr;
614 : }
615 : }
616 50 : else if (strcmp(pszExtension, "flg") == 0)
617 : {
618 1 : if (nBandsIn != 1 || eType != GDT_Byte)
619 : {
620 0 : CPLError(CE_Failure, CPLE_AppDefined,
621 : "Attempt to create ROI_PAC %s dataset with an illegal "
622 : "number of bands (%d) and/or data type (%s).",
623 : pszExtension, nBandsIn, GDALGetDataTypeName(eType));
624 0 : return nullptr;
625 : }
626 : }
627 : else
628 : { /* Eeek */
629 49 : CPLError(CE_Failure, CPLE_AppDefined,
630 : "Attempt to create ROI_PAC dataset with an unknown type (%s)",
631 : pszExtension);
632 49 : return nullptr;
633 : }
634 :
635 : /* -------------------------------------------------------------------- */
636 : /* Try to create the file. */
637 : /* -------------------------------------------------------------------- */
638 3 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
639 3 : if (fp == nullptr)
640 : {
641 0 : CPLError(CE_Failure, CPLE_OpenFailed,
642 : "Attempt to create file `%s' failed.", pszFilename);
643 0 : return nullptr;
644 : }
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* Just write out a couple of bytes to establish the binary */
648 : /* file, and then close it. */
649 : /* -------------------------------------------------------------------- */
650 3 : CPL_IGNORE_RET_VAL(VSIFWriteL("\0\0", 2, 1, fp));
651 3 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
652 :
653 : /* -------------------------------------------------------------------- */
654 : /* Open the RSC file. */
655 : /* -------------------------------------------------------------------- */
656 3 : const char *pszRSCFilename = CPLFormFilename(nullptr, pszFilename, "rsc");
657 3 : fp = VSIFOpenL(pszRSCFilename, "wt");
658 3 : if (fp == nullptr)
659 : {
660 0 : CPLError(CE_Failure, CPLE_OpenFailed,
661 : "Attempt to create file `%s' failed.", pszRSCFilename);
662 0 : return nullptr;
663 : }
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Write out the header. */
667 : /* -------------------------------------------------------------------- */
668 3 : CPL_IGNORE_RET_VAL(VSIFPrintfL(fp, "%-40s %d\n", "WIDTH", nXSize));
669 3 : CPL_IGNORE_RET_VAL(VSIFPrintfL(fp, "%-40s %d\n", "FILE_LENGTH", nYSize));
670 3 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
671 :
672 3 : return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
673 : }
674 :
675 : /************************************************************************/
676 : /* FlushCache() */
677 : /************************************************************************/
678 :
679 15 : CPLErr ROIPACDataset::FlushCache(bool bAtClosing)
680 : {
681 15 : CPLErr eErr = RawDataset::FlushCache(bAtClosing);
682 :
683 15 : GDALRasterBand *band = (GetRasterCount() > 0) ? GetRasterBand(1) : nullptr;
684 :
685 15 : if (eAccess == GA_ReadOnly || band == nullptr)
686 12 : return eErr;
687 :
688 : // If opening an existing file in Update mode (i.e. "r+") we need to make
689 : // sure any existing content is cleared, otherwise the file may contain
690 : // trailing content from the previous write.
691 3 : bool bOK = VSIFTruncateL(fpRsc, 0) == 0;
692 :
693 3 : bOK &= VSIFSeekL(fpRsc, 0, SEEK_SET) == 0;
694 : /* -------------------------------------------------------------------- */
695 : /* Rewrite out the header. */
696 : /* -------------------------------------------------------------------- */
697 : /* -------------------------------------------------------------------- */
698 : /* Raster dimensions. */
699 : /* -------------------------------------------------------------------- */
700 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %d\n", "WIDTH", nRasterXSize) > 0;
701 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %d\n", "FILE_LENGTH", nRasterYSize) > 0;
702 :
703 : /* -------------------------------------------------------------------- */
704 : /* Georeferencing. */
705 : /* -------------------------------------------------------------------- */
706 3 : if (!m_oSRS.IsEmpty())
707 : {
708 3 : int bNorth = FALSE;
709 3 : int iUTMZone = m_oSRS.GetUTMZone(&bNorth);
710 3 : if (iUTMZone != 0)
711 : {
712 1 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s%d\n", "PROJECTION", "UTM",
713 1 : iUTMZone) > 0;
714 : }
715 2 : else if (m_oSRS.IsGeographic())
716 : {
717 2 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "PROJECTION", "LL") > 0;
718 : }
719 : else
720 : {
721 0 : CPLError(CE_Warning, CPLE_AppDefined,
722 : "ROI_PAC format only support Latitude/Longitude and "
723 : "UTM projections, discarding projection.");
724 : }
725 :
726 3 : if (m_oSRS.GetAttrValue("DATUM") != nullptr)
727 : {
728 3 : if (strcmp(m_oSRS.GetAttrValue("DATUM"), "WGS_1984") == 0)
729 : {
730 2 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "DATUM", "WGS84") > 0;
731 : }
732 : else
733 : {
734 1 : CPLError(CE_Warning, CPLE_AppDefined,
735 : "Datum \"%s\" probably not supported in the "
736 : "ROI_PAC format, saving it anyway",
737 : m_oSRS.GetAttrValue("DATUM"));
738 1 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "DATUM",
739 1 : m_oSRS.GetAttrValue("DATUM")) > 0;
740 : }
741 : }
742 3 : if (m_oSRS.GetAttrValue("UNIT") != nullptr)
743 : {
744 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "X_UNIT",
745 3 : m_oSRS.GetAttrValue("UNIT")) > 0;
746 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", "Y_UNIT",
747 3 : m_oSRS.GetAttrValue("UNIT")) > 0;
748 : }
749 : }
750 3 : if (bValidGeoTransform)
751 : {
752 3 : if (adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0)
753 : {
754 0 : CPLError(CE_Warning, CPLE_AppDefined,
755 : "ROI_PAC format do not support geotransform with "
756 : "rotation, discarding info.");
757 : }
758 : else
759 : {
760 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "X_FIRST",
761 3 : adfGeoTransform[0]) > 0;
762 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "X_STEP",
763 3 : adfGeoTransform[1]) > 0;
764 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Y_FIRST",
765 3 : adfGeoTransform[3]) > 0;
766 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Y_STEP",
767 3 : adfGeoTransform[5]) > 0;
768 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Z_OFFSET",
769 3 : band->GetOffset(nullptr)) > 0;
770 3 : bOK &= VSIFPrintfL(fpRsc, "%-40s %.16g\n", "Z_SCALE",
771 6 : band->GetScale(nullptr)) > 0;
772 : }
773 : }
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Metadata stored in the ROI_PAC domain. */
777 : /* -------------------------------------------------------------------- */
778 3 : char **papszROIPACMetadata = GetMetadata("ROI_PAC");
779 3 : for (int i = 0; i < CSLCount(papszROIPACMetadata); i++)
780 : {
781 : /* Get the tokens from the metadata item */
782 : char **papszTokens =
783 0 : CSLTokenizeString2(papszROIPACMetadata[i], "=",
784 : CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
785 0 : if (CSLCount(papszTokens) != 2)
786 : {
787 0 : CPLDebug("ROI_PAC",
788 : "Line of header file could not be split at = "
789 : "into two elements: %s",
790 0 : papszROIPACMetadata[i]);
791 0 : CSLDestroy(papszTokens);
792 0 : continue;
793 : }
794 :
795 : /* Don't write it out if it is one of the bits of metadata that is
796 : * written out elsewhere in this routine */
797 0 : if (strcmp(papszTokens[0], "WIDTH") == 0 ||
798 0 : strcmp(papszTokens[0], "FILE_LENGTH") == 0)
799 : {
800 0 : CSLDestroy(papszTokens);
801 0 : continue;
802 : }
803 0 : bOK &= VSIFPrintfL(fpRsc, "%-40s %s\n", papszTokens[0],
804 0 : papszTokens[1]) > 0;
805 0 : CSLDestroy(papszTokens);
806 : }
807 3 : if (!bOK)
808 0 : eErr = CE_Failure;
809 3 : return eErr;
810 : }
811 :
812 : /************************************************************************/
813 : /* GetGeoTransform() */
814 : /************************************************************************/
815 :
816 8 : CPLErr ROIPACDataset::GetGeoTransform(double *padfTransform)
817 : {
818 8 : memcpy(padfTransform, adfGeoTransform, sizeof(adfGeoTransform));
819 8 : return bValidGeoTransform ? CE_None : CE_Failure;
820 : }
821 :
822 : /************************************************************************/
823 : /* SetGeoTransform() */
824 : /************************************************************************/
825 :
826 3 : CPLErr ROIPACDataset::SetGeoTransform(double *padfTransform)
827 : {
828 3 : memcpy(adfGeoTransform, padfTransform, sizeof(adfGeoTransform));
829 3 : bValidGeoTransform = true;
830 3 : return CE_None;
831 : }
832 :
833 : /************************************************************************/
834 : /* SetSpatialRef() */
835 : /************************************************************************/
836 :
837 3 : CPLErr ROIPACDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
838 :
839 : {
840 3 : if (poSRS)
841 3 : m_oSRS = *poSRS;
842 : else
843 0 : m_oSRS.Clear();
844 3 : return CE_None;
845 : }
846 :
847 : /************************************************************************/
848 : /* GetFileList() */
849 : /************************************************************************/
850 :
851 4 : char **ROIPACDataset::GetFileList()
852 : {
853 : // Main data file, etc.
854 4 : char **papszFileList = RawDataset::GetFileList();
855 :
856 : // RSC file.
857 4 : papszFileList = CSLAddString(papszFileList, pszRscFilename);
858 :
859 4 : return papszFileList;
860 : }
861 :
862 : /************************************************************************/
863 : /* GDALRegister_ROIPAC() */
864 : /************************************************************************/
865 :
866 1511 : void GDALRegister_ROIPAC()
867 : {
868 1511 : if (GDALGetDriverByName("ROI_PAC") != nullptr)
869 295 : return;
870 :
871 1216 : GDALDriver *poDriver = new GDALDriver();
872 :
873 1216 : poDriver->SetDescription("ROI_PAC");
874 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ROI_PAC raster");
875 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
876 1216 : "drivers/raster/roi_pac.html");
877 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
878 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
879 :
880 1216 : poDriver->pfnOpen = ROIPACDataset::Open;
881 1216 : poDriver->pfnIdentify = ROIPACDataset::Identify;
882 1216 : poDriver->pfnCreate = ROIPACDataset::Create;
883 :
884 1216 : GetGDALDriverManager()->RegisterDriver(poDriver);
885 : }
|