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 = CPLGetPath(GetDescription());
270 2 : const CPLString osName = CPLGetBasename(GetDescription());
271 :
272 : // Main data file, etc.
273 1 : char **papszFileList = GDALPamDataset::GetFileList();
274 :
275 : // Header file.
276 1 : const CPLString osFilename = CPLFormCIFilename(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 27999 : GDALDataset *GenBinDataset::Open(GDALOpenInfo *poOpenInfo)
392 :
393 : {
394 : /* -------------------------------------------------------------------- */
395 : /* We assume the user is pointing to the binary (i.e. .bil) file. */
396 : /* -------------------------------------------------------------------- */
397 27999 : if (poOpenInfo->nHeaderBytes < 2 || poOpenInfo->fpL == nullptr)
398 26603 : return nullptr;
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Now we need to tear apart the filename to form a .HDR */
402 : /* filename. */
403 : /* -------------------------------------------------------------------- */
404 2792 : const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
405 2792 : const CPLString osName = CPLGetBasename(poOpenInfo->pszFilename);
406 2792 : CPLString osHDRFilename;
407 :
408 1396 : char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
409 1396 : if (papszSiblingFiles)
410 : {
411 1390 : const int iFile = CSLFindString(
412 : papszSiblingFiles, CPLFormFilename(nullptr, osName, "hdr"));
413 1390 : if (iFile < 0) // return if there is no corresponding .hdr file
414 1148 : return nullptr;
415 :
416 : osHDRFilename =
417 242 : CPLFormFilename(osPath, papszSiblingFiles[iFile], nullptr);
418 : }
419 : else
420 : {
421 6 : osHDRFilename = CPLFormCIFilename(osPath, osName, "hdr");
422 : }
423 :
424 248 : const bool bSelectedHDR = EQUAL(osHDRFilename, poOpenInfo->pszFilename);
425 :
426 : /* -------------------------------------------------------------------- */
427 : /* Do we have a .hdr file? */
428 : /* -------------------------------------------------------------------- */
429 248 : VSILFILE *fp = VSIFOpenL(osHDRFilename, "r");
430 248 : if (fp == nullptr)
431 : {
432 5 : return nullptr;
433 : }
434 :
435 : /* -------------------------------------------------------------------- */
436 : /* Read a chunk to skim for expected keywords. */
437 : /* -------------------------------------------------------------------- */
438 243 : char achHeader[1000] = {'\0'};
439 :
440 : const int nRead =
441 243 : static_cast<int>(VSIFReadL(achHeader, 1, sizeof(achHeader) - 1, fp));
442 243 : achHeader[nRead] = '\0';
443 243 : CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
444 :
445 243 : if (strstr(achHeader, "BANDS:") == nullptr ||
446 2 : strstr(achHeader, "ROWS:") == nullptr ||
447 2 : strstr(achHeader, "COLS:") == nullptr)
448 : {
449 241 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
450 241 : 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->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize - 1);
704 2 : poDS->adfGeoTransform[2] = 0.0;
705 2 : poDS->adfGeoTransform[4] = 0.0;
706 2 : poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize - 1);
707 :
708 2 : poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
709 2 : poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[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 1595 : void GDALRegister_GenBin()
737 :
738 : {
739 1595 : if (GDALGetDriverByName("GenBin") != nullptr)
740 302 : return;
741 :
742 1293 : GDALDriver *poDriver = new GDALDriver();
743 :
744 1293 : poDriver->SetDescription("GenBin");
745 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
746 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
747 1293 : "Generic Binary (.hdr Labelled)");
748 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/genbin.html");
749 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
750 :
751 1293 : poDriver->pfnOpen = GenBinDataset::Open;
752 :
753 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
754 : }
|