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 : GDALGeoTransform m_gt{};
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(GDALGeoTransform >) const 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 : }
200 :
201 : /************************************************************************/
202 : /* ~GenBinDataset() */
203 : /************************************************************************/
204 :
205 4 : GenBinDataset::~GenBinDataset()
206 :
207 : {
208 2 : GenBinDataset::Close();
209 4 : }
210 :
211 : /************************************************************************/
212 : /* Close() */
213 : /************************************************************************/
214 :
215 4 : CPLErr GenBinDataset::Close()
216 : {
217 4 : CPLErr eErr = CE_None;
218 4 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
219 : {
220 2 : if (GenBinDataset::FlushCache(true) != CE_None)
221 0 : eErr = CE_Failure;
222 :
223 2 : if (fpImage)
224 : {
225 2 : if (VSIFCloseL(fpImage) != 0)
226 : {
227 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
228 0 : eErr = CE_Failure;
229 : }
230 : }
231 :
232 2 : CSLDestroy(papszHDR);
233 :
234 2 : if (GDALPamDataset::Close() != CE_None)
235 0 : eErr = CE_Failure;
236 : }
237 4 : return eErr;
238 : }
239 :
240 : /************************************************************************/
241 : /* GetGeoTransform() */
242 : /************************************************************************/
243 :
244 1 : CPLErr GenBinDataset::GetGeoTransform(GDALGeoTransform >) const
245 :
246 : {
247 1 : if (bGotTransform)
248 : {
249 1 : gt = m_gt;
250 1 : return CE_None;
251 : }
252 :
253 0 : return GDALPamDataset::GetGeoTransform(gt);
254 : }
255 :
256 : /************************************************************************/
257 : /* GetFileList() */
258 : /************************************************************************/
259 :
260 1 : char **GenBinDataset::GetFileList()
261 :
262 : {
263 2 : const CPLString osPath = CPLGetPathSafe(GetDescription());
264 2 : const CPLString osName = CPLGetBasenameSafe(GetDescription());
265 :
266 : // Main data file, etc.
267 1 : char **papszFileList = GDALPamDataset::GetFileList();
268 :
269 : // Header file.
270 1 : const CPLString osFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
271 1 : papszFileList = CSLAddString(papszFileList, osFilename);
272 :
273 2 : return papszFileList;
274 : }
275 :
276 : /************************************************************************/
277 : /* ParseCoordinateSystem() */
278 : /************************************************************************/
279 :
280 2 : void GenBinDataset::ParseCoordinateSystem(char **papszHdr)
281 :
282 : {
283 2 : const char *pszProjName = CSLFetchNameValue(papszHdr, "PROJECTION_NAME");
284 2 : if (pszProjName == nullptr)
285 0 : return;
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Translate zone and parameters into numeric form. */
289 : /* -------------------------------------------------------------------- */
290 2 : int nZone = 0;
291 2 : if (const char *pszProjectionZone =
292 2 : CSLFetchNameValue(papszHdr, "PROJECTION_ZONE"))
293 2 : nZone = atoi(pszProjectionZone);
294 :
295 : #if 0
296 : // TODO(schwehr): Why was this being done but not used?
297 : double adfProjParams[15] = { 0.0 };
298 : if( CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) )
299 : {
300 : char **papszTokens = CSLTokenizeString(
301 : CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) );
302 :
303 : for( int i = 0; i < 15 && papszTokens[i] != NULL; i++ )
304 : adfProjParams[i] = CPLAtofM( papszTokens[i] );
305 :
306 : CSLDestroy( papszTokens );
307 : }
308 : #endif
309 :
310 : /* -------------------------------------------------------------------- */
311 : /* Handle projections. */
312 : /* -------------------------------------------------------------------- */
313 2 : const char *pszDatumName = CSLFetchNameValue(papszHdr, "DATUM_NAME");
314 :
315 2 : if (EQUAL(pszProjName, "UTM") && nZone != 0 && nZone > INT_MIN)
316 : {
317 : // Just getting that the negative zone for southern hemisphere is used.
318 0 : m_oSRS.SetUTM(std::abs(nZone), nZone > 0);
319 : }
320 :
321 2 : else if (EQUAL(pszProjName, "State Plane") && nZone != 0 && nZone > INT_MIN)
322 : {
323 2 : const int nPairs = sizeof(anUsgsEsriZones) / (2 * sizeof(int));
324 :
325 218 : for (int i = 0; i < nPairs; i++)
326 : {
327 218 : if (anUsgsEsriZones[i * 2 + 1] == nZone)
328 : {
329 2 : nZone = anUsgsEsriZones[i * 2];
330 2 : break;
331 : }
332 : }
333 :
334 2 : const char *pszUnits = CSLFetchNameValueDef(papszHdr, "MAP_UNITS", "");
335 2 : double dfUnits = 0.0;
336 2 : if (EQUAL(pszUnits, "feet"))
337 2 : dfUnits = CPLAtofM(SRS_UL_US_FOOT_CONV);
338 0 : else if (STARTS_WITH_CI(pszUnits, "MET"))
339 0 : dfUnits = 1.0;
340 : else
341 0 : pszUnits = nullptr;
342 :
343 2 : m_oSRS.SetStatePlane(std::abs(nZone),
344 4 : pszDatumName == nullptr ||
345 2 : !EQUAL(pszDatumName, "NAD27"),
346 : pszUnits, dfUnits);
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Setup the geographic coordinate system. */
351 : /* -------------------------------------------------------------------- */
352 2 : if (m_oSRS.GetAttrNode("GEOGCS") == nullptr)
353 : {
354 : const char *pszSpheroidName =
355 0 : CSLFetchNameValue(papszHdr, "SPHEROID_NAME");
356 : const char *pszSemiMajor =
357 0 : CSLFetchNameValue(papszHdr, "SEMI_MAJOR_AXIS");
358 : const char *pszSemiMinor =
359 0 : CSLFetchNameValue(papszHdr, "SEMI_MINOR_AXIS");
360 0 : if (pszDatumName != nullptr &&
361 0 : m_oSRS.SetWellKnownGeogCS(pszDatumName) == OGRERR_NONE)
362 : {
363 : // good
364 : }
365 0 : else if (pszSpheroidName && pszSemiMajor && pszSemiMinor)
366 : {
367 0 : const double dfSemiMajor = CPLAtofM(pszSemiMajor);
368 0 : const double dfSemiMinor = CPLAtofM(pszSemiMinor);
369 :
370 0 : m_oSRS.SetGeogCS(pszSpheroidName, pszSpheroidName, pszSpheroidName,
371 : dfSemiMajor,
372 0 : (dfSemiMajor == 0.0 || dfSemiMajor == dfSemiMinor)
373 : ? 0.0
374 0 : : 1.0 / (1.0 - dfSemiMinor / dfSemiMajor));
375 : }
376 : else // fallback default.
377 0 : m_oSRS.SetWellKnownGeogCS("WGS84");
378 : }
379 : }
380 :
381 : /************************************************************************/
382 : /* Open() */
383 : /************************************************************************/
384 :
385 30663 : GDALDataset *GenBinDataset::Open(GDALOpenInfo *poOpenInfo)
386 :
387 : {
388 : /* -------------------------------------------------------------------- */
389 : /* We assume the user is pointing to the binary (i.e. .bil) file. */
390 : /* -------------------------------------------------------------------- */
391 30663 : if (poOpenInfo->nHeaderBytes < 2 || poOpenInfo->fpL == nullptr)
392 29213 : return nullptr;
393 :
394 : /* -------------------------------------------------------------------- */
395 : /* Now we need to tear apart the filename to form a .HDR */
396 : /* filename. */
397 : /* -------------------------------------------------------------------- */
398 2900 : const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
399 2900 : const CPLString osName = CPLGetBasenameSafe(poOpenInfo->pszFilename);
400 2900 : CPLString osHDRFilename;
401 :
402 1450 : char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
403 1450 : if (papszSiblingFiles)
404 : {
405 : const int iFile =
406 1444 : CSLFindString(papszSiblingFiles,
407 2888 : CPLFormFilenameSafe(nullptr, osName, "hdr").c_str());
408 1444 : if (iFile < 0) // return if there is no corresponding .hdr file
409 1202 : return nullptr;
410 :
411 : osHDRFilename =
412 242 : CPLFormFilenameSafe(osPath, papszSiblingFiles[iFile], nullptr);
413 : }
414 : else
415 : {
416 6 : osHDRFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
417 : }
418 :
419 248 : const bool bSelectedHDR = EQUAL(osHDRFilename, poOpenInfo->pszFilename);
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Do we have a .hdr file? */
423 : /* -------------------------------------------------------------------- */
424 248 : VSILFILE *fp = VSIFOpenL(osHDRFilename, "r");
425 248 : if (fp == nullptr)
426 : {
427 5 : return nullptr;
428 : }
429 :
430 : /* -------------------------------------------------------------------- */
431 : /* Read a chunk to skim for expected keywords. */
432 : /* -------------------------------------------------------------------- */
433 243 : char achHeader[1000] = {'\0'};
434 :
435 : const int nRead =
436 243 : static_cast<int>(VSIFReadL(achHeader, 1, sizeof(achHeader) - 1, fp));
437 243 : achHeader[nRead] = '\0';
438 243 : CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
439 :
440 243 : if (strstr(achHeader, "BANDS:") == nullptr ||
441 2 : strstr(achHeader, "ROWS:") == nullptr ||
442 2 : strstr(achHeader, "COLS:") == nullptr)
443 : {
444 241 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
445 241 : return nullptr;
446 : }
447 :
448 : /* -------------------------------------------------------------------- */
449 : /* Has the user selected the .hdr file to open? */
450 : /* -------------------------------------------------------------------- */
451 2 : if (bSelectedHDR)
452 : {
453 0 : CPLError(
454 : CE_Failure, CPLE_AppDefined,
455 : "The selected file is an Generic Binary header file, but to "
456 : "open Generic Binary datasets, the data file should be selected "
457 : "instead of the .hdr file. Please try again selecting"
458 : "the raw data file corresponding to the header file: %s",
459 : poOpenInfo->pszFilename);
460 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
461 0 : return nullptr;
462 : }
463 :
464 : /* -------------------------------------------------------------------- */
465 : /* Read the .hdr file. */
466 : /* -------------------------------------------------------------------- */
467 2 : char **papszHdr = nullptr;
468 2 : const char *pszLine = CPLReadLineL(fp);
469 :
470 46 : while (pszLine != nullptr)
471 : {
472 44 : if (EQUAL(pszLine, "PROJECTION_PARAMETERS:"))
473 : {
474 2 : CPLString osPP = pszLine;
475 :
476 2 : pszLine = CPLReadLineL(fp);
477 32 : while (pszLine != nullptr && (*pszLine == '\t' || *pszLine == ' '))
478 : {
479 30 : osPP += pszLine;
480 30 : pszLine = CPLReadLineL(fp);
481 : }
482 2 : papszHdr = CSLAddString(papszHdr, osPP);
483 : }
484 : else
485 : {
486 42 : char *pszName = nullptr;
487 42 : const char *pszKey = CPLParseNameValue(pszLine, &pszName);
488 42 : if (pszKey && pszName)
489 : {
490 42 : CPLString osValue = pszKey;
491 42 : osValue.Trim();
492 :
493 42 : papszHdr = CSLSetNameValue(papszHdr, pszName, osValue);
494 : }
495 42 : CPLFree(pszName);
496 :
497 42 : pszLine = CPLReadLineL(fp);
498 : }
499 : }
500 :
501 2 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
502 :
503 2 : if (CSLFetchNameValue(papszHdr, "COLS") == nullptr ||
504 4 : CSLFetchNameValue(papszHdr, "ROWS") == nullptr ||
505 2 : CSLFetchNameValue(papszHdr, "BANDS") == nullptr)
506 : {
507 0 : CSLDestroy(papszHdr);
508 0 : return nullptr;
509 : }
510 :
511 : /* -------------------------------------------------------------------- */
512 : /* Create a corresponding GDALDataset. */
513 : /* -------------------------------------------------------------------- */
514 4 : auto poDS = std::make_unique<GenBinDataset>();
515 :
516 : /* -------------------------------------------------------------------- */
517 : /* Capture some information from the file that is of interest. */
518 : /* -------------------------------------------------------------------- */
519 2 : const int nBands = atoi(CSLFetchNameValue(papszHdr, "BANDS"));
520 :
521 2 : poDS->nRasterXSize = atoi(CSLFetchNameValue(papszHdr, "COLS"));
522 2 : poDS->nRasterYSize = atoi(CSLFetchNameValue(papszHdr, "ROWS"));
523 2 : poDS->papszHDR = papszHdr;
524 :
525 4 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
526 2 : !GDALCheckBandCount(nBands, FALSE))
527 : {
528 0 : return nullptr;
529 : }
530 :
531 2 : std::swap(poDS->fpImage, poOpenInfo->fpL);
532 2 : poDS->eAccess = poOpenInfo->eAccess;
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Figure out the data type. */
536 : /* -------------------------------------------------------------------- */
537 2 : const char *pszDataType = CSLFetchNameValue(papszHdr, "DATATYPE");
538 2 : GDALDataType eDataType = GDT_Byte;
539 2 : int nBits = -1; // Only needed for partial byte types
540 :
541 2 : if (pszDataType == nullptr)
542 : {
543 : // nothing to do
544 : }
545 2 : else if (EQUAL(pszDataType, "U16"))
546 0 : eDataType = GDT_UInt16;
547 2 : else if (EQUAL(pszDataType, "S16"))
548 0 : eDataType = GDT_Int16;
549 2 : else if (EQUAL(pszDataType, "F32"))
550 0 : eDataType = GDT_Float32;
551 2 : else if (EQUAL(pszDataType, "F64"))
552 0 : eDataType = GDT_Float64;
553 2 : else if (EQUAL(pszDataType, "U8"))
554 : {
555 : // nothing to do
556 : }
557 0 : else if (EQUAL(pszDataType, "U1") || EQUAL(pszDataType, "U2") ||
558 0 : EQUAL(pszDataType, "U4"))
559 : {
560 0 : nBits = atoi(pszDataType + 1);
561 0 : if (nBands != 1)
562 : {
563 0 : CPLError(CE_Failure, CPLE_OpenFailed,
564 : "Only one band is supported for U1/U2/U4 data type");
565 0 : return nullptr;
566 : }
567 : }
568 : else
569 : {
570 0 : CPLError(CE_Warning, CPLE_AppDefined,
571 : "DATATYPE=%s not recognised, assuming Byte.", pszDataType);
572 : }
573 :
574 : /* -------------------------------------------------------------------- */
575 : /* Do we need byte swapping? */
576 : /* -------------------------------------------------------------------- */
577 :
578 2 : RawRasterBand::ByteOrder eByteOrder = RawRasterBand::NATIVE_BYTE_ORDER;
579 :
580 2 : const char *pszByteOrder = CSLFetchNameValue(papszHdr, "BYTE_ORDER");
581 2 : if (pszByteOrder)
582 : {
583 2 : eByteOrder = EQUAL(pszByteOrder, "LSB")
584 2 : ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
585 : : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
586 : }
587 :
588 : /* -------------------------------------------------------------------- */
589 : /* Work out interleaving info. */
590 : /* -------------------------------------------------------------------- */
591 2 : const int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
592 2 : int nPixelOffset = 0;
593 2 : int nLineOffset = 0;
594 2 : vsi_l_offset nBandOffset = 0;
595 2 : bool bIntOverflow = false;
596 :
597 2 : const char *pszInterleaving = CSLFetchNameValue(papszHdr, "INTERLEAVING");
598 2 : if (pszInterleaving == nullptr)
599 0 : pszInterleaving = "BIL";
600 :
601 2 : if (EQUAL(pszInterleaving, "BSQ") || EQUAL(pszInterleaving, "NA"))
602 : {
603 2 : nPixelOffset = nItemSize;
604 2 : if (nItemSize <= 0 || poDS->nRasterXSize > INT_MAX / nItemSize)
605 0 : bIntOverflow = true;
606 : else
607 : {
608 2 : nLineOffset = nItemSize * poDS->nRasterXSize;
609 2 : nBandOffset =
610 2 : nLineOffset * static_cast<vsi_l_offset>(poDS->nRasterYSize);
611 : }
612 : }
613 0 : else if (EQUAL(pszInterleaving, "BIP"))
614 : {
615 0 : nPixelOffset = nItemSize * nBands;
616 0 : if (nPixelOffset == 0 || poDS->nRasterXSize > INT_MAX / nPixelOffset)
617 0 : bIntOverflow = true;
618 : else
619 : {
620 0 : nLineOffset = nPixelOffset * poDS->nRasterXSize;
621 0 : nBandOffset = nItemSize;
622 : }
623 : }
624 : else
625 : {
626 0 : if (!EQUAL(pszInterleaving, "BIL"))
627 0 : CPLError(CE_Warning, CPLE_AppDefined,
628 : "INTERLEAVING:%s not recognised, assume BIL.",
629 : pszInterleaving);
630 :
631 0 : nPixelOffset = nItemSize;
632 0 : if (nPixelOffset == 0 || nBands == 0 ||
633 0 : poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBands))
634 0 : bIntOverflow = true;
635 : else
636 : {
637 0 : nLineOffset = nPixelOffset * nBands * poDS->nRasterXSize;
638 0 : nBandOffset =
639 0 : nItemSize * static_cast<vsi_l_offset>(poDS->nRasterXSize);
640 : }
641 : }
642 :
643 2 : if (bIntOverflow)
644 : {
645 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
646 0 : return nullptr;
647 : }
648 :
649 4 : if (nBits < 0 &&
650 2 : !RAWDatasetCheckMemoryUsage(poDS->nRasterXSize, poDS->nRasterYSize,
651 : nBands, nItemSize, nPixelOffset,
652 2 : nLineOffset, 0, nBandOffset, poDS->fpImage))
653 : {
654 0 : return nullptr;
655 : }
656 :
657 2 : poDS->SetDescription(poOpenInfo->pszFilename);
658 2 : poDS->PamInitialize();
659 :
660 : /* -------------------------------------------------------------------- */
661 : /* Create band information objects. */
662 : /* -------------------------------------------------------------------- */
663 16 : for (int i = 0; i < nBands; i++)
664 : {
665 14 : if (nBits != -1)
666 : {
667 0 : poDS->SetBand(i + 1, new GenBinBitRasterBand(poDS.get(), nBits));
668 : }
669 : else
670 : {
671 : auto poBand = RawRasterBand::Create(
672 28 : poDS.get(), i + 1, poDS->fpImage, nBandOffset * i, nPixelOffset,
673 14 : nLineOffset, eDataType, eByteOrder, RawRasterBand::OwnFP::NO);
674 14 : if (!poBand)
675 0 : return nullptr;
676 14 : poDS->SetBand(i + 1, std::move(poBand));
677 : }
678 : }
679 :
680 : /* -------------------------------------------------------------------- */
681 : /* Get geotransform. */
682 : /* -------------------------------------------------------------------- */
683 4 : if (poDS->nRasterXSize > 1 && poDS->nRasterYSize > 1 &&
684 2 : CSLFetchNameValue(papszHdr, "UL_X_COORDINATE") != nullptr &&
685 2 : CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE") != nullptr &&
686 6 : CSLFetchNameValue(papszHdr, "LR_X_COORDINATE") != nullptr &&
687 2 : CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE") != nullptr)
688 : {
689 : const double dfULX =
690 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "UL_X_COORDINATE"));
691 : const double dfULY =
692 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE"));
693 : const double dfLRX =
694 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "LR_X_COORDINATE"));
695 : const double dfLRY =
696 2 : CPLAtofM(CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE"));
697 :
698 2 : poDS->m_gt[1] = (dfLRX - dfULX) / (poDS->nRasterXSize - 1);
699 2 : poDS->m_gt[2] = 0.0;
700 2 : poDS->m_gt[4] = 0.0;
701 2 : poDS->m_gt[5] = (dfLRY - dfULY) / (poDS->nRasterYSize - 1);
702 :
703 2 : poDS->m_gt[0] = dfULX - poDS->m_gt[1] * 0.5;
704 2 : poDS->m_gt[3] = dfULY - poDS->m_gt[5] * 0.5;
705 :
706 2 : poDS->bGotTransform = true;
707 : }
708 :
709 : /* -------------------------------------------------------------------- */
710 : /* Try and parse the coordinate system. */
711 : /* -------------------------------------------------------------------- */
712 2 : poDS->ParseCoordinateSystem(papszHdr);
713 :
714 : /* -------------------------------------------------------------------- */
715 : /* Initialize any PAM information. */
716 : /* -------------------------------------------------------------------- */
717 2 : poDS->TryLoadXML();
718 :
719 : /* -------------------------------------------------------------------- */
720 : /* Check for overviews. */
721 : /* -------------------------------------------------------------------- */
722 2 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
723 :
724 2 : return poDS.release();
725 : }
726 :
727 : /************************************************************************/
728 : /* GDALRegister_GenBin() */
729 : /************************************************************************/
730 :
731 1911 : void GDALRegister_GenBin()
732 :
733 : {
734 1911 : if (GDALGetDriverByName("GenBin") != nullptr)
735 282 : return;
736 :
737 1629 : GDALDriver *poDriver = new GDALDriver();
738 :
739 1629 : poDriver->SetDescription("GenBin");
740 1629 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
741 1629 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
742 1629 : "Generic Binary (.hdr Labelled)");
743 1629 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/genbin.html");
744 1629 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
745 :
746 1629 : poDriver->pfnOpen = GenBinDataset::Open;
747 :
748 1629 : GetGDALDriverManager()->RegisterDriver(poDriver);
749 : }
|