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 : FILE *fpImage; // image data file.
198 :
199 : int bGotTransform;
200 : double adfGeoTransform[6];
201 : char *pszProjection;
202 :
203 : int bHDRDirty;
204 : char **papszHDR;
205 :
206 : void ParseCoordinateSystem( char ** );
207 :
208 : public:
209 : GenBinDataset();
210 : ~GenBinDataset();
211 :
212 : virtual CPLErr GetGeoTransform( double * padfTransform );
213 : virtual const char *GetProjectionRef(void);
214 :
215 : virtual char **GetFileList();
216 :
217 : static GDALDataset *Open( GDALOpenInfo * );
218 : };
219 :
220 : /************************************************************************/
221 : /* ==================================================================== */
222 : /* GenBinBitRasterBand */
223 : /* ==================================================================== */
224 : /************************************************************************/
225 :
226 : class GenBinBitRasterBand : public GDALPamRasterBand
227 0 : {
228 : int nBits;
229 : long nStartBit;
230 : int nPixelOffsetBits;
231 : int nLineOffsetBits;
232 :
233 : public:
234 : GenBinBitRasterBand( GenBinDataset *poDS, int nBits );
235 :
236 : virtual CPLErr IReadBlock( int, int, void * );
237 : };
238 :
239 : /************************************************************************/
240 : /* GenBinBitRasterBand() */
241 : /************************************************************************/
242 :
243 0 : GenBinBitRasterBand::GenBinBitRasterBand( GenBinDataset *poDS, int nBitsIn )
244 : {
245 : SetMetadataItem( "NBITS",
246 : CPLString().Printf("%d",nBitsIn),
247 0 : "IMAGE_STRUCTURE" );
248 :
249 0 : this->poDS = poDS;
250 0 : nBits = nBitsIn;
251 0 : nBand = 1;
252 :
253 0 : eDataType = GDT_Byte;
254 :
255 0 : nBlockXSize = poDS->nRasterXSize;
256 0 : nBlockYSize = 1;
257 0 : }
258 :
259 : /************************************************************************/
260 : /* IReadBlock() */
261 : /************************************************************************/
262 :
263 : CPLErr GenBinBitRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
264 0 : void * pImage )
265 :
266 : {
267 0 : GenBinDataset *poGDS = (GenBinDataset *) poDS;
268 : vsi_l_offset nLineStart;
269 : unsigned int nLineBytes;
270 : int iBitOffset;
271 : GByte *pabyBuffer;
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Establish desired position. */
275 : /* -------------------------------------------------------------------- */
276 0 : nLineStart = (((vsi_l_offset)nBlockXSize) * nBlockYOff * nBits) / 8;
277 0 : iBitOffset = (int)((((vsi_l_offset)nBlockXSize) * nBlockYOff * nBits) % 8);
278 0 : nLineBytes = (int) ((((vsi_l_offset)nBlockXSize) * (nBlockYOff+1) * nBits + 7) / 8 - nLineStart);
279 :
280 : /* -------------------------------------------------------------------- */
281 : /* Read data into buffer. */
282 : /* -------------------------------------------------------------------- */
283 0 : pabyBuffer = (GByte *) CPLCalloc(nLineBytes,1);
284 :
285 0 : if( VSIFSeekL( poGDS->fpImage, nLineStart, SEEK_SET ) != 0
286 : || VSIFReadL( pabyBuffer, 1, nLineBytes, poGDS->fpImage) != nLineBytes )
287 : {
288 : CPLError( CE_Failure, CPLE_FileIO,
289 : "Failed to read %u bytes at offset %lu.\n%s",
290 : nLineBytes, (unsigned long)nLineStart,
291 0 : VSIStrerror( errno ) );
292 0 : return CE_Failure;
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Copy data, promoting to 8bit. */
297 : /* -------------------------------------------------------------------- */
298 : int iX;
299 :
300 0 : if( nBits == 1 )
301 : {
302 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
303 : {
304 0 : if( pabyBuffer[iBitOffset>>3] & (0x80 >>(iBitOffset & 7)) )
305 0 : ((GByte *) pImage)[iX] = 1;
306 : else
307 0 : ((GByte *) pImage)[iX] = 0;
308 : }
309 : }
310 0 : else if( nBits == 2 )
311 : {
312 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
313 : {
314 : ((GByte *) pImage)[iX] =
315 0 : ((pabyBuffer[iBitOffset>>3]) >> (6-(iBitOffset&0x7)) & 0x3);
316 : }
317 : }
318 0 : else if( nBits == 4 )
319 : {
320 0 : for( iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits )
321 : {
322 0 : if( iBitOffset == 0 )
323 0 : ((GByte *) pImage)[iX] = (pabyBuffer[iBitOffset>>3]) >> 4;
324 : else
325 0 : ((GByte *) pImage)[iX] = (pabyBuffer[iBitOffset>>3]) & 0xf;
326 : }
327 : }
328 : else
329 0 : CPLAssert( FALSE );
330 :
331 0 : CPLFree( pabyBuffer );
332 :
333 0 : return CE_None;
334 : }
335 :
336 : /************************************************************************/
337 : /* ==================================================================== */
338 : /* GenBinDataset */
339 : /* ==================================================================== */
340 : /************************************************************************/
341 :
342 : /************************************************************************/
343 : /* GenBinDataset() */
344 : /************************************************************************/
345 :
346 1 : GenBinDataset::GenBinDataset()
347 : {
348 1 : fpImage = NULL;
349 1 : pszProjection = CPLStrdup("");
350 1 : bGotTransform = FALSE;
351 1 : adfGeoTransform[0] = 0.0;
352 1 : adfGeoTransform[1] = 1.0;
353 1 : adfGeoTransform[2] = 0.0;
354 1 : adfGeoTransform[3] = 0.0;
355 1 : adfGeoTransform[4] = 0.0;
356 1 : adfGeoTransform[5] = 1.0;
357 1 : papszHDR = NULL;
358 1 : }
359 :
360 : /************************************************************************/
361 : /* ~GenBinDataset() */
362 : /************************************************************************/
363 :
364 1 : GenBinDataset::~GenBinDataset()
365 :
366 : {
367 1 : FlushCache();
368 :
369 1 : if( fpImage != NULL )
370 1 : VSIFCloseL( fpImage );
371 :
372 1 : CPLFree( pszProjection );
373 1 : CSLDestroy( papszHDR );
374 1 : }
375 :
376 : /************************************************************************/
377 : /* GetProjectionRef() */
378 : /************************************************************************/
379 :
380 1 : const char *GenBinDataset::GetProjectionRef()
381 :
382 : {
383 1 : if (pszProjection && strlen(pszProjection) > 0)
384 1 : return pszProjection;
385 :
386 0 : return GDALPamDataset::GetProjectionRef();
387 : }
388 :
389 : /************************************************************************/
390 : /* GetGeoTransform() */
391 : /************************************************************************/
392 :
393 1 : CPLErr GenBinDataset::GetGeoTransform( double * padfTransform )
394 :
395 : {
396 1 : if( bGotTransform )
397 : {
398 1 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
399 1 : return CE_None;
400 : }
401 : else
402 : {
403 0 : return GDALPamDataset::GetGeoTransform( padfTransform );
404 : }
405 : }
406 :
407 : /************************************************************************/
408 : /* GetFileList() */
409 : /************************************************************************/
410 :
411 0 : char **GenBinDataset::GetFileList()
412 :
413 : {
414 0 : CPLString osPath = CPLGetPath( GetDescription() );
415 0 : CPLString osName = CPLGetBasename( GetDescription() );
416 0 : char **papszFileList = NULL;
417 :
418 : // Main data file, etc.
419 0 : papszFileList = GDALPamDataset::GetFileList();
420 :
421 : // Header file.
422 0 : CPLString osFilename = CPLFormCIFilename( osPath, osName, "hdr" );
423 0 : papszFileList = CSLAddString( papszFileList, osFilename );
424 :
425 0 : return papszFileList;
426 : }
427 :
428 : /************************************************************************/
429 : /* ParseCoordinateSystem() */
430 : /************************************************************************/
431 :
432 1 : void GenBinDataset::ParseCoordinateSystem( char **papszHdr )
433 :
434 : {
435 1 : const char *pszProjName = CSLFetchNameValue( papszHdr, "PROJECTION_NAME" );
436 1 : OGRSpatialReference oSRS;
437 :
438 1 : if( pszProjName == NULL )
439 0 : return;
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Translate zone and parameters into numeric form. */
443 : /* -------------------------------------------------------------------- */
444 1 : int nZone = 0;
445 : double adfProjParms[15];
446 1 : const char *pszUnits = CSLFetchNameValue( papszHdr, "MAP_UNITS" );
447 1 : const char *pszDatumName = CSLFetchNameValue( papszHdr, "DATUM_NAME" );
448 :
449 1 : if( CSLFetchNameValue( papszHdr, "PROJECTION_ZONE" ) )
450 1 : nZone = atoi(CSLFetchNameValue( papszHdr, "PROJECTION_ZONE" ));
451 :
452 1 : memset( adfProjParms, 0, sizeof(adfProjParms) );
453 1 : if( CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) )
454 : {
455 : int i;
456 : char **papszTokens = CSLTokenizeString(
457 1 : CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) );
458 :
459 15 : for( i = 0; i < 15 && papszTokens[i] != NULL; i++ )
460 14 : adfProjParms[i] = CPLAtofM( papszTokens[i] );
461 :
462 1 : CSLDestroy( papszTokens );
463 : }
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* Handle projections. */
467 : /* -------------------------------------------------------------------- */
468 1 : if( EQUAL(pszProjName,"UTM") && nZone != 0 )
469 : {
470 : // honestly, I'm just getting that the negative zone for
471 : // southern hemisphere is used.
472 0 : oSRS.SetUTM( ABS(nZone), nZone > 0 );
473 : }
474 :
475 1 : else if( EQUAL(pszProjName,"State Plane") && nZone != 0 )
476 : {
477 1 : int nPairs = sizeof(anUsgsEsriZones) / (2*sizeof(int));
478 : int i;
479 1 : double dfUnits = 0.0;
480 :
481 109 : for( i = 0; i < nPairs; i++ )
482 : {
483 109 : if( anUsgsEsriZones[i*2+1] == nZone )
484 : {
485 1 : nZone = anUsgsEsriZones[i*2];
486 1 : break;
487 : }
488 :
489 : }
490 :
491 1 : if( EQUAL(pszUnits,"feet") )
492 1 : dfUnits = CPLAtofM(SRS_UL_US_FOOT_CONV);
493 0 : else if( EQUALN(pszUnits,"MET",3) )
494 0 : dfUnits = 1.0;
495 : else
496 0 : pszUnits = NULL;
497 :
498 : oSRS.SetStatePlane( ABS(nZone),
499 : pszDatumName==NULL || !EQUAL(pszDatumName,"NAD27"),
500 1 : pszUnits, dfUnits );
501 : }
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Setup the geographic coordinate system. */
505 : /* -------------------------------------------------------------------- */
506 1 : if( oSRS.GetAttrNode( "GEOGCS" ) == NULL )
507 : {
508 0 : if( pszDatumName != NULL
509 : && oSRS.SetWellKnownGeogCS( pszDatumName ) == OGRERR_NONE )
510 : {
511 : // good
512 : }
513 0 : else if( CSLFetchNameValue( papszHdr, "SPHEROID_NAME" )
514 : && CSLFetchNameValue( papszHdr, "SEMI_MAJOR_AXIS" )
515 : && CSLFetchNameValue( papszHdr, "SEMI_MINOR_AXIS" ) )
516 : {
517 0 : double dfSemiMajor = CPLAtofM(CSLFetchNameValue( papszHdr, "SEMI_MAJOR_AXIS"));
518 0 : double dfSemiMinor = CPLAtofM(CSLFetchNameValue( papszHdr, "SEMI_MINOR_AXIS"));
519 :
520 : oSRS.SetGeogCS( CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
521 : CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
522 : CSLFetchNameValue( papszHdr, "SPHEROID_NAME" ),
523 : dfSemiMajor,
524 0 : 1.0 / (1.0 - dfSemiMinor/dfSemiMajor) );
525 : }
526 : else // fallback default.
527 0 : oSRS.SetWellKnownGeogCS( "WGS84" );
528 : }
529 :
530 : /* -------------------------------------------------------------------- */
531 : /* Convert to WKT. */
532 : /* -------------------------------------------------------------------- */
533 1 : CPLFree( pszProjection );
534 1 : pszProjection = NULL;
535 :
536 1 : oSRS.exportToWkt( &pszProjection );
537 : }
538 :
539 : /************************************************************************/
540 : /* Open() */
541 : /************************************************************************/
542 :
543 9796 : GDALDataset *GenBinDataset::Open( GDALOpenInfo * poOpenInfo )
544 :
545 : {
546 : int i, bSelectedHDR;
547 :
548 : /* -------------------------------------------------------------------- */
549 : /* We assume the user is pointing to the binary (ie. .bil) file. */
550 : /* -------------------------------------------------------------------- */
551 9796 : if( poOpenInfo->nHeaderBytes < 2 )
552 9304 : return NULL;
553 :
554 : /* -------------------------------------------------------------------- */
555 : /* Now we need to tear apart tfhe filename to form a .HDR */
556 : /* filename. */
557 : /* -------------------------------------------------------------------- */
558 492 : CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
559 492 : CPLString osName = CPLGetBasename( poOpenInfo->pszFilename );
560 492 : CPLString osHDRFilename;
561 :
562 492 : if( poOpenInfo->papszSiblingFiles )
563 : {
564 : int iFile = CSLFindString(poOpenInfo->papszSiblingFiles,
565 450 : CPLFormFilename( NULL, osName, "hdr" ) );
566 450 : if( iFile < 0 ) // return if there is no corresponding .hdr file
567 421 : return NULL;
568 :
569 : osHDRFilename =
570 : CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile],
571 29 : NULL );
572 : }
573 : else
574 : {
575 42 : osHDRFilename = CPLFormCIFilename( osPath, osName, "hdr" );
576 : }
577 :
578 71 : bSelectedHDR = EQUAL( osHDRFilename, poOpenInfo->pszFilename );
579 :
580 : /* -------------------------------------------------------------------- */
581 : /* Do we have a .hdr file? */
582 : /* -------------------------------------------------------------------- */
583 : FILE *fp;
584 :
585 71 : fp = VSIFOpenL( osHDRFilename, "r" );
586 :
587 71 : if( fp == NULL )
588 : {
589 42 : return NULL;
590 : }
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Read a chunk to skim for expected keywords. */
594 : /* -------------------------------------------------------------------- */
595 : char achHeader[1000];
596 :
597 29 : int nRead = VSIFReadL( achHeader, 1, sizeof(achHeader) - 1, fp );
598 29 : achHeader[nRead] = '\0';
599 29 : VSIFSeekL( fp, 0, SEEK_SET );
600 :
601 29 : if( strstr( achHeader, "BANDS:" ) == NULL
602 : || strstr( achHeader, "ROWS:" ) == NULL
603 : || strstr( achHeader, "COLS:" ) == NULL )
604 : {
605 28 : VSIFCloseL( fp );
606 28 : return NULL;
607 : }
608 :
609 : /* -------------------------------------------------------------------- */
610 : /* Has the user selected the .hdr file to open? */
611 : /* -------------------------------------------------------------------- */
612 1 : if( bSelectedHDR )
613 : {
614 : CPLError( CE_Failure, CPLE_AppDefined,
615 : "The selected file is an Generic Binary header file, but to\n"
616 : "open Generic Binary datasets, the data file should be selected\n"
617 : "instead of the .hdr file. Please try again selecting\n"
618 : "the raw data file corresponding to the header file: %s\n",
619 0 : poOpenInfo->pszFilename );
620 0 : VSIFCloseL( fp );
621 0 : return NULL;
622 : }
623 :
624 : /* -------------------------------------------------------------------- */
625 : /* Read the .hdr file. */
626 : /* -------------------------------------------------------------------- */
627 1 : char **papszHdr = NULL;
628 1 : const char *pszLine = CPLReadLineL( fp );
629 :
630 24 : while( pszLine != NULL )
631 : {
632 22 : if( EQUAL(pszLine,"PROJECTION_PARAMETERS:") )
633 : {
634 1 : CPLString osPP = pszLine;
635 :
636 1 : pszLine = CPLReadLineL(fp);
637 17 : while( pszLine != NULL
638 : && (*pszLine == '\t' || *pszLine == ' ') )
639 : {
640 15 : osPP += pszLine;
641 15 : pszLine = CPLReadLineL(fp);
642 : }
643 1 : papszHdr = CSLAddString( papszHdr, osPP );
644 : }
645 : else
646 : {
647 : char *pszName;
648 21 : CPLString osValue;
649 :
650 21 : osValue = CPLParseNameValue( pszLine, &pszName );
651 21 : osValue.Trim();
652 :
653 21 : papszHdr = CSLSetNameValue( papszHdr, pszName, osValue );
654 21 : CPLFree( pszName );
655 :
656 21 : pszLine = CPLReadLineL( fp );
657 : }
658 : }
659 :
660 1 : VSIFCloseL( fp );
661 :
662 1 : if( CSLFetchNameValue( papszHdr, "COLS" ) == NULL
663 : || CSLFetchNameValue( papszHdr, "ROWS" ) == NULL
664 : || CSLFetchNameValue( papszHdr, "BANDS" ) == NULL )
665 : {
666 0 : CSLDestroy( papszHdr );
667 0 : return NULL;
668 : }
669 :
670 : /* -------------------------------------------------------------------- */
671 : /* Create a corresponding GDALDataset. */
672 : /* -------------------------------------------------------------------- */
673 : GenBinDataset *poDS;
674 :
675 1 : poDS = new GenBinDataset();
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Capture some information from the file that is of interest. */
679 : /* -------------------------------------------------------------------- */
680 2 : int nBands = atoi(CSLFetchNameValue( papszHdr, "BANDS" ));
681 :
682 1 : poDS->nRasterXSize = atoi(CSLFetchNameValue( papszHdr, "COLS" ));
683 1 : poDS->nRasterYSize = atoi(CSLFetchNameValue( papszHdr, "ROWS" ));
684 1 : poDS->papszHDR = papszHdr;
685 :
686 1 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
687 : !GDALCheckBandCount(nBands, FALSE))
688 : {
689 0 : delete poDS;
690 492 : return NULL;
691 : }
692 :
693 : /* -------------------------------------------------------------------- */
694 : /* Open target binary file. */
695 : /* -------------------------------------------------------------------- */
696 1 : if( poOpenInfo->eAccess == GA_ReadOnly )
697 1 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
698 : else
699 0 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
700 :
701 1 : if( poDS->fpImage == NULL )
702 : {
703 : CPLError( CE_Failure, CPLE_OpenFailed,
704 : "Failed to open %s with write permission.\n%s",
705 0 : osName.c_str(), VSIStrerror( errno ) );
706 0 : delete poDS;
707 0 : return NULL;
708 : }
709 :
710 1 : poDS->eAccess = poOpenInfo->eAccess;
711 :
712 : /* -------------------------------------------------------------------- */
713 : /* Figure out the data type. */
714 : /* -------------------------------------------------------------------- */
715 1 : const char *pszDataType = CSLFetchNameValue( papszHdr, "DATATYPE" );
716 : GDALDataType eDataType;
717 1 : int nBits = -1; // Only needed for partial byte types
718 :
719 1 : if( pszDataType == NULL )
720 0 : eDataType = GDT_Byte;
721 1 : else if( EQUAL(pszDataType,"U16") )
722 0 : eDataType = GDT_UInt16;
723 1 : else if( EQUAL(pszDataType,"S16") )
724 0 : eDataType = GDT_Int16;
725 1 : else if( EQUAL(pszDataType,"F32") )
726 0 : eDataType = GDT_Float32;
727 1 : else if( EQUAL(pszDataType,"F64") )
728 0 : eDataType = GDT_Float64;
729 1 : else if( EQUAL(pszDataType,"U8") )
730 1 : eDataType = GDT_Byte;
731 0 : else if( EQUAL(pszDataType,"U1")
732 : || EQUAL(pszDataType,"U2")
733 : || EQUAL(pszDataType,"U4") )
734 : {
735 0 : nBits = atoi(pszDataType+1);
736 0 : eDataType = GDT_Byte;
737 0 : if( nBands != 1 )
738 : {
739 : CPLError( CE_Failure, CPLE_OpenFailed,
740 0 : "Only one band is supported for U1/U2/U4 data type" );
741 0 : delete poDS;
742 0 : return NULL;
743 : }
744 : }
745 : else
746 : {
747 0 : eDataType = GDT_Byte;
748 : CPLError( CE_Warning, CPLE_AppDefined,
749 : "DATATYPE=%s not recognised, assuming Byte.",
750 0 : pszDataType );
751 : }
752 :
753 : /* -------------------------------------------------------------------- */
754 : /* Do we need byte swapping? */
755 : /* -------------------------------------------------------------------- */
756 1 : const char *pszBYTE_ORDER = CSLFetchNameValue(papszHdr,"BYTE_ORDER");
757 1 : int bNative = TRUE;
758 :
759 1 : if( pszBYTE_ORDER != NULL )
760 : {
761 : #ifdef CPL_LSB
762 1 : bNative = EQUALN(pszBYTE_ORDER,"LSB",3);
763 : #else
764 : bNative = !EQUALN(pszBYTE_ORDER,"LSB",3);
765 : #endif
766 : }
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Work out interleaving info. */
770 : /* -------------------------------------------------------------------- */
771 1 : int nItemSize = GDALGetDataTypeSize(eDataType)/8;
772 1 : const char *pszInterleaving = CSLFetchNameValue(papszHdr,"INTERLEAVING");
773 : int nPixelOffset, nLineOffset;
774 : vsi_l_offset nBandOffset;
775 1 : int bIntOverflow = FALSE;
776 :
777 1 : if( pszInterleaving == NULL )
778 0 : pszInterleaving = "BIL";
779 :
780 2 : if( EQUAL(pszInterleaving,"BSQ") || EQUAL(pszInterleaving,"NA") )
781 : {
782 1 : nPixelOffset = nItemSize;
783 1 : if (poDS->nRasterXSize > INT_MAX / nItemSize) bIntOverflow = TRUE;
784 1 : nLineOffset = nItemSize * poDS->nRasterXSize;
785 1 : nBandOffset = nLineOffset * poDS->nRasterYSize;
786 : }
787 0 : else if( EQUAL(pszInterleaving,"BIP") )
788 : {
789 0 : nPixelOffset = nItemSize * nBands;
790 0 : if (poDS->nRasterXSize > INT_MAX / nPixelOffset) bIntOverflow = TRUE;
791 0 : nLineOffset = nPixelOffset * poDS->nRasterXSize;
792 0 : nBandOffset = nItemSize;
793 : }
794 : else
795 : {
796 0 : if( !EQUAL(pszInterleaving,"BIL") )
797 : CPLError( CE_Warning, CPLE_AppDefined,
798 : "INTERLEAVING:%s not recognised, assume BIL.",
799 0 : pszInterleaving );
800 :
801 0 : nPixelOffset = nItemSize;
802 0 : if (poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBands)) bIntOverflow = TRUE;
803 0 : nLineOffset = nPixelOffset * nBands * poDS->nRasterXSize;
804 0 : nBandOffset = nItemSize * poDS->nRasterXSize;
805 : }
806 :
807 1 : if (bIntOverflow)
808 : {
809 0 : delete poDS;
810 : CPLError( CE_Failure, CPLE_AppDefined,
811 0 : "Int overflow occured.");
812 0 : return NULL;
813 : }
814 :
815 1 : poDS->SetDescription( poOpenInfo->pszFilename );
816 1 : poDS->PamInitialize();
817 :
818 : /* -------------------------------------------------------------------- */
819 : /* Create band information objects. */
820 : /* -------------------------------------------------------------------- */
821 1 : poDS->nBands = nBands;
822 8 : for( i = 0; i < poDS->nBands; i++ )
823 : {
824 7 : if( nBits != -1 )
825 : {
826 0 : poDS->SetBand( i+1, new GenBinBitRasterBand( poDS, nBits ) );
827 : }
828 : else
829 : poDS->SetBand(
830 : i+1,
831 : new RawRasterBand( poDS, i+1, poDS->fpImage,
832 : nBandOffset * i, nPixelOffset, nLineOffset,
833 7 : eDataType, bNative, TRUE ) );
834 : }
835 :
836 : /* -------------------------------------------------------------------- */
837 : /* Get geotransform. */
838 : /* -------------------------------------------------------------------- */
839 1 : if( CSLFetchNameValue(papszHdr,"UL_X_COORDINATE") != NULL
840 : && CSLFetchNameValue(papszHdr,"UL_Y_COORDINATE") != NULL
841 : && CSLFetchNameValue(papszHdr,"LR_X_COORDINATE") != NULL
842 : && CSLFetchNameValue(papszHdr,"LR_Y_COORDINATE") != NULL )
843 : {
844 1 : double dfULX = CPLAtofM(CSLFetchNameValue(papszHdr,"UL_X_COORDINATE"));
845 1 : double dfULY = CPLAtofM(CSLFetchNameValue(papszHdr,"UL_Y_COORDINATE"));
846 1 : double dfLRX = CPLAtofM(CSLFetchNameValue(papszHdr,"LR_X_COORDINATE"));
847 1 : double dfLRY = CPLAtofM(CSLFetchNameValue(papszHdr,"LR_Y_COORDINATE"));
848 :
849 1 : poDS->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize-1);
850 1 : poDS->adfGeoTransform[2] = 0.0;
851 1 : poDS->adfGeoTransform[4] = 0.0;
852 1 : poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize-1);
853 :
854 1 : poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
855 1 : poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[5] * 0.5;
856 :
857 1 : poDS->bGotTransform = TRUE;
858 : }
859 :
860 : /* -------------------------------------------------------------------- */
861 : /* Try and parse the coordinate system. */
862 : /* -------------------------------------------------------------------- */
863 1 : poDS->ParseCoordinateSystem( papszHdr );
864 :
865 : /* -------------------------------------------------------------------- */
866 : /* Initialize any PAM information. */
867 : /* -------------------------------------------------------------------- */
868 1 : poDS->TryLoadXML();
869 :
870 : /* -------------------------------------------------------------------- */
871 : /* Check for overviews. */
872 : /* -------------------------------------------------------------------- */
873 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
874 :
875 1 : return( poDS );
876 : }
877 :
878 : /************************************************************************/
879 : /* GDALRegister_GenBin() */
880 : /************************************************************************/
881 :
882 409 : void GDALRegister_GenBin()
883 :
884 : {
885 : GDALDriver *poDriver;
886 :
887 409 : if( GDALGetDriverByName( "GenBin" ) == NULL )
888 : {
889 392 : poDriver = new GDALDriver();
890 :
891 392 : poDriver->SetDescription( "GenBin" );
892 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
893 392 : "Generic Binary (.hdr Labelled)" );
894 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
895 392 : "frmt_various.html#GenBin" );
896 392 : poDriver->pfnOpen = GenBinDataset::Open;
897 :
898 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
899 : }
900 409 : }
|