1 : /******************************************************************************
2 : * $Id: aigdataset.cpp 22103 2011-04-02 14:51:10Z warmerdam $
3 : *
4 : * Project: Arc/Info Binary Grid Driver
5 : * Purpose: Implements GDAL interface to underlying library.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
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 "gdal_pam.h"
31 : #include "cpl_string.h"
32 : #include "ogr_spatialref.h"
33 : #include "gdal_rat.h"
34 : #include "aigrid.h"
35 : #include "avc.h"
36 :
37 : CPL_CVSID("$Id: aigdataset.cpp 22103 2011-04-02 14:51:10Z warmerdam $");
38 :
39 : CPL_C_START
40 : void GDALRegister_AIGrid(void);
41 : CPL_C_END
42 :
43 : static CPLString OSR_GDS( char **papszNV, const char * pszField,
44 : const char *pszDefaultValue );
45 :
46 :
47 : /************************************************************************/
48 : /* ==================================================================== */
49 : /* AIGDataset */
50 : /* ==================================================================== */
51 : /************************************************************************/
52 :
53 : class AIGRasterBand;
54 :
55 : class CPL_DLL AIGDataset : public GDALPamDataset
56 : {
57 : friend class AIGRasterBand;
58 :
59 : AIGInfo_t *psInfo;
60 :
61 : char **papszPrj;
62 : char *pszProjection;
63 :
64 : GDALColorTable *poCT;
65 : int bHasReadRat;
66 :
67 : void TranslateColorTable( const char * );
68 :
69 : void ReadRAT();
70 : GDALRasterAttributeTable *poRAT;
71 :
72 : public:
73 : AIGDataset();
74 : ~AIGDataset();
75 :
76 : static GDALDataset *Open( GDALOpenInfo * );
77 :
78 : virtual CPLErr GetGeoTransform( double * );
79 : virtual const char *GetProjectionRef(void);
80 : virtual char **GetFileList(void);
81 : };
82 :
83 : /************************************************************************/
84 : /* ==================================================================== */
85 : /* AIGRasterBand */
86 : /* ==================================================================== */
87 : /************************************************************************/
88 :
89 : class AIGRasterBand : public GDALPamRasterBand
90 :
91 7 : {
92 : friend class AIGDataset;
93 :
94 : public:
95 :
96 : AIGRasterBand( AIGDataset *, int );
97 :
98 : virtual CPLErr IReadBlock( int, int, void * );
99 : virtual double GetMinimum( int *pbSuccess );
100 : virtual double GetMaximum( int *pbSuccess );
101 : virtual double GetNoDataValue( int *pbSuccess );
102 :
103 : virtual GDALColorInterp GetColorInterpretation();
104 : virtual GDALColorTable *GetColorTable();
105 : virtual const GDALRasterAttributeTable *GetDefaultRAT();
106 : };
107 :
108 : /************************************************************************/
109 : /* AIGRasterBand() */
110 : /************************************************************************/
111 :
112 7 : AIGRasterBand::AIGRasterBand( AIGDataset *poDS, int nBand )
113 :
114 : {
115 7 : this->poDS = poDS;
116 7 : this->nBand = nBand;
117 :
118 7 : nBlockXSize = poDS->psInfo->nBlockXSize;
119 7 : nBlockYSize = poDS->psInfo->nBlockYSize;
120 :
121 12 : if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT
122 : && poDS->psInfo->dfMin >= 0.0 && poDS->psInfo->dfMax <= 254.0 )
123 : {
124 5 : eDataType = GDT_Byte;
125 : }
126 4 : else if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT
127 : && poDS->psInfo->dfMin >= -32767 && poDS->psInfo->dfMax <= 32767 )
128 : {
129 2 : eDataType = GDT_Int16;
130 : }
131 0 : else if( poDS->psInfo->nCellType == AIG_CELLTYPE_INT )
132 : {
133 0 : eDataType = GDT_Int32;
134 : }
135 : else
136 : {
137 0 : eDataType = GDT_Float32;
138 : }
139 7 : }
140 :
141 : /************************************************************************/
142 : /* IReadBlock() */
143 : /************************************************************************/
144 :
145 5898 : CPLErr AIGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
146 : void * pImage )
147 :
148 : {
149 5898 : AIGDataset *poODS = (AIGDataset *) poDS;
150 : GInt32 *panGridRaster;
151 : int i;
152 :
153 5898 : if( poODS->psInfo->nCellType == AIG_CELLTYPE_INT )
154 : {
155 5898 : panGridRaster = (GInt32 *) VSIMalloc3(4,nBlockXSize,nBlockYSize);
156 5898 : if( panGridRaster == NULL ||
157 : AIGReadTile( poODS->psInfo, nBlockXOff, nBlockYOff, panGridRaster )
158 : != CE_None )
159 : {
160 0 : CPLFree( panGridRaster );
161 0 : return CE_Failure;
162 : }
163 :
164 5898 : if( eDataType == GDT_Byte )
165 : {
166 2050 : for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
167 : {
168 2048 : if( panGridRaster[i] == ESRI_GRID_NO_DATA )
169 2042 : ((GByte *) pImage)[i] = 255;
170 : else
171 6 : ((GByte *) pImage)[i] = (GByte) panGridRaster[i];
172 : }
173 : }
174 5896 : else if( eDataType == GDT_Int16 )
175 : {
176 6043400 : for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
177 : {
178 6037504 : if( panGridRaster[i] == ESRI_GRID_NO_DATA )
179 4967529 : ((GInt16 *) pImage)[i] = -32768;
180 : else
181 1069975 : ((GInt16 *) pImage)[i] = (GInt16) panGridRaster[i];
182 : }
183 : }
184 : else
185 : {
186 0 : for( i = 0; i < nBlockXSize * nBlockYSize; i++ )
187 0 : ((GInt32 *) pImage)[i] = panGridRaster[i];
188 : }
189 :
190 5898 : CPLFree( panGridRaster );
191 :
192 5898 : return CE_None;
193 : }
194 : else
195 : {
196 : return AIGReadFloatTile( poODS->psInfo, nBlockXOff, nBlockYOff,
197 0 : (float *) pImage );
198 : }
199 : }
200 :
201 : /************************************************************************/
202 : /* GetDefaultRAT() */
203 : /************************************************************************/
204 :
205 1 : const GDALRasterAttributeTable *AIGRasterBand::GetDefaultRAT()
206 :
207 : {
208 1 : AIGDataset *poODS = (AIGDataset *) poDS;
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* Read info raster attribute table, if present. */
212 : /* -------------------------------------------------------------------- */
213 1 : if (!poODS->bHasReadRat)
214 : {
215 1 : poODS->ReadRAT();
216 1 : poODS->bHasReadRat = TRUE;
217 : }
218 :
219 1 : if( poODS->poRAT )
220 1 : return poODS->poRAT;
221 : else
222 0 : return GDALPamRasterBand::GetDefaultRAT();
223 : }
224 :
225 : /************************************************************************/
226 : /* GetMinimum() */
227 : /************************************************************************/
228 :
229 1 : double AIGRasterBand::GetMinimum( int *pbSuccess )
230 :
231 : {
232 1 : AIGDataset *poODS = (AIGDataset *) poDS;
233 :
234 1 : if( pbSuccess != NULL )
235 1 : *pbSuccess = TRUE;
236 :
237 1 : return poODS->psInfo->dfMin;
238 : }
239 :
240 : /************************************************************************/
241 : /* GetMaximum() */
242 : /************************************************************************/
243 :
244 1 : double AIGRasterBand::GetMaximum( int *pbSuccess )
245 :
246 : {
247 1 : AIGDataset *poODS = (AIGDataset *) poDS;
248 :
249 1 : if( pbSuccess != NULL )
250 1 : *pbSuccess = TRUE;
251 :
252 1 : return poODS->psInfo->dfMax;
253 : }
254 :
255 : /************************************************************************/
256 : /* GetNoDataValue() */
257 : /************************************************************************/
258 :
259 3 : double AIGRasterBand::GetNoDataValue( int *pbSuccess )
260 :
261 : {
262 3 : if( pbSuccess != NULL )
263 3 : *pbSuccess = TRUE;
264 :
265 3 : if( eDataType == GDT_Float32 )
266 0 : return ESRI_GRID_FLOAT_NO_DATA;
267 3 : else if( eDataType == GDT_Int16 )
268 0 : return -32768;
269 3 : else if( eDataType == GDT_Byte )
270 3 : return 255;
271 : else
272 0 : return ESRI_GRID_NO_DATA;
273 : }
274 :
275 : /************************************************************************/
276 : /* GetColorInterpretation() */
277 : /************************************************************************/
278 :
279 0 : GDALColorInterp AIGRasterBand::GetColorInterpretation()
280 :
281 : {
282 0 : AIGDataset *poODS = (AIGDataset *) poDS;
283 :
284 0 : if( poODS->poCT != NULL )
285 0 : return GCI_PaletteIndex;
286 : else
287 0 : return GDALPamRasterBand::GetColorInterpretation();
288 : }
289 :
290 : /************************************************************************/
291 : /* GetColorTable() */
292 : /************************************************************************/
293 :
294 2 : GDALColorTable *AIGRasterBand::GetColorTable()
295 :
296 : {
297 2 : AIGDataset *poODS = (AIGDataset *) poDS;
298 :
299 2 : if( poODS->poCT != NULL )
300 2 : return poODS->poCT;
301 : else
302 0 : return GDALPamRasterBand::GetColorTable();
303 : }
304 :
305 : /************************************************************************/
306 : /* ==================================================================== */
307 : /* AIGDataset */
308 : /* ==================================================================== */
309 : /************************************************************************/
310 :
311 :
312 : /************************************************************************/
313 : /* AIGDataset() */
314 : /************************************************************************/
315 :
316 7 : AIGDataset::AIGDataset()
317 :
318 : {
319 7 : psInfo = NULL;
320 7 : papszPrj = NULL;
321 7 : pszProjection = CPLStrdup("");
322 7 : poCT = NULL;
323 7 : poRAT = NULL;
324 7 : bHasReadRat = FALSE;
325 7 : }
326 :
327 : /************************************************************************/
328 : /* ~AIGDataset() */
329 : /************************************************************************/
330 :
331 7 : AIGDataset::~AIGDataset()
332 :
333 : {
334 7 : FlushCache();
335 7 : CPLFree( pszProjection );
336 7 : CSLDestroy( papszPrj );
337 7 : if( psInfo != NULL )
338 7 : AIGClose( psInfo );
339 :
340 7 : if( poCT != NULL )
341 5 : delete poCT;
342 :
343 7 : if( poRAT != NULL )
344 1 : delete poRAT;
345 7 : }
346 :
347 : /************************************************************************/
348 : /* GetFileList() */
349 : /************************************************************************/
350 :
351 0 : char **AIGDataset::GetFileList()
352 :
353 : {
354 0 : char **papszFileList = GDALPamDataset::GetFileList();
355 :
356 : // Add in all files in the cover directory.
357 0 : char **papszCoverFiles = VSIReadDir( GetDescription() );
358 : int i;
359 :
360 0 : for( i = 0; papszCoverFiles != NULL && papszCoverFiles[i] != NULL; i++ )
361 : {
362 0 : if( EQUAL(papszCoverFiles[i],".")
363 0 : || EQUAL(papszCoverFiles[i],"..") )
364 0 : continue;
365 :
366 : papszFileList =
367 : CSLAddString( papszFileList,
368 0 : CPLFormFilename( GetDescription(),
369 0 : papszCoverFiles[i],
370 0 : NULL ) );
371 : }
372 0 : CSLDestroy(papszCoverFiles);
373 :
374 0 : return papszFileList;
375 : }
376 :
377 : /************************************************************************/
378 : /* ReadRAT() */
379 : /************************************************************************/
380 :
381 1 : void AIGDataset::ReadRAT()
382 :
383 : {
384 : #ifndef OGR_ENABLED
385 : #else
386 : /* -------------------------------------------------------------------- */
387 : /* Check if we have an associated info directory. If not */
388 : /* return quietly. */
389 : /* -------------------------------------------------------------------- */
390 1 : CPLString osInfoPath, osTableName;
391 : VSIStatBufL sStatBuf;
392 :
393 1 : osInfoPath = psInfo->pszCoverName;
394 1 : osInfoPath += "/../info";
395 :
396 1 : if( VSIStatL( osInfoPath, &sStatBuf ) != 0 )
397 : {
398 : CPLDebug( "AIG", "No associated info directory at: %s, skip RAT.",
399 0 : osInfoPath.c_str() );
400 : return;
401 : }
402 :
403 1 : osInfoPath += "/";
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Attempt to open the VAT table associated with this coverage. */
407 : /* -------------------------------------------------------------------- */
408 1 : osTableName = CPLGetFilename(psInfo->pszCoverName);
409 1 : osTableName += ".VAT";
410 :
411 : AVCBinFile *psFile =
412 : AVCBinReadOpen( osInfoPath, osTableName,
413 1 : AVCCoverTypeUnknown, AVCFileTABLE, NULL );
414 :
415 1 : CPLErrorReset();
416 1 : if( psFile == NULL )
417 : return;
418 :
419 1 : AVCTableDef *psTableDef = psFile->hdr.psTableDef;
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Setup columns in corresponding RAT. */
423 : /* -------------------------------------------------------------------- */
424 : int iField;
425 :
426 1 : poRAT = new GDALRasterAttributeTable();
427 :
428 3 : for( iField = 0; iField < psTableDef->numFields; iField++ )
429 : {
430 2 : AVCFieldInfo *psFDef = psTableDef->pasFieldDef + iField;
431 2 : GDALRATFieldUsage eFUsage = GFU_Generic;
432 2 : GDALRATFieldType eFType = GFT_String;
433 :
434 2 : CPLString osFName = psFDef->szName;
435 2 : osFName.Trim();
436 :
437 2 : if( EQUAL(osFName,"VALUE") )
438 1 : eFUsage = GFU_MinMax;
439 1 : else if( EQUAL(osFName,"COUNT") )
440 1 : eFUsage = GFU_PixelCount;
441 :
442 2 : if( psFDef->nType1 * 10 == AVC_FT_BININT )
443 2 : eFType = GFT_Integer;
444 0 : else if( psFDef->nType1 * 10 == AVC_FT_BINFLOAT )
445 0 : eFType = GFT_Real;
446 :
447 2 : poRAT->CreateColumn( osFName, eFType, eFUsage );
448 : }
449 :
450 : /* -------------------------------------------------------------------- */
451 : /* Process all records into RAT. */
452 : /* -------------------------------------------------------------------- */
453 : AVCField *pasFields;
454 1 : int iRecord = 0;
455 :
456 2644 : while( (pasFields = AVCBinReadNextTableRec(psFile)) != NULL )
457 : {
458 2642 : iRecord++;
459 :
460 7926 : for( iField = 0; iField < psTableDef->numFields; iField++ )
461 : {
462 5284 : switch( psTableDef->pasFieldDef[iField].nType1 * 10 )
463 : {
464 : case AVC_FT_DATE:
465 : case AVC_FT_FIXINT:
466 : case AVC_FT_CHAR:
467 : case AVC_FT_FIXNUM:
468 : {
469 : // XXX - I bet mloskot would like to see const_cast + static_cast :-)
470 0 : const char* pszTmp = (const char*)(pasFields[iField].pszStr);
471 0 : CPLString osStrValue( pszTmp );
472 0 : poRAT->SetValue( iRecord-1, iField, osStrValue.Trim() );
473 : }
474 0 : break;
475 :
476 : case AVC_FT_BININT:
477 5284 : if( psTableDef->pasFieldDef[iField].nSize == 4 )
478 : poRAT->SetValue( iRecord-1, iField,
479 5284 : pasFields[iField].nInt32 );
480 : else
481 : poRAT->SetValue( iRecord-1, iField,
482 0 : pasFields[iField].nInt16 );
483 5284 : break;
484 :
485 : case AVC_FT_BINFLOAT:
486 0 : if( psTableDef->pasFieldDef[iField].nSize == 4 )
487 : poRAT->SetValue( iRecord-1, iField,
488 0 : pasFields[iField].fFloat );
489 : else
490 : poRAT->SetValue( iRecord-1, iField,
491 0 : pasFields[iField].dDouble );
492 : break;
493 : }
494 : }
495 : }
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* Cleanup */
499 : /* -------------------------------------------------------------------- */
500 :
501 1 : AVCBinReadClose( psFile );
502 :
503 : /* Workaround against #2447 and #3031, to avoid binding languages */
504 : /* not being able to open the dataset */
505 1 : CPLErrorReset();
506 :
507 : #endif /* OGR_ENABLED */
508 : }
509 :
510 : /************************************************************************/
511 : /* Open() */
512 : /************************************************************************/
513 :
514 14277 : GDALDataset *AIGDataset::Open( GDALOpenInfo * poOpenInfo )
515 :
516 : {
517 : AIGInfo_t *psInfo;
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* If the pass name ends in .adf assume a file within the */
521 : /* coverage has been selected, and strip that off the coverage */
522 : /* name. */
523 : /* -------------------------------------------------------------------- */
524 14277 : CPLString osCoverName;
525 :
526 14277 : osCoverName = poOpenInfo->pszFilename;
527 14277 : if( osCoverName.size() > 4
528 : && EQUAL(osCoverName.c_str()+osCoverName.size()-4,".adf") )
529 : {
530 3 : osCoverName = CPLGetDirname( poOpenInfo->pszFilename );
531 3 : if( osCoverName == "" )
532 0 : osCoverName = ".";
533 : }
534 :
535 : /* -------------------------------------------------------------------- */
536 : /* Otherwise verify we were already given a directory. */
537 : /* -------------------------------------------------------------------- */
538 14274 : else if( !poOpenInfo->bIsDirectory )
539 : {
540 14228 : return NULL;
541 : }
542 :
543 : /* -------------------------------------------------------------------- */
544 : /* Verify that a few of the "standard" files are available. */
545 : /* -------------------------------------------------------------------- */
546 : VSIStatBufL sStatBuf;
547 49 : CPLString osTestName;
548 :
549 49 : osTestName.Printf( "%s/hdr.adf", osCoverName.c_str() );
550 49 : if( VSIStatL( osTestName, &sStatBuf ) != 0 )
551 :
552 : {
553 44 : osTestName.Printf( "%s/HDR.ADF", osCoverName.c_str() );
554 44 : if( VSIStatL( osTestName, &sStatBuf ) != 0 )
555 42 : return NULL;
556 : }
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Confirm we have at least one raster data file. These can be */
560 : /* sparse so we don't require particular ones to exists but if */
561 : /* there are none this is likely not a grid. */
562 : /* -------------------------------------------------------------------- */
563 7 : char **papszFileList = VSIReadDir( osCoverName );
564 : int iFile;
565 7 : int bGotOne = FALSE;
566 :
567 7 : if (papszFileList == NULL)
568 : {
569 : /* Useful when reading from /vsicurl/ on servers that don't */
570 : /* return a file list */
571 : /* such as /vsicurl/http://eros.usgs.gov/archive/nslrsda/GeoTowns/NLCD/89110458 */
572 : do
573 : {
574 0 : osTestName.Printf( "%s/W001001.ADF", osCoverName.c_str() );
575 0 : if( VSIStatL( osTestName, &sStatBuf ) == 0 )
576 : {
577 0 : bGotOne = TRUE;
578 0 : break;
579 : }
580 :
581 0 : osTestName.Printf( "%s/w001001.adf", osCoverName.c_str() );
582 0 : if( VSIStatL( osTestName, &sStatBuf ) == 0 )
583 : {
584 0 : bGotOne = TRUE;
585 : break;
586 : }
587 : } while(0);
588 : }
589 :
590 110 : for( iFile = 0;
591 55 : papszFileList != NULL && papszFileList[iFile] != NULL && !bGotOne;
592 : iFile++ )
593 : {
594 48 : if( strlen(papszFileList[iFile]) != 11 )
595 41 : continue;
596 :
597 : // looking for something like w001001.adf or z001013.adf
598 9 : if( papszFileList[iFile][0] != 'w'
599 2 : && papszFileList[iFile][0] != 'W'
600 0 : && papszFileList[iFile][0] != 'z'
601 0 : && papszFileList[iFile][0] != 'Z' )
602 0 : continue;
603 :
604 7 : if( strncmp(papszFileList[iFile] + 1, "0010", 4) != 0 )
605 0 : continue;
606 :
607 7 : if( !EQUAL(papszFileList[iFile] + 7, ".adf") )
608 0 : continue;
609 :
610 7 : bGotOne = TRUE;
611 : }
612 7 : CSLDestroy( papszFileList );
613 :
614 7 : if( !bGotOne )
615 0 : return NULL;
616 :
617 : /* -------------------------------------------------------------------- */
618 : /* Open the file. */
619 : /* -------------------------------------------------------------------- */
620 7 : psInfo = AIGOpen( osCoverName.c_str(), "r" );
621 :
622 7 : if( psInfo == NULL )
623 : {
624 0 : CPLErrorReset();
625 0 : return NULL;
626 : }
627 :
628 : /* -------------------------------------------------------------------- */
629 : /* Confirm the requested access is supported. */
630 : /* -------------------------------------------------------------------- */
631 7 : if( poOpenInfo->eAccess == GA_Update )
632 : {
633 0 : AIGClose(psInfo);
634 : CPLError( CE_Failure, CPLE_NotSupported,
635 : "The AIG driver does not support update access to existing"
636 0 : " datasets.\n" );
637 0 : return NULL;
638 : }
639 : /* -------------------------------------------------------------------- */
640 : /* Create a corresponding GDALDataset. */
641 : /* -------------------------------------------------------------------- */
642 : AIGDataset *poDS;
643 :
644 7 : poDS = new AIGDataset();
645 :
646 7 : poDS->psInfo = psInfo;
647 :
648 : /* -------------------------------------------------------------------- */
649 : /* Try to read a color table (.clr). It seems it is legal to */
650 : /* have more than one so we just use the first one found. */
651 : /* -------------------------------------------------------------------- */
652 14 : char **papszFiles = CPLReadDir( psInfo->pszCoverName );
653 7 : CPLString osClrFilename;
654 7 : CPLString osCleanPath = CPLCleanTrailingSlash( psInfo->pszCoverName );
655 :
656 : // first check for any .clr in coverage dir.
657 114 : for( iFile = 0; papszFiles != NULL && papszFiles[iFile] != NULL; iFile++ )
658 : {
659 53 : if( !EQUAL(CPLGetExtension(papszFiles[iFile]),"clr") && !EQUAL(CPLGetExtension(papszFiles[iFile]),"CLR"))
660 50 : continue;
661 :
662 : osClrFilename = CPLFormFilename( psInfo->pszCoverName,
663 3 : papszFiles[iFile], NULL );
664 3 : break;
665 : }
666 :
667 7 : CSLDestroy( papszFiles );
668 :
669 : // Look in parent if we don't find a .clr in the coverage dir.
670 7 : if( strlen(osClrFilename) == 0 )
671 : {
672 : osTestName.Printf( "%s/../%s.clr",
673 : psInfo->pszCoverName,
674 4 : CPLGetFilename( osCleanPath ) );
675 :
676 4 : if( VSIStatL( osTestName, &sStatBuf ) != 0 )
677 :
678 : {
679 : osTestName.Printf( "%s/../%s.CLR",
680 : psInfo->pszCoverName,
681 4 : CPLGetFilename( osCleanPath ) );
682 :
683 4 : if( !VSIStatL( osTestName, &sStatBuf ) )
684 2 : osClrFilename = osTestName;
685 : }
686 : else
687 0 : osClrFilename = osTestName;
688 : }
689 :
690 :
691 7 : if( strlen(osClrFilename) > 0 )
692 5 : poDS->TranslateColorTable( osClrFilename );
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* Establish raster info. */
696 : /* -------------------------------------------------------------------- */
697 7 : poDS->nRasterXSize = psInfo->nPixels;
698 7 : poDS->nRasterYSize = psInfo->nLines;
699 7 : poDS->nBands = 1;
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Create band information objects. */
703 : /* -------------------------------------------------------------------- */
704 7 : poDS->SetBand( 1, new AIGRasterBand( poDS, 1 ) );
705 :
706 : /* -------------------------------------------------------------------- */
707 : /* Try to read projection file. */
708 : /* -------------------------------------------------------------------- */
709 : const char *pszPrjFilename;
710 :
711 7 : pszPrjFilename = CPLFormCIFilename( psInfo->pszCoverName, "prj", "adf" );
712 7 : if( VSIStatL( pszPrjFilename, &sStatBuf ) == 0 )
713 : {
714 5 : OGRSpatialReference oSRS;
715 :
716 5 : poDS->papszPrj = CSLLoad( pszPrjFilename );
717 :
718 5 : if( oSRS.importFromESRI( poDS->papszPrj ) == OGRERR_NONE )
719 : {
720 : // If geographic values are in seconds, we must transform.
721 : // Is there a code for minutes too?
722 5 : if( oSRS.IsGeographic()
723 : && EQUAL(OSR_GDS( poDS->papszPrj, "Units", ""), "DS") )
724 : {
725 0 : psInfo->dfLLX /= 3600.0;
726 0 : psInfo->dfURY /= 3600.0;
727 0 : psInfo->dfCellSizeX /= 3600.0;
728 0 : psInfo->dfCellSizeY /= 3600.0;
729 : }
730 :
731 5 : CPLFree( poDS->pszProjection );
732 5 : oSRS.exportToWkt( &(poDS->pszProjection) );
733 5 : }
734 : }
735 :
736 : /* -------------------------------------------------------------------- */
737 : /* Initialize any PAM information. */
738 : /* -------------------------------------------------------------------- */
739 7 : poDS->SetDescription( psInfo->pszCoverName );
740 7 : poDS->TryLoadXML();
741 :
742 : /* -------------------------------------------------------------------- */
743 : /* Open overviews. */
744 : /* -------------------------------------------------------------------- */
745 7 : poDS->oOvManager.Initialize( poDS, psInfo->pszCoverName );
746 :
747 7 : return( poDS );
748 : }
749 :
750 : /************************************************************************/
751 : /* GetGeoTransform() */
752 : /************************************************************************/
753 :
754 1 : CPLErr AIGDataset::GetGeoTransform( double * padfTransform )
755 :
756 : {
757 1 : padfTransform[0] = psInfo->dfLLX;
758 1 : padfTransform[1] = psInfo->dfCellSizeX;
759 1 : padfTransform[2] = 0;
760 :
761 1 : padfTransform[3] = psInfo->dfURY;
762 1 : padfTransform[4] = 0;
763 1 : padfTransform[5] = -psInfo->dfCellSizeY;
764 :
765 1 : return( CE_None );
766 : }
767 :
768 : /************************************************************************/
769 : /* GetProjectionRef() */
770 : /************************************************************************/
771 :
772 1 : const char *AIGDataset::GetProjectionRef()
773 :
774 : {
775 1 : return pszProjection;
776 : }
777 :
778 : /************************************************************************/
779 : /* TranslateColorTable() */
780 : /************************************************************************/
781 :
782 5 : void AIGDataset::TranslateColorTable( const char *pszClrFilename )
783 :
784 : {
785 : int iLine;
786 : char **papszClrLines;
787 :
788 5 : papszClrLines = CSLLoad( pszClrFilename );
789 5 : if( papszClrLines == NULL )
790 0 : return;
791 :
792 5 : poCT = new GDALColorTable();
793 :
794 1295 : for( iLine = 0; papszClrLines[iLine] != NULL; iLine++ )
795 : {
796 1290 : char **papszTokens = CSLTokenizeString( papszClrLines[iLine] );
797 :
798 1290 : if( CSLCount(papszTokens) >= 4 && papszTokens[0][0] != '#' )
799 : {
800 : int nIndex;
801 : GDALColorEntry sEntry;
802 :
803 1280 : nIndex = atoi(papszTokens[0]);
804 1280 : sEntry.c1 = (short) atoi(papszTokens[1]);
805 1280 : sEntry.c2 = (short) atoi(papszTokens[2]);
806 1280 : sEntry.c3 = (short) atoi(papszTokens[3]);
807 1280 : sEntry.c4 = 255;
808 :
809 1280 : if( (nIndex < 0 || nIndex > 33000)
810 : || (sEntry.c1 < 0 || sEntry.c1 > 255)
811 : || (sEntry.c2 < 0 || sEntry.c2 > 255)
812 : || (sEntry.c3 < 0 || sEntry.c3 > 255) )
813 : {
814 0 : CSLDestroy( papszTokens );
815 : CPLError( CE_Failure, CPLE_AppDefined,
816 0 : "Color table entry appears to be corrupt, skipping the rest. " );
817 0 : break;
818 : }
819 :
820 1280 : poCT->SetColorEntry( nIndex, &sEntry );
821 : }
822 :
823 1290 : CSLDestroy( papszTokens );
824 : }
825 :
826 5 : CSLDestroy( papszClrLines );
827 : }
828 :
829 : /************************************************************************/
830 : /* OSR_GDS() */
831 : /************************************************************************/
832 :
833 0 : static CPLString OSR_GDS( char **papszNV, const char * pszField,
834 : const char *pszDefaultValue )
835 :
836 : {
837 : int iLine;
838 :
839 0 : if( papszNV == NULL || papszNV[0] == NULL )
840 0 : return pszDefaultValue;
841 :
842 0 : for( iLine = 0;
843 0 : papszNV[iLine] != NULL &&
844 0 : !EQUALN(papszNV[iLine],pszField,strlen(pszField));
845 : iLine++ ) {}
846 :
847 0 : if( papszNV[iLine] == NULL )
848 0 : return pszDefaultValue;
849 : else
850 : {
851 0 : CPLString osResult;
852 : char **papszTokens;
853 :
854 0 : papszTokens = CSLTokenizeString(papszNV[iLine]);
855 :
856 0 : if( CSLCount(papszTokens) > 1 )
857 0 : osResult = papszTokens[1];
858 : else
859 0 : osResult = pszDefaultValue;
860 :
861 0 : CSLDestroy( papszTokens );
862 0 : return osResult;
863 : }
864 : }
865 :
866 : /************************************************************************/
867 : /* AIGRename() */
868 : /* */
869 : /* Custom renamer for AIG dataset. */
870 : /************************************************************************/
871 :
872 0 : static CPLErr AIGRename( const char *pszNewName, const char *pszOldName )
873 :
874 : {
875 : /* -------------------------------------------------------------------- */
876 : /* Make sure we are talking about paths to the coverage */
877 : /* directory. */
878 : /* -------------------------------------------------------------------- */
879 0 : CPLString osOldPath, osNewPath;
880 :
881 0 : if( strlen(CPLGetExtension(pszNewName)) > 0 )
882 0 : osNewPath = CPLGetPath(pszNewName);
883 : else
884 0 : osNewPath = pszNewName;
885 :
886 0 : if( strlen(CPLGetExtension(pszOldName)) > 0 )
887 0 : osOldPath = CPLGetPath(pszOldName);
888 : else
889 0 : osOldPath = pszOldName;
890 :
891 : /* -------------------------------------------------------------------- */
892 : /* Get file list. */
893 : /* -------------------------------------------------------------------- */
894 :
895 0 : GDALDatasetH hDS = GDALOpen( osOldPath, GA_ReadOnly );
896 0 : if( hDS == NULL )
897 0 : return CE_Failure;
898 :
899 0 : char **papszFileList = GDALGetFileList( hDS );
900 0 : GDALClose( hDS );
901 :
902 0 : if( papszFileList == NULL )
903 0 : return CE_Failure;
904 :
905 : /* -------------------------------------------------------------------- */
906 : /* Work out the corresponding new names. */
907 : /* -------------------------------------------------------------------- */
908 0 : char **papszNewFileList = NULL;
909 : int i;
910 :
911 0 : for( i = 0; papszFileList[i] != NULL; i++ )
912 : {
913 0 : CPLString osNewFilename;
914 :
915 0 : if( !EQUALN(papszFileList[i],osOldPath,strlen(osOldPath)) )
916 : {
917 0 : CPLAssert( FALSE );
918 0 : return CE_Failure;
919 : }
920 :
921 0 : osNewFilename = osNewPath + (papszFileList[i] + strlen(osOldPath));
922 :
923 0 : papszNewFileList = CSLAddString( papszNewFileList, osNewFilename );
924 : }
925 :
926 : /* -------------------------------------------------------------------- */
927 : /* Try renaming the directory. */
928 : /* -------------------------------------------------------------------- */
929 0 : if( VSIRename( osNewPath, osOldPath ) != 0 )
930 : {
931 0 : if( VSIMkdir( osNewPath, 0777 ) != 0 )
932 : {
933 : CPLError( CE_Failure, CPLE_AppDefined,
934 : "Unable to create directory %s:\n%s",
935 : osNewPath.c_str(),
936 0 : VSIStrerror(errno) );
937 0 : return CE_Failure;
938 : }
939 : }
940 :
941 : /* -------------------------------------------------------------------- */
942 : /* Copy/rename any remaining files. */
943 : /* -------------------------------------------------------------------- */
944 : VSIStatBufL sStatBuf;
945 :
946 0 : for( i = 0; papszFileList[i] != NULL; i++ )
947 : {
948 0 : if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
949 : && VSI_ISREG( sStatBuf.st_mode ) )
950 : {
951 0 : if( CPLMoveFile( papszNewFileList[i], papszFileList[i] ) != 0 )
952 : {
953 : CPLError( CE_Failure, CPLE_AppDefined,
954 : "Unable to move %s to %s:\n%s",
955 : papszFileList[i],
956 : papszNewFileList[i],
957 0 : VSIStrerror(errno) );
958 0 : return CE_Failure;
959 : }
960 : }
961 : }
962 :
963 0 : if( VSIStatL( osOldPath, &sStatBuf ) == 0 )
964 0 : CPLUnlinkTree( osOldPath );
965 :
966 0 : return CE_None;
967 : }
968 :
969 : /************************************************************************/
970 : /* AIGDelete() */
971 : /* */
972 : /* Custom dataset deleter for AIG dataset. */
973 : /************************************************************************/
974 :
975 0 : static CPLErr AIGDelete( const char *pszDatasetname )
976 :
977 : {
978 : /* -------------------------------------------------------------------- */
979 : /* Get file list. */
980 : /* -------------------------------------------------------------------- */
981 0 : GDALDatasetH hDS = GDALOpen( pszDatasetname, GA_ReadOnly );
982 0 : if( hDS == NULL )
983 0 : return CE_Failure;
984 :
985 0 : char **papszFileList = GDALGetFileList( hDS );
986 0 : GDALClose( hDS );
987 :
988 0 : if( papszFileList == NULL )
989 0 : return CE_Failure;
990 :
991 : /* -------------------------------------------------------------------- */
992 : /* Delete all regular files. */
993 : /* -------------------------------------------------------------------- */
994 : int i;
995 0 : for( i = 0; papszFileList[i] != NULL; i++ )
996 : {
997 : VSIStatBufL sStatBuf;
998 0 : if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
999 : && VSI_ISREG( sStatBuf.st_mode ) )
1000 : {
1001 0 : if( VSIUnlink( papszFileList[i] ) != 0 )
1002 : {
1003 : CPLError( CE_Failure, CPLE_AppDefined,
1004 : "Unable to delete '%s':\n%s",
1005 0 : papszFileList[i], VSIStrerror( errno ) );
1006 0 : return CE_Failure;
1007 : }
1008 : }
1009 : }
1010 :
1011 : /* -------------------------------------------------------------------- */
1012 : /* Delete directories. */
1013 : /* -------------------------------------------------------------------- */
1014 0 : for( i = 0; papszFileList[i] != NULL; i++ )
1015 : {
1016 : VSIStatBufL sStatBuf;
1017 0 : if( VSIStatL( papszFileList[i], &sStatBuf ) == 0
1018 : && VSI_ISDIR( sStatBuf.st_mode ) )
1019 : {
1020 0 : if( CPLUnlinkTree( papszFileList[i] ) != 0 )
1021 0 : return CE_Failure;
1022 : }
1023 : }
1024 :
1025 0 : return CE_None;
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* GDALRegister_AIG() */
1030 : /************************************************************************/
1031 :
1032 582 : void GDALRegister_AIGrid()
1033 :
1034 : {
1035 : GDALDriver *poDriver;
1036 :
1037 582 : if( GDALGetDriverByName( "AIG" ) == NULL )
1038 : {
1039 561 : poDriver = new GDALDriver();
1040 :
1041 561 : poDriver->SetDescription( "AIG" );
1042 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1043 561 : "Arc/Info Binary Grid" );
1044 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1045 561 : "frmt_various.html#AIG" );
1046 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1047 :
1048 561 : poDriver->pfnOpen = AIGDataset::Open;
1049 :
1050 561 : poDriver->pfnRename = AIGRename;
1051 561 : poDriver->pfnDelete = AIGDelete;
1052 :
1053 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1054 : }
1055 582 : }
|