Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Generic Binary format driver (.hdr but not ESRI .hdr!)
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "gdal_frmts.h"
16 : #include "ogr_spatialref.h"
17 : #include "rawdataset.h"
18 :
19 : #include <algorithm>
20 : #include <cstdlib>
21 :
22 : #include "usgs_esri_zones.h"
23 :
24 : /************************************************************************/
25 : /* ==================================================================== */
26 : /* GenBinDataset */
27 : /* ==================================================================== */
28 : /************************************************************************/
29 :
30 : class GenBinDataset final : public RawDataset
31 : {
32 : friend class GenBinBitRasterBand;
33 :
34 : VSILFILE *fpImage; // image data file.
35 :
36 : bool bGotTransform;
37 : double adfGeoTransform[6];
38 : OGRSpatialReference m_oSRS{};
39 :
40 : char **papszHDR;
41 :
42 : void ParseCoordinateSystem(char **);
43 :
44 : CPL_DISALLOW_COPY_ASSIGN(GenBinDataset)
45 :
46 : CPLErr Close() override;
47 :
48 : public:
49 : GenBinDataset();
50 : ~GenBinDataset() override;
51 :
52 : CPLErr GetGeoTransform(double *padfTransform) override;
53 :
54 1 : const OGRSpatialReference *GetSpatialRef() const override
55 : {
56 1 : return m_oSRS.IsEmpty() ? RawDataset::GetSpatialRef() : &m_oSRS;
57 : }
58 :
59 : char **GetFileList() override;
60 :
61 : static GDALDataset *Open(GDALOpenInfo *);
62 : };
63 :
64 : /************************************************************************/
65 : /* ==================================================================== */
66 : /* GenBinBitRasterBand */
67 : /* ==================================================================== */
68 : /************************************************************************/
69 :
70 : class GenBinBitRasterBand final : public GDALPamRasterBand
71 : {
72 : int nBits;
73 :
74 : CPL_DISALLOW_COPY_ASSIGN(GenBinBitRasterBand)
75 :
76 : public:
77 : GenBinBitRasterBand(GenBinDataset *poDS, int nBits);
78 :
79 0 : ~GenBinBitRasterBand() override
80 0 : {
81 0 : }
82 :
83 : CPLErr IReadBlock(int, int, void *) override;
84 : };
85 :
86 : /************************************************************************/
87 : /* GenBinBitRasterBand() */
88 : /************************************************************************/
89 :
90 0 : GenBinBitRasterBand::GenBinBitRasterBand(GenBinDataset *poDSIn, int nBitsIn)
91 0 : : nBits(nBitsIn)
92 : {
93 0 : SetMetadataItem("NBITS", CPLString().Printf("%d", nBitsIn),
94 : "IMAGE_STRUCTURE");
95 :
96 0 : poDS = poDSIn;
97 0 : nBand = 1;
98 :
99 0 : eDataType = GDT_Byte;
100 :
101 0 : nBlockXSize = poDSIn->nRasterXSize;
102 0 : nBlockYSize = 1;
103 0 : }
104 :
105 : /************************************************************************/
106 : /* IReadBlock() */
107 : /************************************************************************/
108 :
109 0 : CPLErr GenBinBitRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
110 : void *pImage)
111 :
112 : {
113 0 : GenBinDataset *poGDS = reinterpret_cast<GenBinDataset *>(poDS);
114 :
115 : /* -------------------------------------------------------------------- */
116 : /* Establish desired position. */
117 : /* -------------------------------------------------------------------- */
118 0 : const vsi_l_offset nLineStart =
119 0 : (static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBits) / 8;
120 0 : int iBitOffset = static_cast<int>(
121 0 : (static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBits) % 8);
122 0 : const unsigned int nLineBytes = static_cast<unsigned int>(
123 0 : (static_cast<vsi_l_offset>(nBlockXSize) * (nBlockYOff + 1) * nBits +
124 0 : 7) /
125 0 : 8 -
126 : nLineStart);
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Read data into buffer. */
130 : /* -------------------------------------------------------------------- */
131 0 : GByte *pabyBuffer = static_cast<GByte *>(CPLCalloc(nLineBytes, 1));
132 :
133 0 : if (VSIFSeekL(poGDS->fpImage, nLineStart, SEEK_SET) != 0 ||
134 0 : VSIFReadL(pabyBuffer, 1, nLineBytes, poGDS->fpImage) != nLineBytes)
135 : {
136 0 : CPLError(CE_Failure, CPLE_FileIO,
137 : "Failed to read %u bytes at offset %lu.\n%s", nLineBytes,
138 0 : static_cast<unsigned long>(nLineStart), VSIStrerror(errno));
139 0 : CPLFree(pabyBuffer);
140 0 : return CE_Failure;
141 : }
142 :
143 : /* -------------------------------------------------------------------- */
144 : /* Copy data, promoting to 8bit. */
145 : /* -------------------------------------------------------------------- */
146 0 : GByte *pafImage = reinterpret_cast<GByte *>(pImage);
147 0 : if (nBits == 1)
148 : {
149 0 : for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
150 : {
151 0 : if (pabyBuffer[iBitOffset >> 3] & (0x80 >> (iBitOffset & 7)))
152 0 : pafImage[iX] = 1;
153 : else
154 0 : pafImage[iX] = 0;
155 : }
156 : }
157 0 : else if (nBits == 2)
158 : {
159 0 : for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
160 : {
161 0 : pafImage[iX] =
162 0 : (pabyBuffer[iBitOffset >> 3]) >> (6 - (iBitOffset & 0x7)) & 0x3;
163 : }
164 : }
165 0 : else if (nBits == 4)
166 : {
167 0 : for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
168 : {
169 0 : if (iBitOffset == 0)
170 0 : pafImage[iX] = (pabyBuffer[iBitOffset >> 3]) >> 4;
171 : else
172 0 : pafImage[iX] = (pabyBuffer[iBitOffset >> 3]) & 0xf;
173 : }
174 : }
175 : else
176 : {
177 0 : CPLAssert(false);
178 : }
179 :
180 0 : CPLFree(pabyBuffer);
181 :
182 0 : return CE_None;
183 : }
184 :
185 : /************************************************************************/
186 : /* ==================================================================== */
187 : /* GenBinDataset */
188 : /* ==================================================================== */
189 : /************************************************************************/
190 :
191 : /************************************************************************/
192 : /* GenBinDataset() */
193 : /************************************************************************/
194 :
195 2 : GenBinDataset::GenBinDataset()
196 2 : : fpImage(nullptr), bGotTransform(false), papszHDR(nullptr)
197 : {
198 2 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
199 2 : adfGeoTransform[0] = 0.0;
200 2 : adfGeoTransform[1] = 1.0;
201 2 : adfGeoTransform[2] = 0.0;
202 2 : adfGeoTransform[3] = 0.0;
203 2 : adfGeoTransform[4] = 0.0;
204 2 : adfGeoTransform[5] = 1.0;
205 2 : }
206 :
207 : /************************************************************************/
208 : /* ~GenBinDataset() */
209 : /************************************************************************/
210 :
211 4 : GenBinDataset::~GenBinDataset()
212 :
213 : {
214 2 : GenBinDataset::Close();
215 4 : }
216 :
217 : /************************************************************************/
218 : /* Close() */
219 : /************************************************************************/
220 :
221 4 : CPLErr GenBinDataset::Close()
222 : {
223 4 : CPLErr eErr = CE_None;
224 4 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
225 : {
226 2 : if (GenBinDataset::FlushCache(true) != CE_None)
227 0 : eErr = CE_Failure;
228 :
229 2 : if (fpImage)
230 : {
231 2 : if (VSIFCloseL(fpImage) != 0)
232 : {
233 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
234 0 : eErr = CE_Failure;
235 : }
236 : }
237 :
238 2 : CSLDestroy(papszHDR);
239 :
240 2 : if (GDALPamDataset::Close() != CE_None)
241 0 : eErr = CE_Failure;
242 : }
243 4 : return eErr;
244 : }
245 :
246 : /************************************************************************/
247 : /* GetGeoTransform() */
248 : /************************************************************************/
249 :
250 1 : CPLErr GenBinDataset::GetGeoTransform(double *padfTransform)
251 :
252 : {
253 1 : if (bGotTransform)
254 : {
255 1 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
256 1 : return CE_None;
257 : }
258 :
259 0 : return GDALPamDataset::GetGeoTransform(padfTransform);
260 : }
261 :
262 : /************************************************************************/
263 : /* GetFileList() */
264 : /************************************************************************/
265 :
266 1 : char **GenBinDataset::GetFileList()
267 :
268 : {
269 2 : const CPLString osPath = CPLGetPathSafe(GetDescription());
270 2 : const CPLString osName = CPLGetBasenameSafe(GetDescription());
271 :
272 : // Main data file, etc.
273 1 : char **papszFileList = GDALPamDataset::GetFileList();
274 :
275 : // Header file.
276 1 : const CPLString osFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
277 1 : papszFileList = CSLAddString(papszFileList, osFilename);
278 :
279 2 : return papszFileList;
280 : }
281 :
282 : /************************************************************************/
283 : /* ParseCoordinateSystem() */
284 : /************************************************************************/
285 :
286 2 : void GenBinDataset::ParseCoordinateSystem(char **papszHdr)
287 :
288 : {
289 2 : const char *pszProjName = CSLFetchNameValue(papszHdr, "PROJECTION_NAME");
290 2 : if (pszProjName == nullptr)
291 0 : return;
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Translate zone and parameters into numeric form. */
295 : /* -------------------------------------------------------------------- */
296 2 : int nZone = 0;
297 2 : if (const char *pszProjectionZone =
298 2 : CSLFetchNameValue(papszHdr, "PROJECTION_ZONE"))
299 2 : nZone = atoi(pszProjectionZone);
300 :
301 : #if 0
302 : // TODO(schwehr): Why was this being done but not used?
303 : double adfProjParams[15] = { 0.0 };
304 : if( CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) )
305 : {
306 : char **papszTokens = CSLTokenizeString(
307 : CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) );
308 :
309 : for( int i = 0; i < 15 && papszTokens[i] != NULL; i++ )
310 : adfProjParams[i] = CPLAtofM( papszTokens[i] );
311 :
312 : CSLDestroy( papszTokens );
313 : }
314 : #endif
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Handle projections. */
318 : /* -------------------------------------------------------------------- */
319 2 : const char *pszDatumName = CSLFetchNameValue(papszHdr, "DATUM_NAME");
320 :
321 2 : if (EQUAL(pszProjName, "UTM") && nZone != 0 && nZone > INT_MIN)
322 : {
323 : // Just getting that the negative zone for southern hemisphere is used.
324 0 : m_oSRS.SetUTM(std::abs(nZone), nZone > 0);
325 : }
326 :
327 2 : else if (EQUAL(pszProjName, "State Plane") && nZone != 0 && nZone > INT_MIN)
328 : {
329 2 : const int nPairs = sizeof(anUsgsEsriZones) / (2 * sizeof(int));
330 :
331 218 : for (int i = 0; i < nPairs; i++)
332 : {
333 218 : if (anUsgsEsriZones[i * 2 + 1] == nZone)
334 : {
335 2 : nZone = anUsgsEsriZones[i * 2];
336 2 : break;
337 : }
338 : }
339 :
340 2 : const char *pszUnits = CSLFetchNameValueDef(papszHdr, "MAP_UNITS", "");
341 2 : double dfUnits = 0.0;
342 2 : if (EQUAL(pszUnits, "feet"))
343 2 : dfUnits = CPLAtofM(SRS_UL_US_FOOT_CONV);
344 0 : else if (STARTS_WITH_CI(pszUnits, "MET"))
345 0 : dfUnits = 1.0;
346 : else
347 0 : pszUnits = nullptr;
348 :
349 2 : m_oSRS.SetStatePlane(std::abs(nZone),
350 4 : pszDatumName == nullptr ||
351 2 : !EQUAL(pszDatumName, "NAD27"),
352 : pszUnits, dfUnits);
353 : }
354 :
355 : /* -------------------------------------------------------------------- */
356 : /* Setup the geographic coordinate system. */
357 : /* -------------------------------------------------------------------- */
358 2 : if (m_oSRS.GetAttrNode("GEOGCS") == nullptr)
359 : {
360 : const char *pszSpheroidName =
361 0 : CSLFetchNameValue(papszHdr, "SPHEROID_NAME");
362 : const char *pszSemiMajor =
363 0 : CSLFetchNameValue(papszHdr, "SEMI_MAJOR_AXIS");
364 : const char *pszSemiMinor =
365 0 : CSLFetchNameValue(papszHdr, "SEMI_MINOR_AXIS");
366 0 : if (pszDatumName != nullptr &&
367 0 : m_oSRS.SetWellKnownGeogCS(pszDatumName) == OGRERR_NONE)
368 : {
369 : // good
370 : }
371 0 : else if (pszSpheroidName && pszSemiMajor && pszSemiMinor)
372 : {
373 0 : const double dfSemiMajor = CPLAtofM(pszSemiMajor);
374 0 : const double dfSemiMinor = CPLAtofM(pszSemiMinor);
375 :
376 0 : m_oSRS.SetGeogCS(pszSpheroidName, pszSpheroidName, pszSpheroidName,
377 : dfSemiMajor,
378 0 : (dfSemiMajor == 0.0 || dfSemiMajor == dfSemiMinor)
379 : ? 0.0
380 0 : : 1.0 / (1.0 - dfSemiMinor / dfSemiMajor));
381 : }
382 : else // fallback default.
383 0 : m_oSRS.SetWellKnownGeogCS("WGS84");
384 : }
385 : }
386 :
387 : /************************************************************************/
388 : /* Open() */
389 : /************************************************************************/
390 :
391 28263 : GDALDataset *GenBinDataset::Open(GDALOpenInfo *poOpenInfo)
392 :
393 : {
394 : /* -------------------------------------------------------------------- */
395 : /* We assume the user is pointing to the binary (i.e. .bil) file. */
396 : /* -------------------------------------------------------------------- */
397 28263 : if (poOpenInfo->nHeaderBytes < 2 || poOpenInfo->fpL == nullptr)
398 26865 : return nullptr;
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Now we need to tear apart the filename to form a .HDR */
402 : /* filename. */
403 : /* -------------------------------------------------------------------- */
404 2796 : const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
405 2796 : const CPLString osName = CPLGetBasenameSafe(poOpenInfo->pszFilename);
406 2796 : CPLString osHDRFilename;
407 :
408 1398 : char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
409 1398 : if (papszSiblingFiles)
410 : {
411 : const int iFile =
412 1392 : CSLFindString(papszSiblingFiles,
413 2784 : CPLFormFilenameSafe(nullptr, osName, "hdr").c_str());
414 1392 : if (iFile < 0) // return if there is no corresponding .hdr file
415 1150 : return nullptr;
416 :
417 : osHDRFilename =
418 242 : CPLFormFilenameSafe(osPath, papszSiblingFiles[iFile], nullptr);
419 : }
420 : else
421 : {
422 6 : osHDRFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
423 : }
424 :
425 248 : const bool bSelectedHDR = EQUAL(osHDRFilename, poOpenInfo->pszFilename);
426 :
427 : /* -------------------------------------------------------------------- */
428 : /* Do we have a .hdr file? */
429 : /* -------------------------------------------------------------------- */
430 248 : VSILFILE *fp = VSIFOpenL(osHDRFilename, "r");
431 248 : if (fp == nullptr)
432 : {
433 5 : return nullptr;
434 : }
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Read a chunk to skim for expected keywords. */
438 : /* -------------------------------------------------------------------- */
439 243 : char achHeader[1000] = {'\0'};
440 :
441 : const int nRead =
442 243 : static_cast<int>(VSIFReadL(achHeader, 1, sizeof(achHeader) - 1, fp));
443 243 : achHeader[nRead] = '\0';
444 243 : CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
445 :
446 243 : if (strstr(achHeader, "BANDS:") == nullptr ||
447 2 : strstr(achHeader, "ROWS:") == nullptr ||
448 2 : strstr(achHeader, "COLS:") == nullptr)
449 : {
450 241 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
451 241 : return nullptr;
452 : }
453 :
454 : /* -------------------------------------------------------------------- */
455 : /* Has the user selected the .hdr file to open? */
456 : /* -------------------------------------------------------------------- */
457 2 : if (bSelectedHDR)
458 : {
459 0 : CPLError(
460 : CE_Failure, CPLE_AppDefined,
461 : "The selected file is an Generic Binary header file, but to "
462 : "open Generic Binary datasets, the data file should be selected "
463 : "instead of the .hdr file. Please try again selecting"
464 : "the raw data file corresponding to the header file: %s",
465 : poOpenInfo->pszFilename);
466 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
467 0 : return nullptr;
468 : }
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Read the .hdr file. */
472 : /* -------------------------------------------------------------------- */
473 2 : char **papszHdr = nullptr;
474 2 : const char *pszLine = CPLReadLineL(fp);
475 :
476 46 : while (pszLine != nullptr)
477 : {
478 44 : if (EQUAL(pszLine, "PROJECTION_PARAMETERS:"))
479 : {
480 2 : CPLString osPP = pszLine;
481 :
482 2 : pszLine = CPLReadLineL(fp);
483 32 : while (pszLine != nullptr && (*pszLine == '\t' || *pszLine == ' '))
484 : {
485 30 : osPP += pszLine;
486 30 : pszLine = CPLReadLineL(fp);
487 : }
488 2 : papszHdr = CSLAddString(papszHdr, osPP);
489 : }
490 : else
491 : {
492 42 : char *pszName = nullptr;
493 42 : const char *pszKey = CPLParseNameValue(pszLine, &pszName);
494 42 : if (pszKey && pszName)
495 : {
496 42 : CPLString osValue = pszKey;
497 42 : osValue.Trim();
498 :
499 42 : papszHdr = CSLSetNameValue(papszHdr, pszName, osValue);
500 : }
501 42 : CPLFree(pszName);
502 :
503 42 : pszLine = CPLReadLineL(fp);
504 : }
505 : }
506 :
507 2 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
508 :
509 2 : if (CSLFetchNameValue(papszHdr, "COLS") == nullptr ||
510 4 : CSLFetchNameValue(papszHdr, "ROWS") == nullptr ||
511 2 : CSLFetchNameValue(papszHdr, "BANDS") == nullptr)
512 : {
513 0 : CSLDestroy(papszHdr);
514 0 : return nullptr;
515 : }
516 :
517 : /* -------------------------------------------------------------------- */
518 : /* Create a corresponding GDALDataset. */
519 : /* -------------------------------------------------------------------- */
520 4 : auto poDS = std::make_unique<GenBinDataset>();
521 :
522 : /* -------------------------------------------------------------------- */
523 : /* Capture some information from the file that is of interest. */
524 : /* -------------------------------------------------------------------- */
525 2 : const int nBands = atoi(CSLFetchNameValue(papszHdr, "BANDS"));
526 :
527 2 : poDS->nRasterXSize = atoi(CSLFetchNameValue(papszHdr, "COLS"));
528 2 : poDS->nRasterYSize = atoi(CSLFetchNameValue(papszHdr, "ROWS"));
529 2 : poDS->papszHDR = papszHdr;
530 :
531 4 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
532 2 : !GDALCheckBandCount(nBands, FALSE))
533 : {
534 0 : return nullptr;
535 : }
536 :
537 2 : std::swap(poDS->fpImage, poOpenInfo->fpL);
538 2 : poDS->eAccess = poOpenInfo->eAccess;
539 :
540 : /* -------------------------------------------------------------------- */
541 : /* Figure out the data type. */
542 : /* -------------------------------------------------------------------- */
543 2 : const char *pszDataType = CSLFetchNameValue(papszHdr, "DATATYPE");
544 2 : GDALDataType eDataType = GDT_Byte;
545 2 : int nBits = -1; // Only needed for partial byte types
546 :
547 2 : if (pszDataType == nullptr)
548 : {
549 : // nothing to do
550 : }
551 2 : else if (EQUAL(pszDataType, "U16"))
552 0 : eDataType = GDT_UInt16;
553 2 : else if (EQUAL(pszDataType, "S16"))
554 0 : eDataType = GDT_Int16;
555 2 : else if (EQUAL(pszDataType, "F32"))
556 0 : eDataType = GDT_Float32;
557 2 : else if (EQUAL(pszDataType, "F64"))
558 0 : eDataType = GDT_Float64;
559 2 : else if (EQUAL(pszDataType, "U8"))
560 : {
561 : // nothing to do
562 : }
563 0 : else if (EQUAL(pszDataType, "U1") || EQUAL(pszDataType, "U2") ||
564 0 : EQUAL(pszDataType, "U4"))
565 : {
566 0 : nBits = atoi(pszDataType + 1);
567 0 : if (nBands != 1)
568 : {
569 0 : CPLError(CE_Failure, CPLE_OpenFailed,
570 : "Only one band is supported for U1/U2/U4 data type");
571 0 : return nullptr;
572 : }
573 : }
574 : else
575 : {
576 0 : CPLError(CE_Warning, CPLE_AppDefined,
577 : "DATATYPE=%s not recognised, assuming Byte.", pszDataType);
578 : }
579 :
580 : /* -------------------------------------------------------------------- */
581 : /* Do we need byte swapping? */
582 : /* -------------------------------------------------------------------- */
583 :
584 2 : RawRasterBand::ByteOrder eByteOrder = RawRasterBand::NATIVE_BYTE_ORDER;
585 :
586 2 : const char *pszByteOrder = CSLFetchNameValue(papszHdr, "BYTE_ORDER");
587 2 : if (pszByteOrder)
588 : {
589 2 : eByteOrder = EQUAL(pszByteOrder, "LSB")
590 2 : ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
591 : : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
592 : }
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Work out interleaving info. */
596 : /* -------------------------------------------------------------------- */
597 2 : const int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
598 2 : int nPixelOffset = 0;
599 2 : int nLineOffset = 0;
600 2 : vsi_l_offset nBandOffset = 0;
601 2 : bool bIntOverflow = false;
602 :
603 2 : const char *pszInterleaving = CSLFetchNameValue(papszHdr, "INTERLEAVING");
604 2 : if (pszInterleaving == nullptr)
605 0 : pszInterleaving = "BIL";
606 :
607 2 : if (EQUAL(pszInterleaving, "BSQ") || EQUAL(pszInterleaving, "NA"))
608 : {
609 2 : nPixelOffset = nItemSize;
610 2 : if (nItemSize <= 0 || poDS->nRasterXSize > INT_MAX / nItemSize)
611 0 : bIntOverflow = true;
612 : else
613 : {
614 2 : nLineOffset = nItemSize * poDS->nRasterXSize;
615 2 : nBandOffset =
616 2 : nLineOffset * static_cast<vsi_l_offset>(poDS->nRasterYSize);
617 : }
618 : }
619 0 : else if (EQUAL(pszInterleaving, "BIP"))
620 : {
621 0 : nPixelOffset = nItemSize * nBands;
622 0 : if (nPixelOffset == 0 || poDS->nRasterXSize > INT_MAX / nPixelOffset)
623 0 : bIntOverflow = true;
624 : else
625 : {
626 0 : nLineOffset = nPixelOffset * poDS->nRasterXSize;
627 0 : nBandOffset = nItemSize;
628 : }
629 : }
630 : else
631 : {
632 0 : if (!EQUAL(pszInterleaving, "BIL"))
633 0 : CPLError(CE_Warning, CPLE_AppDefined,
634 : "INTERLEAVING:%s not recognised, assume BIL.",
635 : pszInterleaving);
636 :
637 0 : nPixelOffset = nItemSize;
638 0 : if (nPixelOffset == 0 || nBands == 0 ||
639 0 : poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBands))
640 0 : bIntOverflow = true;
641 : else
642 : {
643 0 : nLineOffset = nPixelOffset * nBands * poDS->nRasterXSize;
644 0 : nBandOffset =
645 0 : nItemSize * static_cast<vsi_l_offset>(poDS->nRasterXSize);
646 : }
647 : }
648 :
649 2 : if (bIntOverflow)
650 : {
651 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
652 0 : return nullptr;
653 : }
654 :
655 4 : if (nBits < 0 &&
656 2 : !RAWDatasetCheckMemoryUsage(poDS->nRasterXSize, poDS->nRasterYSize,
657 : nBands, nItemSize, nPixelOffset,
658 2 : nLineOffset, 0, nBandOffset, poDS->fpImage))
659 : {
660 0 : return nullptr;
661 : }
662 :
663 2 : poDS->SetDescription(poOpenInfo->pszFilename);
664 2 : poDS->PamInitialize();
665 :
666 : /* -------------------------------------------------------------------- */
667 : /* Create band information objects. */
668 : /* -------------------------------------------------------------------- */
669 16 : for (int i = 0; i < nBands; i++)
670 : {
671 14 : if (nBits != -1)
672 : {
673 0 : poDS->SetBand(i + 1, new GenBinBitRasterBand(poDS.get(), nBits));
674 : }
675 : else
676 : {
677 : auto poBand = RawRasterBand::Create(
678 28 : poDS.get(), i + 1, poDS->fpImage, nBandOffset * i, nPixelOffset,
679 14 : nLineOffset, eDataType, eByteOrder, RawRasterBand::OwnFP::NO);
680 14 : if (!poBand)
681 0 : return nullptr;
682 14 : poDS->SetBand(i + 1, std::move(poBand));
683 : }
684 : }
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Get geotransform. */
688 : /* -------------------------------------------------------------------- */
689 4 : if (poDS->nRasterXSize > 1 && poDS->nRasterYSize > 1 &&
690 2 : CSLFetchNameValue(papszHdr, "UL_X_COORDINATE") != nullptr &&
691 2 : CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE") != nullptr &&
692 6 : CSLFetchNameValue(papszHdr, "LR_X_COORDINATE") != nullptr &&
693 2 : CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE") != nullptr)
694 : {
695 : const double dfULX =
696 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "UL_X_COORDINATE"));
697 : const double dfULY =
698 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE"));
699 : const double dfLRX =
700 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "LR_X_COORDINATE"));
701 : const double dfLRY =
702 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE"));
703 :
704 2 : poDS->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize - 1);
705 2 : poDS->adfGeoTransform[2] = 0.0;
706 2 : poDS->adfGeoTransform[4] = 0.0;
707 2 : poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize - 1);
708 :
709 2 : poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
710 2 : poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[5] * 0.5;
711 :
712 2 : poDS->bGotTransform = true;
713 : }
714 :
715 : /* -------------------------------------------------------------------- */
716 : /* Try and parse the coordinate system. */
717 : /* -------------------------------------------------------------------- */
718 2 : poDS->ParseCoordinateSystem(papszHdr);
719 :
720 : /* -------------------------------------------------------------------- */
721 : /* Initialize any PAM information. */
722 : /* -------------------------------------------------------------------- */
723 2 : poDS->TryLoadXML();
724 :
725 : /* -------------------------------------------------------------------- */
726 : /* Check for overviews. */
727 : /* -------------------------------------------------------------------- */
728 2 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
729 :
730 2 : return poDS.release();
731 : }
732 :
733 : /************************************************************************/
734 : /* GDALRegister_GenBin() */
735 : /************************************************************************/
736 :
737 1682 : void GDALRegister_GenBin()
738 :
739 : {
740 1682 : if (GDALGetDriverByName("GenBin") != nullptr)
741 301 : return;
742 :
743 1381 : GDALDriver *poDriver = new GDALDriver();
744 :
745 1381 : poDriver->SetDescription("GenBin");
746 1381 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
747 1381 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
748 1381 : "Generic Binary (.hdr Labelled)");
749 1381 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/genbin.html");
750 1381 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
751 :
752 1381 : poDriver->pfnOpen = GenBinDataset::Open;
753 :
754 1381 : GetGDALDriverManager()->RegisterDriver(poDriver);
755 : }
|