1 : /******************************************************************************
2 : * $Id: ehdrdataset.cpp 12350 2007-10-08 17:41:32Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: Generic Binary format driver (.hdr but not ESRI .hdr!)
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.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 "rawdataset.h"
31 : #include "ogr_spatialref.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ehdrdataset.cpp 12350 2007-10-08 17:41:32Z rouault $");
35 :
36 : CPL_C_START
37 : void GDALRegister_GenBin(void);
38 : CPL_C_END
39 :
40 : /* ==================================================================== */
41 : /* Table relating USGS and ESRI state plane zones. */
42 : /* ==================================================================== */
43 : static const int anUsgsEsriZones[] =
44 : {
45 : 101, 3101,
46 : 102, 3126,
47 : 201, 3151,
48 : 202, 3176,
49 : 203, 3201,
50 : 301, 3226,
51 : 302, 3251,
52 : 401, 3276,
53 : 402, 3301,
54 : 403, 3326,
55 : 404, 3351,
56 : 405, 3376,
57 : 406, 3401,
58 : 407, 3426,
59 : 501, 3451,
60 : 502, 3476,
61 : 503, 3501,
62 : 600, 3526,
63 : 700, 3551,
64 : 901, 3601,
65 : 902, 3626,
66 : 903, 3576,
67 : 1001, 3651,
68 : 1002, 3676,
69 : 1101, 3701,
70 : 1102, 3726,
71 : 1103, 3751,
72 : 1201, 3776,
73 : 1202, 3801,
74 : 1301, 3826,
75 : 1302, 3851,
76 : 1401, 3876,
77 : 1402, 3901,
78 : 1501, 3926,
79 : 1502, 3951,
80 : 1601, 3976,
81 : 1602, 4001,
82 : 1701, 4026,
83 : 1702, 4051,
84 : 1703, 6426,
85 : 1801, 4076,
86 : 1802, 4101,
87 : 1900, 4126,
88 : 2001, 4151,
89 : 2002, 4176,
90 : 2101, 4201,
91 : 2102, 4226,
92 : 2103, 4251,
93 : 2111, 6351,
94 : 2112, 6376,
95 : 2113, 6401,
96 : 2201, 4276,
97 : 2202, 4301,
98 : 2203, 4326,
99 : 2301, 4351,
100 : 2302, 4376,
101 : 2401, 4401,
102 : 2402, 4426,
103 : 2403, 4451,
104 : 2500, 0,
105 : 2501, 4476,
106 : 2502, 4501,
107 : 2503, 4526,
108 : 2600, 0,
109 : 2601, 4551,
110 : 2602, 4576,
111 : 2701, 4601,
112 : 2702, 4626,
113 : 2703, 4651,
114 : 2800, 4676,
115 : 2900, 4701,
116 : 3001, 4726,
117 : 3002, 4751,
118 : 3003, 4776,
119 : 3101, 4801,
120 : 3102, 4826,
121 : 3103, 4851,
122 : 3104, 4876,
123 : 3200, 4901,
124 : 3301, 4926,
125 : 3302, 4951,
126 : 3401, 4976,
127 : 3402, 5001,
128 : 3501, 5026,
129 : 3502, 5051,
130 : 3601, 5076,
131 : 3602, 5101,
132 : 3701, 5126,
133 : 3702, 5151,
134 : 3800, 5176,
135 : 3900, 0,
136 : 3901, 5201,
137 : 3902, 5226,
138 : 4001, 5251,
139 : 4002, 5276,
140 : 4100, 5301,
141 : 4201, 5326,
142 : 4202, 5351,
143 : 4203, 5376,
144 : 4204, 5401,
145 : 4205, 5426,
146 : 4301, 5451,
147 : 4302, 5476,
148 : 4303, 5501,
149 : 4400, 5526,
150 : 4501, 5551,
151 : 4502, 5576,
152 : 4601, 5601,
153 : 4602, 5626,
154 : 4701, 5651,
155 : 4702, 5676,
156 : 4801, 5701,
157 : 4802, 5726,
158 : 4803, 5751,
159 : 4901, 5776,
160 : 4902, 5801,
161 : 4903, 5826,
162 : 4904, 5851,
163 : 5001, 6101,
164 : 5002, 6126,
165 : 5003, 6151,
166 : 5004, 6176,
167 : 5005, 6201,
168 : 5006, 6226,
169 : 5007, 6251,
170 : 5008, 6276,
171 : 5009, 6301,
172 : 5010, 6326,
173 : 5101, 5876,
174 : 5102, 5901,
175 : 5103, 5926,
176 : 5104, 5951,
177 : 5105, 5976,
178 : 5201, 6001,
179 : 5200, 6026,
180 : 5200, 6076,
181 : 5201, 6051,
182 : 5202, 6051,
183 : 5300, 0,
184 : 5400, 0
185 : };
186 :
187 : /************************************************************************/
188 : /* ==================================================================== */
189 : /* GenBinDataset */
190 : /* ==================================================================== */
191 : /************************************************************************/
192 :
193 : class GenBinDataset : public RawDataset
194 : {
195 : friend class GenBinBitRasterBand;
196 :
197 : VSILFILE *fpImage; // image data file.
198 :
199 : int bGotTransform;
200 : double adfGeoTransform[6];
201 : char *pszProjection;
202 :
203 : char **papszHDR;
204 :
205 : void ParseCoordinateSystem( char ** );
206 :
207 : public:
208 : GenBinDataset();
209 : ~GenBinDataset();
210 :
211 : virtual CPLErr GetGeoTransform( double * padfTransform );
212 : virtual const char *GetProjectionRef(void);
213 :
214 : virtual char **GetFileList();
215 :
216 : static GDALDataset *Open( GDALOpenInfo * );
217 : };
218 :
219 : /************************************************************************/
220 : /* ==================================================================== */
221 : /* GenBinBitRasterBand */
222 : /* ==================================================================== */
223 : /************************************************************************/
224 :
225 : class GenBinBitRasterBand : public GDALPamRasterBand
226 0 : {
227 : int nBits;
228 :
229 : public:
230 : GenBinBitRasterBand( GenBinDataset *poDS, int nBits );
231 :
232 : virtual CPLErr IReadBlock( int, int, void * );
233 : };
234 :
235 : /************************************************************************/
236 : /* GenBinBitRasterBand() */
237 : /************************************************************************/
238 :
239 0 : GenBinBitRasterBand::GenBinBitRasterBand( GenBinDataset *poDS, int nBitsIn )
240 : {
241 : SetMetadataItem( "NBITS",
242 : CPLString().Printf("%d",nBitsIn),
243 0 : "IMAGE_STRUCTURE" );
244 :
245 0 : this->poDS = poDS;
246 0 : nBits = nBitsIn;
247 0 : nBand = 1;
248 :
249 0 : eDataType = GDT_Byte;
250 :
251 0 : nBlockXSize = poDS->nRasterXSize;
252 0 : nBlockYSize = 1;
253 0 : }
254 :
255 : /************************************************************************/
256 : /* IReadBlock() */
257 : /************************************************************************/
258 :
259 0 : CPLErr GenBinBitRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
260 : void * pImage )
261 :
262 : {
263 0 : GenBinDataset *poGDS = (GenBinDataset *) poDS;
264 : vsi_l_offset nLineStart;
265 : unsigned int nLineBytes;
266 : int iBitOffset;
267 : GByte *pabyBuffer;
268 :
269 : /* -------------------------------------------------------------------- */
270 : /* Establish desired position. */
271 : /* -------------------------------------------------------------------- */
272 0 : nLineStart = (((vsi_l_offset)nBlockXSize) * nBlockYOff * nBits) / 8;
273 0 : iBitOffset = (int)((((vsi_l_offset)nBlockXSize) * nBlockYOff * nBits) % 8);
274 0 : nLineBytes = (int) ((((vsi_l_offset)nBlockXSize) * (nBlockYOff+1) * nBits + 7) / 8 - nLineStart);
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Read data into buffer. */
278 : /* -------------------------------------------------------------------- */
279 0 : pabyBuffer = (GByte *) CPLCalloc(nLineBytes,1);
280 :
281 0 : if( VSIFSeekL( poGDS->fpImage, nLineStart, SEEK_SET ) != 0
282 : || VSIFReadL( pabyBuffer, 1, nLineBytes, poGDS->fpImage) != nLineBytes )
283 : {
284 : CPLError( CE_Failure, CPLE_FileIO,
285 : "Failed to read %u bytes at offset %lu.\n%s",
286 : nLineBytes, (unsigned long)nLineStart,
287 0 : VSIStrerror( errno ) );
288 0 : return CE_Failure;
289 : }
290 :
291 : /* -------------------------------------------------------------------- */
292 : /* Copy data, promoting to 8bit. */
293 : /* -------------------------------------------------------------------- */
294 : int iX;
295 :
296 0 : if( nBits == 1 )
297 : {
298 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
299 : {
300 0 : if( pabyBuffer[iBitOffset>>3] & (0x80 >>(iBitOffset & 7)) )
301 0 : ((GByte *) pImage)[iX] = 1;
302 : else
303 0 : ((GByte *) pImage)[iX] = 0;
304 : }
305 : }
306 0 : else if( nBits == 2 )
307 : {
308 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
309 : {
310 0 : ((GByte *) pImage)[iX] =
311 0 : ((pabyBuffer[iBitOffset>>3]) >> (6-(iBitOffset&0x7)) & 0x3);
312 : }
313 : }
314 0 : else if( nBits == 4 )
315 : {
316 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
317 : {
318 0 : if( iBitOffset == 0 )
319 0 : ((GByte *) pImage)[iX] = (pabyBuffer[iBitOffset>>3]) >> 4;
320 : else
321 0 : ((GByte *) pImage)[iX] = (pabyBuffer[iBitOffset>>3]) & 0xf;
322 : }
323 : }
324 : else
325 0 : CPLAssert( FALSE );
326 :
327 0 : CPLFree( pabyBuffer );
328 :
329 0 : return CE_None;
330 : }
331 :
332 : /************************************************************************/
333 : /* ==================================================================== */
334 : /* GenBinDataset */
335 : /* ==================================================================== */
336 : /************************************************************************/
337 :
338 : /************************************************************************/
339 : /* GenBinDataset() */
340 : /************************************************************************/
341 :
342 1 : GenBinDataset::GenBinDataset()
343 : {
344 1 : fpImage = NULL;
345 1 : pszProjection = CPLStrdup("");
346 1 : bGotTransform = FALSE;
347 1 : adfGeoTransform[0] = 0.0;
348 1 : adfGeoTransform[1] = 1.0;
349 1 : adfGeoTransform[2] = 0.0;
350 1 : adfGeoTransform[3] = 0.0;
351 1 : adfGeoTransform[4] = 0.0;
352 1 : adfGeoTransform[5] = 1.0;
353 1 : papszHDR = NULL;
354 1 : }
355 :
356 : /************************************************************************/
357 : /* ~GenBinDataset() */
358 : /************************************************************************/
359 :
360 1 : GenBinDataset::~GenBinDataset()
361 :
362 : {
363 1 : FlushCache();
364 :
365 1 : if( fpImage != NULL )
366 1 : VSIFCloseL( fpImage );
367 :
368 1 : CPLFree( pszProjection );
369 1 : CSLDestroy( papszHDR );
370 1 : }
371 :
372 : /************************************************************************/
373 : /* GetProjectionRef() */
374 : /************************************************************************/
375 :
376 1 : const char *GenBinDataset::GetProjectionRef()
377 :
378 : {
379 1 : if (pszProjection && strlen(pszProjection) > 0)
380 1 : return pszProjection;
381 :
382 0 : return GDALPamDataset::GetProjectionRef();
383 : }
384 :
385 : /************************************************************************/
386 : /* GetGeoTransform() */
387 : /************************************************************************/
388 :
389 1 : CPLErr GenBinDataset::GetGeoTransform( double * padfTransform )
390 :
391 : {
392 1 : if( bGotTransform )
393 : {
394 1 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
395 1 : return CE_None;
396 : }
397 : else
398 : {
399 0 : return GDALPamDataset::GetGeoTransform( padfTransform );
400 : }
401 : }
402 :
403 : /************************************************************************/
404 : /* GetFileList() */
405 : /************************************************************************/
406 :
407 0 : char **GenBinDataset::GetFileList()
408 :
409 : {
410 0 : CPLString osPath = CPLGetPath( GetDescription() );
411 0 : CPLString osName = CPLGetBasename( GetDescription() );
412 0 : char **papszFileList = NULL;
413 :
414 : // Main data file, etc.
415 0 : papszFileList = GDALPamDataset::GetFileList();
416 :
417 : // Header file.
418 0 : CPLString osFilename = CPLFormCIFilename( osPath, osName, "hdr" );
419 0 : papszFileList = CSLAddString( papszFileList, osFilename );
420 :
421 0 : return papszFileList;
422 : }
423 :
424 : /************************************************************************/
425 : /* ParseCoordinateSystem() */
426 : /************************************************************************/
427 :
428 1 : void GenBinDataset::ParseCoordinateSystem( char **papszHdr )
429 :
430 : {
431 1 : const char *pszProjName = CSLFetchNameValue( papszHdr, "PROJECTION_NAME" );
432 1 : OGRSpatialReference oSRS;
433 :
434 1 : if( pszProjName == NULL )
435 : return;
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* Translate zone and parameters into numeric form. */
439 : /* -------------------------------------------------------------------- */
440 1 : int nZone = 0;
441 : double adfProjParms[15];
442 1 : const char *pszUnits = CSLFetchNameValue( papszHdr, "MAP_UNITS" );
443 1 : const char *pszDatumName = CSLFetchNameValue( papszHdr, "DATUM_NAME" );
444 :
445 1 : if( CSLFetchNameValue( papszHdr, "PROJECTION_ZONE" ) )
446 1 : nZone = atoi(CSLFetchNameValue( papszHdr, "PROJECTION_ZONE" ));
447 :
448 1 : memset( adfProjParms, 0, sizeof(adfProjParms) );
449 1 : if( CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) )
450 : {
451 : int i;
452 : char **papszTokens = CSLTokenizeString(
453 1 : CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) );
454 :
455 15 : for( i = 0; i < 15 && papszTokens[i] != NULL; i++ )
456 14 : adfProjParms[i] = CPLAtofM( papszTokens[i] );
457 :
458 1 : CSLDestroy( papszTokens );
459 : }
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Handle projections. */
463 : /* -------------------------------------------------------------------- */
464 1 : if( EQUAL(pszProjName,"UTM") && nZone != 0 )
465 : {
466 : // honestly, I'm just getting that the negative zone for
467 : // southern hemisphere is used.
468 0 : oSRS.SetUTM( ABS(nZone), nZone > 0 );
469 : }
470 :
471 1 : else if( EQUAL(pszProjName,"State Plane") && nZone != 0 )
472 : {
473 1 : int nPairs = sizeof(anUsgsEsriZones) / (2*sizeof(int));
474 : int i;
475 1 : double dfUnits = 0.0;
476 :
477 109 : for( i = 0; i < nPairs; i++ )
478 : {
479 109 : if( anUsgsEsriZones[i*2+1] == nZone )
480 : {
481 1 : nZone = anUsgsEsriZones[i*2];
482 1 : break;
483 : }
484 :
485 : }
486 :
487 1 : if( EQUAL(pszUnits,"feet") )
488 1 : dfUnits = CPLAtofM(SRS_UL_US_FOOT_CONV);
489 0 : else if( EQUALN(pszUnits,"MET",3) )
490 0 : dfUnits = 1.0;
491 : else
492 0 : pszUnits = NULL;
493 :
494 : oSRS.SetStatePlane( ABS(nZone),
495 : pszDatumName==NULL || !EQUAL(pszDatumName,"NAD27"),
496 1 : pszUnits, dfUnits );
497 : }
498 :
499 : /* -------------------------------------------------------------------- */
500 : /* Setup the geographic coordinate system. */
501 : /* -------------------------------------------------------------------- */
502 1 : if( oSRS.GetAttrNode( "GEOGCS" ) == NULL )
503 : {
504 0 : if( pszDatumName != NULL
505 : && oSRS.SetWellKnownGeogCS( pszDatumName ) == OGRERR_NONE )
506 : {
507 : // good
508 : }
509 0 : else if( CSLFetchNameValue( papszHdr, "SPHEROID_NAME" )
510 : && CSLFetchNameValue( papszHdr, "SEMI_MAJOR_AXIS" )
511 : && CSLFetchNameValue( papszHdr, "SEMI_MINOR_AXIS" ) )
512 : {
513 0 : double dfSemiMajor = CPLAtofM(CSLFetchNameValue( papszHdr, "SEMI_MAJOR_AXIS"));
514 0 : double dfSemiMinor = CPLAtofM(CSLFetchNameValue( papszHdr, "SEMI_MINOR_AXIS"));
515 :
516 : oSRS.SetGeogCS( CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
517 : CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
518 : CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
519 : dfSemiMajor,
520 0 : 1.0 / (1.0 - dfSemiMinor/dfSemiMajor) );
521 : }
522 : else // fallback default.
523 0 : oSRS.SetWellKnownGeogCS( "WGS84" );
524 : }
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Convert to WKT. */
528 : /* -------------------------------------------------------------------- */
529 1 : CPLFree( pszProjection );
530 1 : pszProjection = NULL;
531 :
532 1 : oSRS.exportToWkt( &pszProjection );
533 : }
534 :
535 : /************************************************************************/
536 : /* Open() */
537 : /************************************************************************/
538 :
539 12149 : GDALDataset *GenBinDataset::Open( GDALOpenInfo * poOpenInfo )
540 :
541 : {
542 : int i, bSelectedHDR;
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* We assume the user is pointing to the binary (ie. .bil) file. */
546 : /* -------------------------------------------------------------------- */
547 12149 : if( poOpenInfo->nHeaderBytes < 2 )
548 11319 : return NULL;
549 :
550 : /* -------------------------------------------------------------------- */
551 : /* Now we need to tear apart tfhe filename to form a .HDR */
552 : /* filename. */
553 : /* -------------------------------------------------------------------- */
554 830 : CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
555 830 : CPLString osName = CPLGetBasename( poOpenInfo->pszFilename );
556 830 : CPLString osHDRFilename;
557 :
558 830 : if( poOpenInfo->papszSiblingFiles )
559 : {
560 : int iFile = CSLFindString(poOpenInfo->papszSiblingFiles,
561 826 : CPLFormFilename( NULL, osName, "hdr" ) );
562 826 : if( iFile < 0 ) // return if there is no corresponding .hdr file
563 795 : return NULL;
564 :
565 : osHDRFilename =
566 31 : CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile],
567 62 : NULL );
568 : }
569 : else
570 : {
571 4 : osHDRFilename = CPLFormCIFilename( osPath, osName, "hdr" );
572 : }
573 :
574 35 : bSelectedHDR = EQUAL( osHDRFilename, poOpenInfo->pszFilename );
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Do we have a .hdr file? */
578 : /* -------------------------------------------------------------------- */
579 : VSILFILE *fp;
580 :
581 35 : fp = VSIFOpenL( osHDRFilename, "r" );
582 :
583 35 : if( fp == NULL )
584 : {
585 4 : return NULL;
586 : }
587 :
588 : /* -------------------------------------------------------------------- */
589 : /* Read a chunk to skim for expected keywords. */
590 : /* -------------------------------------------------------------------- */
591 : char achHeader[1000];
592 :
593 31 : int nRead = VSIFReadL( achHeader, 1, sizeof(achHeader) - 1, fp );
594 31 : achHeader[nRead] = '\0';
595 31 : VSIFSeekL( fp, 0, SEEK_SET );
596 :
597 31 : if( strstr( achHeader, "BANDS:" ) == NULL
598 : || strstr( achHeader, "ROWS:" ) == NULL
599 : || strstr( achHeader, "COLS:" ) == NULL )
600 : {
601 30 : VSIFCloseL( fp );
602 30 : return NULL;
603 : }
604 :
605 : /* -------------------------------------------------------------------- */
606 : /* Has the user selected the .hdr file to open? */
607 : /* -------------------------------------------------------------------- */
608 1 : if( bSelectedHDR )
609 : {
610 : CPLError( CE_Failure, CPLE_AppDefined,
611 : "The selected file is an Generic Binary header file, but to\n"
612 : "open Generic Binary datasets, the data file should be selected\n"
613 : "instead of the .hdr file. Please try again selecting\n"
614 : "the raw data file corresponding to the header file: %s\n",
615 0 : poOpenInfo->pszFilename );
616 0 : VSIFCloseL( fp );
617 0 : return NULL;
618 : }
619 :
620 : /* -------------------------------------------------------------------- */
621 : /* Read the .hdr file. */
622 : /* -------------------------------------------------------------------- */
623 1 : char **papszHdr = NULL;
624 1 : const char *pszLine = CPLReadLineL( fp );
625 :
626 24 : while( pszLine != NULL )
627 : {
628 22 : if( EQUAL(pszLine,"PROJECTION_PARAMETERS:") )
629 : {
630 1 : CPLString osPP = pszLine;
631 :
632 1 : pszLine = CPLReadLineL(fp);
633 17 : while( pszLine != NULL
634 : && (*pszLine == '\t' || *pszLine == ' ') )
635 : {
636 15 : osPP += pszLine;
637 15 : pszLine = CPLReadLineL(fp);
638 : }
639 1 : papszHdr = CSLAddString( papszHdr, osPP );
640 : }
641 : else
642 : {
643 : char *pszName;
644 21 : CPLString osValue;
645 :
646 21 : osValue = CPLParseNameValue( pszLine, &pszName );
647 21 : osValue.Trim();
648 :
649 21 : papszHdr = CSLSetNameValue( papszHdr, pszName, osValue );
650 21 : CPLFree( pszName );
651 :
652 21 : pszLine = CPLReadLineL( fp );
653 : }
654 : }
655 :
656 1 : VSIFCloseL( fp );
657 :
658 1 : if( CSLFetchNameValue( papszHdr, "COLS" ) == NULL
659 : || CSLFetchNameValue( papszHdr, "ROWS" ) == NULL
660 : || CSLFetchNameValue( papszHdr, "BANDS" ) == NULL )
661 : {
662 0 : CSLDestroy( papszHdr );
663 0 : return NULL;
664 : }
665 :
666 : /* -------------------------------------------------------------------- */
667 : /* Create a corresponding GDALDataset. */
668 : /* -------------------------------------------------------------------- */
669 : GenBinDataset *poDS;
670 :
671 1 : poDS = new GenBinDataset();
672 :
673 : /* -------------------------------------------------------------------- */
674 : /* Capture some information from the file that is of interest. */
675 : /* -------------------------------------------------------------------- */
676 2 : int nBands = atoi(CSLFetchNameValue( papszHdr, "BANDS" ));
677 :
678 1 : poDS->nRasterXSize = atoi(CSLFetchNameValue( papszHdr, "COLS" ));
679 1 : poDS->nRasterYSize = atoi(CSLFetchNameValue( papszHdr, "ROWS" ));
680 1 : poDS->papszHDR = papszHdr;
681 :
682 1 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
683 : !GDALCheckBandCount(nBands, FALSE))
684 : {
685 0 : delete poDS;
686 0 : return NULL;
687 : }
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* Open target binary file. */
691 : /* -------------------------------------------------------------------- */
692 1 : if( poOpenInfo->eAccess == GA_ReadOnly )
693 1 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
694 : else
695 0 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
696 :
697 1 : if( poDS->fpImage == NULL )
698 : {
699 : CPLError( CE_Failure, CPLE_OpenFailed,
700 : "Failed to open %s with write permission.\n%s",
701 0 : osName.c_str(), VSIStrerror( errno ) );
702 0 : delete poDS;
703 0 : return NULL;
704 : }
705 :
706 1 : poDS->eAccess = poOpenInfo->eAccess;
707 :
708 : /* -------------------------------------------------------------------- */
709 : /* Figure out the data type. */
710 : /* -------------------------------------------------------------------- */
711 1 : const char *pszDataType = CSLFetchNameValue( papszHdr, "DATATYPE" );
712 : GDALDataType eDataType;
713 1 : int nBits = -1; // Only needed for partial byte types
714 :
715 1 : if( pszDataType == NULL )
716 0 : eDataType = GDT_Byte;
717 1 : else if( EQUAL(pszDataType,"U16") )
718 0 : eDataType = GDT_UInt16;
719 1 : else if( EQUAL(pszDataType,"S16") )
720 0 : eDataType = GDT_Int16;
721 1 : else if( EQUAL(pszDataType,"F32") )
722 0 : eDataType = GDT_Float32;
723 1 : else if( EQUAL(pszDataType,"F64") )
724 0 : eDataType = GDT_Float64;
725 1 : else if( EQUAL(pszDataType,"U8") )
726 1 : eDataType = GDT_Byte;
727 0 : else if( EQUAL(pszDataType,"U1")
728 : || EQUAL(pszDataType,"U2")
729 : || EQUAL(pszDataType,"U4") )
730 : {
731 0 : nBits = atoi(pszDataType+1);
732 0 : eDataType = GDT_Byte;
733 0 : if( nBands != 1 )
734 : {
735 : CPLError( CE_Failure, CPLE_OpenFailed,
736 0 : "Only one band is supported for U1/U2/U4 data type" );
737 0 : delete poDS;
738 0 : return NULL;
739 : }
740 : }
741 : else
742 : {
743 0 : eDataType = GDT_Byte;
744 : CPLError( CE_Warning, CPLE_AppDefined,
745 : "DATATYPE=%s not recognised, assuming Byte.",
746 0 : pszDataType );
747 : }
748 :
749 : /* -------------------------------------------------------------------- */
750 : /* Do we need byte swapping? */
751 : /* -------------------------------------------------------------------- */
752 1 : const char *pszBYTE_ORDER = CSLFetchNameValue(papszHdr,"BYTE_ORDER");
753 1 : int bNative = TRUE;
754 :
755 1 : if( pszBYTE_ORDER != NULL )
756 : {
757 : #ifdef CPL_LSB
758 1 : bNative = EQUALN(pszBYTE_ORDER,"LSB",3);
759 : #else
760 : bNative = !EQUALN(pszBYTE_ORDER,"LSB",3);
761 : #endif
762 : }
763 :
764 : /* -------------------------------------------------------------------- */
765 : /* Work out interleaving info. */
766 : /* -------------------------------------------------------------------- */
767 1 : int nItemSize = GDALGetDataTypeSize(eDataType)/8;
768 1 : const char *pszInterleaving = CSLFetchNameValue(papszHdr,"INTERLEAVING");
769 : int nPixelOffset, nLineOffset;
770 : vsi_l_offset nBandOffset;
771 1 : int bIntOverflow = FALSE;
772 :
773 1 : if( pszInterleaving == NULL )
774 0 : pszInterleaving = "BIL";
775 :
776 2 : if( EQUAL(pszInterleaving,"BSQ") || EQUAL(pszInterleaving,"NA") )
777 : {
778 1 : nPixelOffset = nItemSize;
779 1 : if (poDS->nRasterXSize > INT_MAX / nItemSize) bIntOverflow = TRUE;
780 1 : nLineOffset = nItemSize * poDS->nRasterXSize;
781 1 : nBandOffset = nLineOffset * poDS->nRasterYSize;
782 : }
783 0 : else if( EQUAL(pszInterleaving,"BIP") )
784 : {
785 0 : nPixelOffset = nItemSize * nBands;
786 0 : if (poDS->nRasterXSize > INT_MAX / nPixelOffset) bIntOverflow = TRUE;
787 0 : nLineOffset = nPixelOffset * poDS->nRasterXSize;
788 0 : nBandOffset = nItemSize;
789 : }
790 : else
791 : {
792 0 : if( !EQUAL(pszInterleaving,"BIL") )
793 : CPLError( CE_Warning, CPLE_AppDefined,
794 : "INTERLEAVING:%s not recognised, assume BIL.",
795 0 : pszInterleaving );
796 :
797 0 : nPixelOffset = nItemSize;
798 0 : if (poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBands)) bIntOverflow = TRUE;
799 0 : nLineOffset = nPixelOffset * nBands * poDS->nRasterXSize;
800 0 : nBandOffset = nItemSize * poDS->nRasterXSize;
801 : }
802 :
803 1 : if (bIntOverflow)
804 : {
805 0 : delete poDS;
806 : CPLError( CE_Failure, CPLE_AppDefined,
807 0 : "Int overflow occured.");
808 0 : return NULL;
809 : }
810 :
811 1 : poDS->SetDescription( poOpenInfo->pszFilename );
812 1 : poDS->PamInitialize();
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* Create band information objects. */
816 : /* -------------------------------------------------------------------- */
817 1 : poDS->nBands = nBands;
818 8 : for( i = 0; i < poDS->nBands; i++ )
819 : {
820 7 : if( nBits != -1 )
821 : {
822 0 : poDS->SetBand( i+1, new GenBinBitRasterBand( poDS, nBits ) );
823 : }
824 : else
825 : poDS->SetBand(
826 : i+1,
827 : new RawRasterBand( poDS, i+1, poDS->fpImage,
828 : nBandOffset * i, nPixelOffset, nLineOffset,
829 7 : eDataType, bNative, TRUE ) );
830 : }
831 :
832 : /* -------------------------------------------------------------------- */
833 : /* Get geotransform. */
834 : /* -------------------------------------------------------------------- */
835 1 : if( CSLFetchNameValue(papszHdr,"UL_X_COORDINATE") != NULL
836 : && CSLFetchNameValue(papszHdr,"UL_Y_COORDINATE") != NULL
837 : && CSLFetchNameValue(papszHdr,"LR_X_COORDINATE") != NULL
838 : && CSLFetchNameValue(papszHdr,"LR_Y_COORDINATE") != NULL )
839 : {
840 1 : double dfULX = CPLAtofM(CSLFetchNameValue(papszHdr,"UL_X_COORDINATE"));
841 1 : double dfULY = CPLAtofM(CSLFetchNameValue(papszHdr,"UL_Y_COORDINATE"));
842 1 : double dfLRX = CPLAtofM(CSLFetchNameValue(papszHdr,"LR_X_COORDINATE"));
843 1 : double dfLRY = CPLAtofM(CSLFetchNameValue(papszHdr,"LR_Y_COORDINATE"));
844 :
845 1 : poDS->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize-1);
846 1 : poDS->adfGeoTransform[2] = 0.0;
847 1 : poDS->adfGeoTransform[4] = 0.0;
848 1 : poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize-1);
849 :
850 1 : poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
851 1 : poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[5] * 0.5;
852 :
853 1 : poDS->bGotTransform = TRUE;
854 : }
855 :
856 : /* -------------------------------------------------------------------- */
857 : /* Try and parse the coordinate system. */
858 : /* -------------------------------------------------------------------- */
859 1 : poDS->ParseCoordinateSystem( papszHdr );
860 :
861 : /* -------------------------------------------------------------------- */
862 : /* Initialize any PAM information. */
863 : /* -------------------------------------------------------------------- */
864 1 : poDS->TryLoadXML();
865 :
866 : /* -------------------------------------------------------------------- */
867 : /* Check for overviews. */
868 : /* -------------------------------------------------------------------- */
869 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
870 :
871 1 : return( poDS );
872 : }
873 :
874 : /************************************************************************/
875 : /* GDALRegister_GenBin() */
876 : /************************************************************************/
877 :
878 582 : void GDALRegister_GenBin()
879 :
880 : {
881 : GDALDriver *poDriver;
882 :
883 582 : if( GDALGetDriverByName( "GenBin" ) == NULL )
884 : {
885 561 : poDriver = new GDALDriver();
886 :
887 561 : poDriver->SetDescription( "GenBin" );
888 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
889 561 : "Generic Binary (.hdr Labelled)" );
890 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
891 561 : "frmt_various.html#GenBin" );
892 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
893 :
894 561 : poDriver->pfnOpen = GenBinDataset::Open;
895 :
896 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
897 : }
898 582 : }
|