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