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